diff --git a/jOOQ/pom.xml b/jOOQ/pom.xml index 384fd05833..7ee10f9079 100644 --- a/jOOQ/pom.xml +++ b/jOOQ/pom.xml @@ -109,18 +109,6 @@ jakarta.xml.bind-api - - org.postgresql - postgresql - provided - true - - - - - - - diff --git a/jOOQ/src/main/java/module-info.java b/jOOQ/src/main/java/module-info.java index 2265e11cbe..01a612c50a 100644 --- a/jOOQ/src/main/java/module-info.java +++ b/jOOQ/src/main/java/module-info.java @@ -44,8 +44,6 @@ module org.jooq { - requires static org.postgresql.jdbc; - exports org.jooq; exports org.jooq.conf; exports org.jooq.exception; diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java index deab4ec0e9..e89d3c5e07 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java @@ -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 implements Binding { // [#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 implements Binding { // [#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 implements Binding { @Override final DayToSecond get0(BindingGetResultSetContext 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 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 implements Binding { // [#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 implements Binding { // [#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 implements Binding { // [#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 implements Binding { // [#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 implements Binding { @Override final YearToMonth get0(BindingGetResultSetContext 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 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())); } diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index b01193eaf8..932c216b28 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -348,6 +348,8 @@ final class SelectQueryImpl extends AbstractResultQuery imp + + final WithImpl with; private final SelectFieldList select; private Table intoTable; @@ -3044,9 +3046,11 @@ final class SelectQueryImpl extends AbstractResultQuery 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 extends AbstractResultQuery imp - private static final Set NO_SUPPORT_UNION_PARENTHESES = SQLDialect.supportedBy(SQLITE); diff --git a/jOOQ/src/main/java/org/jooq/util/postgres/PGInterval.java b/jOOQ/src/main/java/org/jooq/util/postgres/PGInterval.java new file mode 100644 index 0000000000..d6c21b4d86 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/util/postgres/PGInterval.java @@ -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(); + } +} diff --git a/jOOQ/src/main/java/org/jooq/util/postgres/PGobject.java b/jOOQ/src/main/java/org/jooq/util/postgres/PGobject.java new file mode 100644 index 0000000000..89ea9c3b73 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/util/postgres/PGobject.java @@ -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() { + } + + /** + *

This method sets the type of this object.

+ * + *

It should not be extended by subclasses, hence it is final

+ * + * @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); + } +} diff --git a/jOOQ/src/main/java/org/jooq/util/postgres/PostgresUtils.java b/jOOQ/src/main/java/org/jooq/util/postgres/PostgresUtils.java index c916c66c43..359d93d3d0 100644 --- a/jOOQ/src/main/java/org/jooq/util/postgres/PostgresUtils.java +++ b/jOOQ/src/main/java/org/jooq/util/postgres/PostgresUtils.java @@ -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 bytea string */ @@ -209,7 +202,7 @@ public class PostgresUtils { /** * Convert a jOOQ DAY TO SECOND 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 YEAR TO SECOND 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 YEAR TO MONTH 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 DAY TO SECOND 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 DAY TO SECOND 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 YEAR TO MONTH 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 YEAR TO MONTH 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; - } - - - - - - - - - - - - - - - - - - - } diff --git a/pom.xml b/pom.xml index b97bcd8f96..e2384aa80e 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,6 @@ 42.3.3 10.2.0.jre11 21.5.0.0 - 2.1.0.4 0.9.0.RELEASE @@ -385,11 +384,6 @@ - - - - - org.testcontainers