[jOOQ/jOOQ#2230] H2 code generation support for interval types
This includes: [jOOQ/jOOQ#10451] Use H2 native interval arithmetic instead of DATEADD emulation
This commit is contained in:
parent
ca2f784d3d
commit
c3f404b046
@ -37,10 +37,12 @@
|
||||
*/
|
||||
package org.jooq.meta.h2;
|
||||
|
||||
import static org.jooq.impl.DSL.any;
|
||||
import static org.jooq.impl.DSL.choose;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.DSL.noCondition;
|
||||
import static org.jooq.impl.DSL.when;
|
||||
import static org.jooq.impl.DSL.zero;
|
||||
import static org.jooq.meta.h2.information_schema.Tables.COLUMNS;
|
||||
import static org.jooq.tools.StringUtils.defaultString;
|
||||
@ -89,7 +91,11 @@ public class H2TableDefinition extends AbstractTableDefinition {
|
||||
for (Record record : create().select(
|
||||
COLUMNS.COLUMN_NAME,
|
||||
COLUMNS.ORDINAL_POSITION,
|
||||
COLUMNS.TYPE_NAME,
|
||||
|
||||
// [#2230] Translate INTERVAL_TYPE to supported types
|
||||
when(COLUMNS.INTERVAL_TYPE.like(any(inline("%YEAR%"), inline("%MONTH%"))), inline("INTERVAL YEAR TO MONTH"))
|
||||
.when(COLUMNS.INTERVAL_TYPE.like(any(inline("%DAY%"), inline("%HOUR%"), inline("%MINUTE%"), inline("%SECOND%"))), inline("INTERVAL DAY TO SECOND"))
|
||||
.else_(COLUMNS.TYPE_NAME).as(COLUMNS.TYPE_NAME),
|
||||
(((H2Database) getDatabase()).is1_4_197() ? COLUMNS.COLUMN_TYPE : COLUMNS.TYPE_NAME).as(COLUMNS.COLUMN_TYPE),
|
||||
choose().when(COLUMNS.NUMERIC_PRECISION.eq(maxP).and(COLUMNS.NUMERIC_SCALE.eq(maxS)), zero())
|
||||
.otherwise(COLUMNS.CHARACTER_MAXIMUM_LENGTH).as(COLUMNS.CHARACTER_MAXIMUM_LENGTH),
|
||||
@ -120,15 +126,10 @@ public class H2TableDefinition extends AbstractTableDefinition {
|
||||
// [#7644] H2 puts DATETIME_PRECISION in NUMERIC_SCALE column
|
||||
boolean isTimestamp = record.get(COLUMNS.TYPE_NAME).trim().toLowerCase().startsWith("timestamp");
|
||||
|
||||
// [#10389] The interval subtype is contained in COLUMN_TYPE, not TYPE_NAME
|
||||
boolean isInterval = record.get(COLUMNS.TYPE_NAME).trim().toLowerCase().equals("interval");
|
||||
|
||||
DataTypeDefinition type = new DefaultDataTypeDefinition(
|
||||
getDatabase(),
|
||||
getSchema(),
|
||||
isInterval
|
||||
? record.get(COLUMNS.COLUMN_TYPE)
|
||||
: record.get(COLUMNS.TYPE_NAME),
|
||||
record.get(COLUMNS.TYPE_NAME),
|
||||
record.get(COLUMNS.CHARACTER_MAXIMUM_LENGTH),
|
||||
isTimestamp
|
||||
? record.get(COLUMNS.NUMERIC_SCALE)
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
package org.jooq.meta.postgres;
|
||||
|
||||
import static org.jooq.impl.DSL.any;
|
||||
import static org.jooq.impl.DSL.count;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.lower;
|
||||
@ -84,7 +85,10 @@ public class PostgresTableDefinition extends AbstractTableDefinition {
|
||||
List<ColumnDefinition> result = new ArrayList<>();
|
||||
|
||||
PostgresDatabase database = (PostgresDatabase) getDatabase();
|
||||
Field<String> dataType = COLUMNS.DATA_TYPE;
|
||||
Field<String> dataType =
|
||||
when(COLUMNS.INTERVAL_TYPE.like(any(inline("%YEAR%"), inline("%MONTH%"))), inline("INTERVAL YEAR TO MONTH"))
|
||||
.when(COLUMNS.INTERVAL_TYPE.like(any(inline("%DAY%"), inline("%HOUR%"), inline("%MINUTE%"), inline("%SECOND%"))), inline("INTERVAL DAY TO SECOND"))
|
||||
.else_(COLUMNS.DATA_TYPE);
|
||||
Field<Integer> precision = nvl(COLUMNS.DATETIME_PRECISION, COLUMNS.NUMERIC_PRECISION);
|
||||
Field<String> serialColumnDefault = inline("nextval('%_seq'::regclass)");
|
||||
|
||||
|
||||
@ -160,6 +160,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// ...
|
||||
import org.jooq.Attachable;
|
||||
@ -226,6 +227,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
*/
|
||||
private static final long serialVersionUID = -198499389344950496L;
|
||||
private static final Set<SQLDialect> REQUIRE_JDBC_DATE_LITERAL = SQLDialect.supportedBy(MYSQL);
|
||||
private static final Pattern P_INTERVAL_LITERAL = Pattern.compile("INTERVAL '([^']+)' .*");
|
||||
|
||||
// Taken from org.postgresql.PGStatement 9223372036825200000
|
||||
private static final long PG_DATE_POSITIVE_INFINITY = 9223372036825200000L;
|
||||
@ -630,6 +632,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
|
||||
|
||||
case H2:
|
||||
case POSTGRES:
|
||||
return true;
|
||||
}
|
||||
@ -2220,10 +2223,8 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
Object object = ctx.resultSet().getObject(ctx.index());
|
||||
return object == null ? null : PostgresUtils.toDayToSecond(object);
|
||||
}
|
||||
else {
|
||||
String string = ctx.resultSet().getString(ctx.index());
|
||||
return string == null ? null : DayToSecond.valueOf(string);
|
||||
}
|
||||
else
|
||||
return parseDTS(ctx, ctx.resultSet().getString(ctx.index()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2232,16 +2233,22 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
Object object = ctx.statement().getObject(ctx.index());
|
||||
return object == null ? null : PostgresUtils.toDayToSecond(object);
|
||||
}
|
||||
else {
|
||||
String string = ctx.statement().getString(ctx.index());
|
||||
return string == null ? null : DayToSecond.valueOf(string);
|
||||
}
|
||||
else
|
||||
return parseDTS(ctx, ctx.statement().getString(ctx.index()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final DayToSecond get0(BindingGetSQLInputContext<U> ctx) throws SQLException {
|
||||
String string = ctx.input().readString();
|
||||
return string == null ? null : DayToSecond.valueOf(string);
|
||||
return parseDTS(ctx, ctx.input().readString());
|
||||
}
|
||||
|
||||
private final DayToSecond parseDTS(Scope scope, String string) {
|
||||
if (string == null)
|
||||
return null;
|
||||
else if (scope.family() == H2)
|
||||
return DayToSecond.valueOf(P_INTERVAL_LITERAL.matcher(string).replaceFirst("$1"));
|
||||
else
|
||||
return DayToSecond.valueOf(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -4700,10 +4707,8 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
Object object = ctx.resultSet().getObject(ctx.index());
|
||||
return object == null ? null : PostgresUtils.toYearToMonth(object);
|
||||
}
|
||||
else {
|
||||
String string = ctx.resultSet().getString(ctx.index());
|
||||
return string == null ? null : YearToMonth.valueOf(string);
|
||||
}
|
||||
else
|
||||
return parseYTM(ctx, ctx.resultSet().getString(ctx.index()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -4712,16 +4717,22 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
Object object = ctx.statement().getObject(ctx.index());
|
||||
return object == null ? null : PostgresUtils.toYearToMonth(object);
|
||||
}
|
||||
else {
|
||||
String string = ctx.statement().getString(ctx.index());
|
||||
return string == null ? null : YearToMonth.valueOf(string);
|
||||
}
|
||||
else
|
||||
return parseYTM(ctx, ctx.statement().getString(ctx.index()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final YearToMonth get0(BindingGetSQLInputContext<U> ctx) throws SQLException {
|
||||
String string = ctx.input().readString();
|
||||
return string == null ? null : YearToMonth.valueOf(string);
|
||||
return parseYTM(ctx, ctx.input().readString());
|
||||
}
|
||||
|
||||
private final YearToMonth parseYTM(Scope scope, String string) {
|
||||
if (string == null)
|
||||
return null;
|
||||
else if (scope.family() == H2)
|
||||
return YearToMonth.valueOf(P_INTERVAL_LITERAL.matcher(string).replaceFirst("$1"));
|
||||
else
|
||||
return YearToMonth.valueOf(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -401,15 +401,6 @@ final class Expression<T> extends AbstractField<T> {
|
||||
break;
|
||||
}
|
||||
|
||||
case H2: {
|
||||
if (rhs.getType() == YearToMonth.class)
|
||||
ctx.visit(N_DATEADD).sql("('month', ").visit(p(sign * rhsAsYTM().intValue())).sql(", ").visit(lhs).sql(')');
|
||||
else
|
||||
ctx.visit(N_DATEADD).sql("('ms', ").visit(p(sign * (long) rhsAsDTS().getTotalMilli())).sql(", ").visit(lhs).sql(')');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE: {
|
||||
boolean ytm = rhs.getType() == YearToMonth.class;
|
||||
Field<?> interval = p(ytm ? rhsAsYTM().intValue() : rhsAsDTS().getTotalSeconds());
|
||||
@ -584,6 +575,7 @@ final class Expression<T> extends AbstractField<T> {
|
||||
|
||||
|
||||
|
||||
case H2:
|
||||
case POSTGRES:
|
||||
default:
|
||||
ctx.visit(new DefaultExpression<>(lhs, operator, wrap(rhs)));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user