[jOOQ/jOOQ#13053] java.lang.NoClassDefFoundError: org/postgresql/util/PGInterval when rendering SQL without the pgjdbc dependency

This commit is contained in:
Lukas Eder 2022-05-06 10:45:48 +02:00
parent 96b09d7686
commit 6f099c6cc9
8 changed files with 736 additions and 234 deletions

View File

@ -109,18 +109,6 @@
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>

View File

@ -44,8 +44,6 @@ module org.jooq {
requires static org.postgresql.jdbc;
exports org.jooq;
exports org.jooq.conf;
exports org.jooq.exception;

View File

@ -163,12 +163,12 @@ import static org.jooq.tools.jdbc.JDBCUtils.safeFree;
import static org.jooq.tools.jdbc.JDBCUtils.wasNull;
import static org.jooq.tools.reflect.Reflect.onClass;
import static org.jooq.tools.reflect.Reflect.wrapper;
import static org.jooq.util.postgres.PostgresUtils.toDayToSecond;
import static org.jooq.util.postgres.PostgresUtils.toPGArray;
import static org.jooq.util.postgres.PostgresUtils.toPGArrayString;
import static org.jooq.util.postgres.PostgresUtils.toPGInterval;
import static org.jooq.util.postgres.PostgresUtils.toYearToMonth;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.StringReader;
import java.lang.reflect.Modifier;
@ -2429,12 +2429,6 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.render().visit(inline(toPGInterval(value).toString()));
else
super.sqlInline0(ctx, value);
@ -2445,13 +2439,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.statement().setObject(ctx.index(), toPGInterval(value));
ctx.statement().setString(ctx.index(), toPGInterval(value).toString());
else
ctx.statement().setString(ctx.index(), renderDTS(ctx, value));
}
@ -2463,20 +2451,16 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
@Override
final DayToSecond get0(BindingGetResultSetContext<U> ctx) throws SQLException {
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect())) {
Object object = ctx.resultSet().getObject(ctx.index());
return object == null ? null : PostgresUtils.toDayToSecond(object);
}
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
return toDayToSecond(ctx.resultSet().getString(ctx.index()));
else
return parseDTS(ctx, ctx.resultSet().getString(ctx.index()));
}
@Override
final DayToSecond get0(BindingGetStatementContext<U> ctx) throws SQLException {
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect())) {
Object object = ctx.statement().getObject(ctx.index());
return object == null ? null : PostgresUtils.toDayToSecond(object);
}
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
return toDayToSecond(ctx.statement().getString(ctx.index()));
else
return parseDTS(ctx, ctx.statement().getString(ctx.index()));
}
@ -5548,12 +5532,6 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.render().visit(inline(toPGInterval(value).toString()));
else
super.sqlInline0(ctx, value);
@ -5564,13 +5542,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.statement().setObject(ctx.index(), toPGInterval(value));
ctx.statement().setString(ctx.index(), toPGInterval(value).toString());
else
ctx.statement().setString(ctx.index(), value.toString());
}
@ -5629,12 +5601,6 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.render().visit(inline(toPGInterval(value).toString()));
else
super.sqlInline0(ctx, value);
@ -5645,13 +5611,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.statement().setObject(ctx.index(), toPGInterval(value));
ctx.statement().setString(ctx.index(), toPGInterval(value).toString());
else
ctx.statement().setString(ctx.index(), renderYTM(ctx, value));
}
@ -5663,20 +5623,16 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
@Override
final YearToMonth get0(BindingGetResultSetContext<U> ctx) throws SQLException {
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect())) {
Object object = ctx.resultSet().getObject(ctx.index());
return object == null ? null : PostgresUtils.toYearToMonth(object);
}
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
return toYearToMonth(ctx.resultSet().getString(ctx.index()));
else
return parseYTM(ctx, ctx.resultSet().getString(ctx.index()));
}
@Override
final YearToMonth get0(BindingGetStatementContext<U> ctx) throws SQLException {
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect())) {
Object object = ctx.statement().getObject(ctx.index());
return object == null ? null : PostgresUtils.toYearToMonth(object);
}
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
return toYearToMonth(ctx.statement().getString(ctx.index()));
else
return parseYTM(ctx, ctx.statement().getString(ctx.index()));
}

View File

@ -348,6 +348,8 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
final WithImpl with;
private final SelectFieldList<SelectFieldOrAsterisk> select;
private Table<?> intoTable;
@ -3044,9 +3046,11 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
if (actualLimit.isApplicable()) {
ctx.visit(actualLimit);
}
// [#13509] Force a LIMIT clause to prevent optimisation of "unnecessary" ORDER BY
else if (!actualOrderBy.isEmpty() && TRUE.equals(ctx.data(DATA_FORCE_LIMIT_WITH_ORDER_BY))) {
Limit l = new Limit();
l.setLimit(Integer.MAX_VALUE);
l.setLimit(Long.MAX_VALUE);
ctx.visit(l);
}
}
@ -3120,7 +3124,6 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
private static final Set<SQLDialect> NO_SUPPORT_UNION_PARENTHESES = SQLDialect.supportedBy(SQLITE);

View File

@ -0,0 +1,541 @@
/*
* Copyright (c) 2004, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.jooq.util.postgres;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.StringTokenizer;
import org.jetbrains.annotations.ApiStatus.Internal;
/**
* This implements a class that handles the PostgreSQL interval type.
*/
@Internal
public class PGInterval extends PGobject {
private static final int MICROS_IN_SECOND = 1000000;
private int years;
private int months;
private int days;
private int hours;
private int minutes;
private int wholeSeconds;
private int microSeconds;
private boolean isNull;
/**
* required by the driver.
*/
public PGInterval() {
type = "interval";
}
/**
* Initialize a interval with a given interval string representation.
*
* @param value String representated interval (e.g. '3 years 2 mons')
* @see PGobject#setValue(String)
*/
public PGInterval(String value) {
this();
setValue(value);
}
private int lookAhead(String value, int position, String find) {
char [] tokens = find.toCharArray();
int found = -1;
for ( int i = 0; i < tokens.length; i++ ) {
found = value.indexOf(tokens[i], position);
if ( found > 0 ) {
return found;
}
}
return found;
}
private void parseISO8601Format(String value) {
int number = 0;
String dateValue;
String timeValue = null;
int hasTime = value.indexOf('T');
if ( hasTime > 0 ) {
/* skip over the P */
dateValue = value.substring(1,hasTime);
timeValue = value.substring(hasTime + 1);
} else {
/* skip over the P */
dateValue = value.substring(1);
}
for ( int i = 0; i < dateValue.length(); i++ ) {
int lookAhead = lookAhead(dateValue, i, "YMD");
if (lookAhead > 0) {
number = Integer.parseInt(dateValue.substring(i, lookAhead));
if (dateValue.charAt(lookAhead) == 'Y') {
setYears(number);
} else if (dateValue.charAt(lookAhead) == 'M') {
setMonths(number);
} else if (dateValue.charAt(lookAhead) == 'D') {
setDays(number);
}
i = lookAhead;
}
}
if ( timeValue != null ) {
for (int i = 0; i < timeValue.length(); i++) {
int lookAhead = lookAhead(timeValue, i, "HMS");
if (lookAhead > 0) {
number = Integer.parseInt(timeValue.substring(i, lookAhead));
if (timeValue.charAt(lookAhead) == 'H') {
setHours(number);
} else if (timeValue.charAt(lookAhead) == 'M') {
setMinutes(number);
} else if (timeValue.charAt(lookAhead) == 'S') {
setSeconds(number);
}
i = lookAhead;
}
}
}
}
/**
* Initializes all values of this interval to the specified values.
*
* @param years years
* @param months months
* @param days days
* @param hours hours
* @param minutes minutes
* @param seconds seconds
* @see #setValue(int, int, int, int, int, double)
*/
public PGInterval(int years, int months, int days, int hours, int minutes, double seconds) {
this();
setValue(years, months, days, hours, minutes, seconds);
}
/**
* Sets a interval string represented value to this instance. This method only recognize the
* format, that Postgres returns - not all input formats are supported (e.g. '1 yr 2 m 3 s').
*
* @param value String representated interval (e.g. '3 years 2 mons')
*/
@Override
public void setValue(String value) {
isNull = value == null;
if (value == null) {
setValue(0, 0, 0, 0, 0, 0);
isNull = true;
return;
}
final boolean PostgresFormat = !value.startsWith("@");
if (value.startsWith("P")) {
parseISO8601Format(value);
return;
}
// Just a simple '0'
if (!PostgresFormat && value.length() == 3 && value.charAt(2) == '0') {
setValue(0, 0, 0, 0, 0, 0.0);
return;
}
int years = 0;
int months = 0;
int days = 0;
int hours = 0;
int minutes = 0;
double seconds = 0;
String valueToken = null;
value = value.replace('+', ' ').replace('@', ' ');
final StringTokenizer st = new StringTokenizer(value);
for (int i = 1; st.hasMoreTokens(); i++) {
String token = st.nextToken();
if ((i & 1) == 1) {
int endHours = token.indexOf(':');
if (endHours == -1) {
valueToken = token;
continue;
}
// This handles hours, minutes, seconds and microseconds for
// ISO intervals
int offset = (token.charAt(0) == '-') ? 1 : 0;
hours = nullSafeIntGet(token.substring(offset + 0, endHours));
minutes = nullSafeIntGet(token.substring(endHours + 1, endHours + 3));
// Pre 7.4 servers do not put second information into the results
// unless it is non-zero.
int endMinutes = token.indexOf(':', endHours + 1);
if (endMinutes != -1) {
seconds = nullSafeDoubleGet(token.substring(endMinutes + 1));
}
if (offset == 1) {
hours = -hours;
minutes = -minutes;
seconds = -seconds;
}
valueToken = null;
} else {
// This handles years, months, days for both, ISO and
// Non-ISO intervals. Hours, minutes, seconds and microseconds
// are handled for Non-ISO intervals here.
if (token.startsWith("year")) {
years = nullSafeIntGet(valueToken);
} else if (token.startsWith("mon")) {
months = nullSafeIntGet(valueToken);
} else if (token.startsWith("day")) {
days = nullSafeIntGet(valueToken);
} else if (token.startsWith("hour")) {
hours = nullSafeIntGet(valueToken);
} else if (token.startsWith("min")) {
minutes = nullSafeIntGet(valueToken);
} else if (token.startsWith("sec")) {
seconds = nullSafeDoubleGet(valueToken);
}
}
}
if (!PostgresFormat && value.endsWith("ago")) {
// Inverse the leading sign
setValue(-years, -months, -days, -hours, -minutes, -seconds);
} else {
setValue(years, months, days, hours, minutes, seconds);
}
}
/**
* Set all values of this interval to the specified values.
*
* @param years years
* @param months months
* @param days days
* @param hours hours
* @param minutes minutes
* @param seconds seconds
*/
public void setValue(int years, int months, int days, int hours, int minutes, double seconds) {
setYears(years);
setMonths(months);
setDays(days);
setHours(hours);
setMinutes(minutes);
setSeconds(seconds);
}
/**
* Returns the stored interval information as a string.
*
* @return String represented interval
*/
@Override
public String getValue() {
if (isNull) {
return null;
}
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.US);
df.applyPattern("0.0#####");
return String.format(
Locale.ROOT,
"%d years %d mons %d days %d hours %d mins %s secs",
years,
months,
days,
hours,
minutes,
df.format(getSeconds())
);
}
/**
* Returns the years represented by this interval.
*
* @return years represented by this interval
*/
public int getYears() {
return years;
}
/**
* Set the years of this interval to the specified value.
*
* @param years years to set
*/
public void setYears(int years) {
isNull = false;
this.years = years;
}
/**
* Returns the months represented by this interval.
*
* @return months represented by this interval
*/
public int getMonths() {
return months;
}
/**
* Set the months of this interval to the specified value.
*
* @param months months to set
*/
public void setMonths(int months) {
isNull = false;
this.months = months;
}
/**
* Returns the days represented by this interval.
*
* @return days represented by this interval
*/
public int getDays() {
return days;
}
/**
* Set the days of this interval to the specified value.
*
* @param days days to set
*/
public void setDays(int days) {
isNull = false;
this.days = days;
}
/**
* Returns the hours represented by this interval.
*
* @return hours represented by this interval
*/
public int getHours() {
return hours;
}
/**
* Set the hours of this interval to the specified value.
*
* @param hours hours to set
*/
public void setHours(int hours) {
isNull = false;
this.hours = hours;
}
/**
* Returns the minutes represented by this interval.
*
* @return minutes represented by this interval
*/
public int getMinutes() {
return minutes;
}
/**
* Set the minutes of this interval to the specified value.
*
* @param minutes minutes to set
*/
public void setMinutes(int minutes) {
isNull = false;
this.minutes = minutes;
}
/**
* Returns the seconds represented by this interval.
*
* @return seconds represented by this interval
*/
public double getSeconds() {
return wholeSeconds + (double) microSeconds / MICROS_IN_SECOND;
}
public int getWholeSeconds() {
return wholeSeconds;
}
public int getMicroSeconds() {
return microSeconds;
}
/**
* Set the seconds of this interval to the specified value.
*
* @param seconds seconds to set
*/
public void setSeconds(double seconds) {
isNull = false;
wholeSeconds = (int) seconds;
microSeconds = (int) Math.round((seconds - wholeSeconds) * MICROS_IN_SECOND);
}
/**
* Rolls this interval on a given calendar.
*
* @param cal Calendar instance to add to
*/
public void add(Calendar cal) {
if (isNull) {
return;
}
final int milliseconds = (microSeconds + ((microSeconds < 0) ? -500 : 500)) / 1000 + wholeSeconds * 1000;
cal.add(Calendar.MILLISECOND, milliseconds);
cal.add(Calendar.MINUTE, getMinutes());
cal.add(Calendar.HOUR, getHours());
cal.add(Calendar.DAY_OF_MONTH, getDays());
cal.add(Calendar.MONTH, getMonths());
cal.add(Calendar.YEAR, getYears());
}
/**
* Rolls this interval on a given date.
*
* @param date Date instance to add to
*/
public void add(Date date) {
if (isNull) {
return;
}
final Calendar cal = Calendar.getInstance();
cal.setTime(date);
add(cal);
date.setTime(cal.getTime().getTime());
}
/**
* Add this interval's value to the passed interval. This is backwards to what I would expect, but
* this makes it match the other existing add methods.
*
* @param interval intval to add
*/
public void add(PGInterval interval) {
if (isNull || interval.isNull) {
return;
}
interval.setYears(interval.getYears() + getYears());
interval.setMonths(interval.getMonths() + getMonths());
interval.setDays(interval.getDays() + getDays());
interval.setHours(interval.getHours() + getHours());
interval.setMinutes(interval.getMinutes() + getMinutes());
interval.setSeconds(interval.getSeconds() + getSeconds());
}
/**
* Scale this interval by an integer factor. The server can scale by arbitrary factors, but that
* would require adjusting the call signatures for all the existing methods like getDays() or
* providing our own justification of fractional intervals. Neither of these seem like a good idea
* without a strong use case.
*
* @param factor scale factor
*/
public void scale(int factor) {
if (isNull) {
return;
}
setYears(factor * getYears());
setMonths(factor * getMonths());
setDays(factor * getDays());
setHours(factor * getHours());
setMinutes(factor * getMinutes());
setSeconds(factor * getSeconds());
}
/**
* Returns integer value of value or 0 if value is null.
*
* @param value integer as string value
* @return integer parsed from string value
* @throws NumberFormatException if the string contains invalid chars
*/
private static int nullSafeIntGet(String value) throws NumberFormatException {
return (value == null) ? 0 : Integer.parseInt(value);
}
/**
* Returns double value of value or 0 if value is null.
*
* @param value double as string value
* @return double parsed from string value
* @throws NumberFormatException if the string contains invalid chars
*/
private static double nullSafeDoubleGet(String value) throws NumberFormatException {
return (value == null) ? 0 : Double.parseDouble(value);
}
/**
* Returns whether an object is equal to this one or not.
*
* @param obj Object to compare with
* @return true if the two intervals are identical
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (!(obj instanceof PGInterval)) {
return false;
}
final PGInterval pgi = (PGInterval) obj;
if (isNull) {
return pgi.isNull;
} else if (pgi.isNull) {
return false;
}
return pgi.years == years
&& pgi.months == months
&& pgi.days == days
&& pgi.hours == hours
&& pgi.minutes == minutes
&& pgi.wholeSeconds == wholeSeconds
&& pgi.microSeconds == microSeconds;
}
/**
* Returns a hashCode for this object.
*
* @return hashCode
*/
@Override
public int hashCode() {
if (isNull) {
return 0;
}
return (((((((8 * 31 + microSeconds) * 31 + wholeSeconds) * 31 + minutes) * 31 + hours) * 31
+ days) * 31 + months) * 31 + years) * 31;
}
@Override
public Object clone() throws CloneNotSupportedException {
// squid:S2157 "Cloneables" should implement "clone
return super.clone();
}
}

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2003, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.jooq.util.postgres;
import java.io.Serializable;
import java.sql.SQLException;
import org.jetbrains.annotations.ApiStatus.Internal;
/**
* PGobject is a class used to describe unknown types An unknown type is any type that is unknown by
* JDBC Standards.
*/
@Internal
public class PGobject implements Serializable, Cloneable {
protected String type;
protected String value;
/**
* This is called by org.postgresql.Connection.getObject() to create the object.
*/
public PGobject() {
}
/**
* <p>This method sets the type of this object.</p>
*
* <p>It should not be extended by subclasses, hence it is final</p>
*
* @param type a string describing the type of the object
*/
public final void setType(String type) {
this.type = type;
}
/**
* This method sets the value of this object. It must be overridden.
*
* @param value a string representation of the value of the object
* @throws SQLException thrown if value is invalid for this type
*/
public void setValue(String value) throws SQLException {
this.value = value;
}
/**
* As this cannot change during the life of the object, it's final.
*
* @return the type name of this object
*/
public final String getType() {
return type;
}
/**
* This must be overidden, to return the value of the object, in the form required by
* org.postgresql.
*
* @return the value of this object
*/
public String getValue() {
return value;
}
/**
* Returns true if the current object wraps `null` value.
* This might be helpful
*
* @return true if the current object wraps `null` value.
*/
public boolean isNull() {
return getValue() != null;
}
/**
* This must be overidden to allow comparisons of objects.
*
* @param obj Object to compare with
* @return true if the two boxes are identical
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof PGobject) {
final Object otherValue = ((PGobject) obj).getValue();
if (otherValue == null) {
return getValue() == null;
}
return otherValue.equals(getValue());
}
return false;
}
/**
* This must be overidden to allow the object to be cloned.
*/
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
/**
* This is defined here, so user code need not overide it.
*
* @return the value of this object, in the syntax expected by org.postgresql
*/
@Override
public String toString() {
return getValue();
}
/**
* Compute hash. As equals() use only value. Return the same hash for the same value.
*
* @return Value hashcode, 0 if value is null {@link java.util.Objects#hashCode(Object)}
*/
@Override
public int hashCode() {
String value = getValue();
return value != null ? value.hashCode() : 0;
}
protected static boolean equals(Object a, Object b) {
return a == b || a != null && a.equals(b);
}
}

View File

@ -51,7 +51,6 @@ import java.util.List;
import org.jooq.Converter;
import org.jooq.EnumType;
// ...
import org.jooq.Record;
import org.jooq.exception.DataTypeException;
import org.jooq.tools.StringUtils;
@ -59,9 +58,8 @@ import org.jooq.types.DayToSecond;
import org.jooq.types.YearToMonth;
import org.jooq.types.YearToSecond;
import org.postgresql.util.PGInterval;
import org.jetbrains.annotations.ApiStatus.Internal;
// ...
/**
* A collection of utilities to cover the Postgres JDBC driver's missing
@ -73,6 +71,7 @@ import org.postgresql.util.PGInterval;
* @author Lukas Eder
* @author Peter Ertl
*/
@Internal
public class PostgresUtils {
private static final String POSTGRESQL_HEX_STRING_PREFIX = "\\x";
@ -85,12 +84,6 @@ public class PostgresUtils {
private static final int PG_OBJECT_AFTER_VALUE = 4;
private static final int PG_OBJECT_END = 5;
private static volatile Boolean pgIntervalAvailable;
/**
* Parse a Postgres-encoded <code>bytea</code> string
*/
@ -209,7 +202,7 @@ public class PostgresUtils {
/**
* Convert a jOOQ <code>DAY TO SECOND</code> interval to a Postgres representation
*/
public static Object toPGInterval(DayToSecond interval) {
public static PGInterval toPGInterval(DayToSecond interval) {
return new PGInterval(0, 0,
interval.getSign() * interval.getDays(),
interval.getSign() * interval.getHours(),
@ -222,7 +215,7 @@ public class PostgresUtils {
/**
* Convert a jOOQ <code>YEAR TO SECOND</code> interval to a Postgres representation
*/
public static Object toPGInterval(YearToSecond interval) {
public static PGInterval toPGInterval(YearToSecond interval) {
return new PGInterval(
interval.getSign() * interval.getYears(),
interval.getSign() * interval.getMonths(),
@ -237,7 +230,7 @@ public class PostgresUtils {
/**
* Convert a jOOQ <code>YEAR TO MONTH</code> interval to a Postgres representation
*/
public static Object toPGInterval(YearToMonth interval) {
public static PGInterval toPGInterval(YearToMonth interval) {
return new PGInterval(
interval.getSign() * interval.getYears(),
interval.getSign() * interval.getMonths(),
@ -245,136 +238,69 @@ public class PostgresUtils {
);
}
/**
* Convert a Postgres interval to a jOOQ <code>DAY TO SECOND</code> interval
*/
public static DayToSecond toDayToSecond(Object pgInterval) {
if (pgInterval == null)
return null;
else if (pgInterval instanceof PGInterval)
return toDayToSecond((PGInterval) pgInterval);
else
return toDayToSecond(new PGInterval(pgInterval.toString()));
}
/**
* Convert a Postgres interval to a jOOQ <code>DAY TO SECOND</code> interval
*/
public static DayToSecond toDayToSecond(PGInterval pgInterval) {
boolean negative = pgInterval.toString().contains("-");
if (pgIntervalAvailable() && pgInterval instanceof PGInterval) {
PGInterval i = (PGInterval) pgInterval;
if (negative)
i.scale(-1);
if (negative)
pgInterval.scale(-1);
Double seconds = i.getSeconds();
DayToSecond result = new DayToSecond(
i.getDays(),
i.getHours(),
i.getMinutes(),
seconds.intValue(),
(int) (1000000000 * (seconds - seconds.intValue()))
);
Double seconds = pgInterval.getSeconds();
DayToSecond result = new DayToSecond(
pgInterval.getDays(),
pgInterval.getHours(),
pgInterval.getMinutes(),
seconds.intValue(),
(int) (1000000000 * (seconds - seconds.intValue()))
);
if (negative)
result = result.neg();
if (negative)
result = result.neg();
return result;
}
else
throw new IllegalArgumentException("Unsupported interval type. Make sure you have the pgjdbc or redshift driver on your classpath: " + pgInterval);
return result;
}
/**
* Convert a Postgres interval to a jOOQ <code>YEAR TO MONTH</code> interval
*/
public static YearToMonth toYearToMonth(Object pgInterval) {
if (pgInterval == null)
return null;
else if (pgInterval instanceof PGInterval)
return toYearToMonth((PGInterval) pgInterval);
else
return toYearToMonth(new PGInterval(pgInterval.toString()));
}
/**
* Convert a Postgres interval to a jOOQ <code>YEAR TO MONTH</code> interval
*/
public static YearToMonth toYearToMonth(PGInterval pgInterval) {
boolean negative = pgInterval.toString().contains("-");
if (pgIntervalAvailable() && pgInterval instanceof PGInterval) {
PGInterval i = (PGInterval) pgInterval;
if (negative)
i.scale(-1);
if (negative)
pgInterval.scale(-1);
YearToMonth result = new YearToMonth(i.getYears(), i.getMonths());
YearToMonth result = new YearToMonth(pgInterval.getYears(), pgInterval.getMonths());
if (negative)
result = result.neg();
if (negative)
result = result.neg();
return result;
}
else
throw new IllegalArgumentException("Unsupported interval type. Make sure you have the pgjdbc or redshift driver on your classpath: " + pgInterval);
return result;
}
/**
@ -638,37 +564,4 @@ public class PostgresUtils {
return sb.toString();
}
private static final boolean pgIntervalAvailable() {
if (pgIntervalAvailable == null) {
try {
new PGInterval();
pgIntervalAvailable = true;
}
catch (NoClassDefFoundError e) {
pgIntervalAvailable = false;
}
}
return pgIntervalAvailable;
}
}

View File

@ -30,7 +30,6 @@
<postgres.version>42.3.3</postgres.version>
<sqlserver.version>10.2.0.jre11</sqlserver.version>
<oracle.version>21.5.0.0</oracle.version>
<redshift.version>2.1.0.4</redshift.version>
<!-- R2DBC SPI version and some matching driver versions -->
<io.r2dbc.version>0.9.0.RELEASE</io.r2dbc.version>
@ -385,11 +384,6 @@
<!-- Some examples require testcontainers as dependencies -->
<dependency>
<groupId>org.testcontainers</groupId>