From e2cecab034488c0fc203c972b386540fd04d58d4 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Tue, 23 Mar 2021 13:36:19 +0100 Subject: [PATCH] [jOOQ/jOOQ#11704] Support floating point NaN and (-)Infinity (WIP) --- .../java/org/jooq/impl/DefaultBinding.java | 64 ++++++++++++++----- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java index f5eaa80732..8debc05941 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java @@ -76,10 +76,15 @@ import static org.jooq.SQLDialect.SQLITE; // ... import static org.jooq.conf.ParamType.INLINED; import static org.jooq.impl.DSL.cast; +import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.inline; +import static org.jooq.impl.DSL.log; import static org.jooq.impl.DSL.name; +import static org.jooq.impl.DSL.power; import static org.jooq.impl.DSL.sqrt; import static org.jooq.impl.DSL.using; +import static org.jooq.impl.DefaultBinding.DefaultDoubleBinding.infinity; +import static org.jooq.impl.DefaultBinding.DefaultDoubleBinding.nan; import static org.jooq.impl.DefaultExecuteContext.localTargetConnection; import static org.jooq.impl.DefaultExecuteContext.targetPreparedStatement; import static org.jooq.impl.Keywords.K_ARRAY; @@ -111,6 +116,7 @@ import static org.jooq.impl.SQLDataType.DOUBLE; import static org.jooq.impl.SQLDataType.INTEGER; import static org.jooq.impl.SQLDataType.LONGVARCHAR; import static org.jooq.impl.SQLDataType.OTHER; +import static org.jooq.impl.SQLDataType.REAL; import static org.jooq.impl.SQLDataType.ROWID; import static org.jooq.impl.SQLDataType.SMALLINT; import static org.jooq.impl.SQLDataType.TIME; @@ -2323,24 +2329,50 @@ public class DefaultBinding implements Binding { /** * Generated UID */ - private static final long serialVersionUID = -615723070592774059L; - private static final Set REQUIRE_NAN_CAST = SQLDialect.supportedBy(POSTGRES); + private static final long serialVersionUID = -615723070592774059L; DefaultDoubleBinding(DataType dataType, Converter converter) { super(dataType, converter); } + @SuppressWarnings({ "unchecked", "rawtypes" }) + static final Field nan(BindingSQLContext ctx, DataType type) { + switch (ctx.family()) { + case FIREBIRD: + return log(inline(1), inline(1)); + case H2: + return sqrt(inline(-1)); + case HSQLDB: + return inline(0.0).div(field("0.0e0", (DataType) type)); + default: + return inline("NaN").cast(type); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + static final Field infinity(BindingSQLContext ctx, DataType type, boolean negative) { + switch (ctx.family()) { + case FIREBIRD: + return log(negative ? inline(0.5) : inline(1.5), inline(1)); + case H2: + return negative ? power(inline(0), inline(-1)).neg() : power(inline(0), inline(-1)); + case HSQLDB: + return inline(negative ? -1.0 : 1.0).div(field("0.0e0", (DataType) type)); + default: + return inline(negative ? "-Infinity" : "Infinity").cast(type); + } + } + @Override final void sqlInline0(BindingSQLContext ctx, Double value) { // [#5249] [#6912] [#8063] [#11701] Special inlining of special floating point values - if (value.isNaN() || value.isInfinite()) - if (REQUIRE_NAN_CAST.contains(ctx.dialect())) - ctx.render().visit(inline(value.toString())).sql("::float8"); - else if (ctx.family() == HSQLDB) - ctx.render().visit(sqrt(inline(-1))); - else - ctx.render().visit(new CastNative<>(inline(value.toString()), DOUBLE)); + if (value.isNaN()) + ctx.render().visit(nan(ctx, DOUBLE)); + else if (value == Double.POSITIVE_INFINITY) + ctx.render().visit(infinity(ctx, DOUBLE, false)); + else if (value == Double.NEGATIVE_INFINITY) + ctx.render().visit(infinity(ctx, DOUBLE, true)); else ctx.render().sql(value); } @@ -2496,7 +2528,6 @@ public class DefaultBinding implements Binding { * Generated UID */ private static final long serialVersionUID = -2468794191255859536L; - private static final Set REQUIRE_NAN_CAST = SQLDialect.supportedBy(POSTGRES); DefaultFloatBinding(DataType dataType, Converter converter) { super(dataType, converter); @@ -2506,13 +2537,12 @@ public class DefaultBinding implements Binding { final void sqlInline0(BindingSQLContext ctx, Float value) { // [#5249] [#6912] [#8063] [#11701] Special inlining of special floating point values - if (value.isNaN() || value.isInfinite()) - if (REQUIRE_NAN_CAST.contains(ctx.dialect())) - ctx.render().visit(inline(value.toString())).sql("::float4"); - else if (ctx.family() == HSQLDB) - ctx.render().visit(sqrt(inline(-1))); - else - ctx.render().visit(new CastNative<>(inline(value.toString()), DOUBLE)); + if (value.isNaN()) + ctx.render().visit(nan(ctx, REAL)); + else if (value == Double.POSITIVE_INFINITY) + ctx.render().visit(infinity(ctx, REAL, false)); + else if (value == Double.NEGATIVE_INFINITY) + ctx.render().visit(infinity(ctx, REAL, true)); else ctx.render().sql(value); }