[jOOQ/jOOQ#11960] Add support for Redshift YEAR TO MONTH interval literals

This commit is contained in:
Lukas Eder 2021-06-03 16:03:13 +02:00
parent 57bf3e2524
commit d2faa7c2df
4 changed files with 84 additions and 23 deletions

View File

@ -78,6 +78,14 @@ abstract class AbstractTypedNamed<T> extends AbstractNamed implements Typed<T> {
return getDataType().getType();
}
/**
* [#11959] A workaround to get access to the actual data type of an
* expression.
*/
/* non-final */ DataType<?> getExpressionDataType() {
return getDataType();
}
@Override
public final DataType<T> getDataType() {
return type;

View File

@ -200,7 +200,11 @@ extends
default: throw unsupported();
}
if (getDataType().isDate())
// [#10258] [#11954]
if (((AbstractField<?>) interval).getExpressionDataType().isInterval())
ctx.sql('(').visit(date).sql(" + ").visit(interval).sql(')');
else if (getDataType().isDate())
// [#10258] Special case for DATE + INTEGER arithmetic
if (datePart == DatePart.DAY)

View File

@ -686,6 +686,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
case H2:
case HSQLDB:
case POSTGRES:
@ -698,6 +699,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
switch (ctx.family()) {
case POSTGRES:
return true;
}
@ -2232,8 +2234,8 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
}
static final class DefaultDayToSecondBinding<U> extends AbstractBinding<DayToSecond, U> {
private static final Set<SQLDialect> REQUIRE_PG_INTERVAL_SYNTAX = SQLDialect.supportedBy(POSTGRES);
private static final Set<SQLDialect> REQUIRE_STANDARD_INTERVAL = SQLDialect.supportedBy(H2);
private static final Set<SQLDialect> REQUIRE_PG_INTERVAL = SQLDialect.supportedBy(POSTGRES);
private static final Set<SQLDialect> REQUIRE_STANDARD_INTERVAL = SQLDialect.supportedBy(H2);
DefaultDayToSecondBinding(DataType<DayToSecond> dataType, Converter<DayToSecond, U> converter) {
super(dataType, converter);
@ -2241,32 +2243,25 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
@Override
void sqlInline0(BindingSQLContext<U> ctx, DayToSecond value) throws SQLException {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL_SYNTAX.contains(ctx.dialect())) {
int sign = value.getSign();
int days = sign * value.getDays();
ctx.render().sql('\'')
.sql(days >= 0 ? '+' : '-')
.sql(Math.abs(days))
.sql(' ')
.sql(sign * value.getHours())
.sql(':')
.sql(sign * value.getMinutes())
.sql(':')
.sql(sign * value.getSeconds())
.sql('.')
.sql(StringUtils.leftPad(Integer.toString(value.getNano()), 9, '0'))
.sql('\'');
}
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.render().visit(inline(toPGInterval(value).toString()));
else
ctx.render().sql('\'').sql(value.toString()).sql('\'');
super.sqlInline0(ctx, value);
}
@Override
final void set0(BindingSetStatementContext<U> ctx, DayToSecond value) throws SQLException {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL_SYNTAX.contains(ctx.dialect()))
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.statement().setObject(ctx.index(), toPGInterval(value));
else
ctx.statement().setString(ctx.index(), renderDTS(ctx, value));
@ -2279,7 +2274,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
@Override
final DayToSecond get0(BindingGetResultSetContext<U> ctx) throws SQLException {
if (REQUIRE_PG_INTERVAL_SYNTAX.contains(ctx.dialect())) {
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect())) {
Object object = ctx.resultSet().getObject(ctx.index());
return object == null ? null : PostgresUtils.toDayToSecond(object);
}
@ -2289,7 +2284,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
@Override
final DayToSecond get0(BindingGetStatementContext<U> ctx) throws SQLException {
if (REQUIRE_PG_INTERVAL_SYNTAX.contains(ctx.dialect())) {
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect())) {
Object object = ctx.statement().getObject(ctx.index());
return object == null ? null : PostgresUtils.toDayToSecond(object);
}
@ -4609,11 +4604,27 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
super(dataType, converter);
}
@Override
final void sqlInline0(BindingSQLContext<U> ctx, YearToSecond value) throws SQLException {
// [#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);
}
@Override
final void set0(BindingSetStatementContext<U> ctx, YearToSecond value) throws SQLException {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.statement().setObject(ctx.index(), toPGInterval(value));
else
ctx.statement().setString(ctx.index(), value.toString());
@ -4668,11 +4679,27 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
super(dataType, converter);
}
@Override
final void sqlInline0(BindingSQLContext<U> ctx, YearToMonth value) throws SQLException {
// [#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);
}
@Override
final void set0(BindingSetStatementContext<U> ctx, YearToMonth value) throws SQLException {
// [#566] Interval data types are best bound as Strings
if (REQUIRE_PG_INTERVAL.contains(ctx.dialect()))
ctx.statement().setObject(ctx.index(), toPGInterval(value));
else
ctx.statement().setString(ctx.index(), renderYTM(ctx, value));

View File

@ -166,6 +166,28 @@ final class Expression<T> extends AbstractTransformable<T> {
this.rhs = rhs;
}
@Override
DataType<?> getExpressionDataType() {
// [#11959] Workaround for lack of proper data type information for interval based expressions
AbstractField<?> l = (AbstractField<?>) lhs;
AbstractField<?> r = (AbstractField<?>) rhs;
DataType<?> lt = l.getExpressionDataType();
DataType<?> rt = r.getExpressionDataType();
switch (operator) {
case MULTIPLY:
case DIVIDE:
return rt.isInterval() ? rt : lt;
case ADD:
return lt.isInterval() ? rt : lt;
}
return lt;
}
@SuppressWarnings("unchecked")
@Override
final void accept0(Context<?> ctx) {