diff --git a/jOOQ/src/main/java/org/jooq/Context.java b/jOOQ/src/main/java/org/jooq/Context.java index bf6836be43..1a6dd1ef4e 100644 --- a/jOOQ/src/main/java/org/jooq/Context.java +++ b/jOOQ/src/main/java/org/jooq/Context.java @@ -38,6 +38,7 @@ package org.jooq; import java.sql.PreparedStatement; +import java.text.DecimalFormat; import java.util.function.Consumer; import org.jooq.RenderContext.CastMode; @@ -481,12 +482,22 @@ public interface Context> extends Scope { @NotNull C sql(long sql); + /** + * A formatter to produce scientific notation for {@link Float} types. + */ + DecimalFormat floatFormat(); + /** * Append some SQL to the context's contained {@link StringBuilder}. */ @NotNull C sql(float sql); + /** + * A formatter to produce scientific notation for {@link Double} types. + */ + DecimalFormat doubleFormat(); + /** * Append some SQL to the context's contained {@link StringBuilder}. */ diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java index 3a1317f17e..756a34f9f2 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java @@ -50,11 +50,11 @@ import static org.jooq.conf.InvocationOrder.REVERSE; import static org.jooq.conf.ParamType.INDEXED; import static org.jooq.impl.Tools.EMPTY_CLAUSE; import static org.jooq.impl.Tools.EMPTY_QUERYPART; -import static org.jooq.impl.Tools.settings; import static org.jooq.impl.Tools.BooleanDataKey.DATA_NESTED_SET_OPERATIONS; import static org.jooq.impl.Tools.BooleanDataKey.DATA_OMIT_CLAUSE_EVENT_EMISSION; import java.sql.PreparedStatement; +import java.text.DecimalFormat; import java.util.ArrayDeque; import java.util.Arrays; import java.util.BitSet; @@ -62,10 +62,10 @@ import java.util.Deque; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Supplier; -import java.util.Set; import org.jooq.BindContext; import org.jooq.Clause; @@ -92,8 +92,6 @@ import org.jooq.conf.SettingsTools; import org.jooq.conf.StatementType; import org.jooq.tools.StringUtils; -import org.jetbrains.annotations.NotNull; - /** * @author Lukas Eder */ @@ -141,6 +139,10 @@ abstract class AbstractContext> extends AbstractScope imple boolean qualifySchema = true; boolean qualifyCatalog = true; + // [#11711] Enforcing scientific notation + private transient DecimalFormat doubleFormat; + private transient DecimalFormat floatFormat; + AbstractContext(Configuration configuration, PreparedStatement stmt) { super(configuration); this.stmt = stmt; @@ -782,6 +784,22 @@ abstract class AbstractContext> extends AbstractScope imple // XXX RenderContext API // ------------------------------------------------------------------------ + @Override + public final DecimalFormat floatFormat() { + if (floatFormat == null) + floatFormat = new DecimalFormat("0.#######E0"); + + return floatFormat; + } + + @Override + public final DecimalFormat doubleFormat() { + if (doubleFormat == null) + doubleFormat = new DecimalFormat("0.################E0"); + + return doubleFormat; + } + @Override public final ParamType paramType() { return forcedParamType != null ? forcedParamType : paramType; diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java index 041f0ad89e..cad5b6fb61 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java @@ -84,6 +84,7 @@ 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.REQUIRES_LITERAL_CAST; import static org.jooq.impl.DefaultBinding.DefaultDoubleBinding.infinity; import static org.jooq.impl.DefaultBinding.DefaultDoubleBinding.nan; import static org.jooq.impl.DefaultExecuteContext.localTargetConnection; @@ -2330,7 +2331,8 @@ public class DefaultBinding implements Binding { /** * Generated UID */ - private static final long serialVersionUID = -615723070592774059L; + private static final long serialVersionUID = -615723070592774059L; + static final Set REQUIRES_LITERAL_CAST = SQLDialect.supportedBy(H2); DefaultDoubleBinding(DataType dataType, Converter converter) { super(dataType, converter); @@ -2370,6 +2372,8 @@ public class DefaultBinding implements Binding { ctx.render().visit(infinity(ctx, DOUBLE, false)); else if (value == Double.NEGATIVE_INFINITY) ctx.render().visit(infinity(ctx, DOUBLE, true)); + else if (REQUIRES_LITERAL_CAST.contains(ctx.dialect())) + ctx.render().visit(field(ctx.render().doubleFormat().format(value)).cast(DOUBLE)); else ctx.render().sql(value); } @@ -2540,6 +2544,8 @@ public class DefaultBinding implements Binding { ctx.render().visit(infinity(ctx, REAL, false)); else if (value == Double.NEGATIVE_INFINITY) ctx.render().visit(infinity(ctx, REAL, true)); + else if (REQUIRES_LITERAL_CAST.contains(ctx.dialect())) + ctx.render().visit(field(ctx.render().floatFormat().format(value)).cast(REAL)); else ctx.render().sql(value); } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java index 15e1f63d80..7df0c56df7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java @@ -63,7 +63,6 @@ import org.jooq.Constants; import org.jooq.Field; import org.jooq.ForeignKey; import org.jooq.Param; -// ... import org.jooq.QueryPart; import org.jooq.QueryPartInternal; import org.jooq.RenderContext; @@ -459,7 +458,7 @@ class DefaultRenderContext extends AbstractContext implements Ren @Override public final RenderContext sql(float f) { applyNewLine(); - sql.append(f); + sql.append(floatFormat().format(f)); resetSeparatorFlags(); return this; } @@ -467,7 +466,7 @@ class DefaultRenderContext extends AbstractContext implements Ren @Override public final RenderContext sql(double d) { applyNewLine(); - sql.append(d); + sql.append(doubleFormat().format(d)); resetSeparatorFlags(); return this; } diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index 2687589841..9bb80642ba 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -11903,56 +11903,48 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { private final Number parseUnsignedNumericLiteralIf(Sign sign) { int p = position(); - char c; + boolean decimal = false; + parseDigits(); - for (;;) { - c = character(); - if (c >= '0' && c <= '9') { - positionInc(); - } - else - break; - } - - if (c == '.') { - positionInc(); - } - else { - if (p == position()) - return null; - - String s = substring(p, position()); - parseWhitespaceIf(); - try { - return sign == Sign.MINUS - ? -Long.valueOf(s) - : Long.valueOf(s); - } - catch (Exception e1) { - return sign == Sign.MINUS - ? new BigInteger(s).negate() - : new BigInteger(s); - } - } - - for (;;) { - c = character(); - if (c >= '0' && c <= '9') { - positionInc(); - } - else - break; - } + if (decimal |= parseIf('.', false)) + parseDigits(); if (p == position()) return null; - String s = substring(p, position()); - parseWhitespaceIf(); - return sign == Sign.MINUS - ? new BigDecimal(s).negate() - : new BigDecimal(s); - // TODO add floating point support + if (parseIf('e', false) || parseIf('E', false)) { + parseIf('-', false); + parseDigits(); + + String s = substring(p, position()); + parseWhitespaceIf(); + return sign == Sign.MINUS ? -Double.parseDouble(s) : Double.parseDouble(s); + } + else { + String s = substring(p, position()); + parseWhitespaceIf(); + + if (decimal) + return sign == Sign.MINUS ? new BigDecimal(s).negate() : new BigDecimal(s); + + try { + return sign == Sign.MINUS ? -Long.valueOf(s) : Long.valueOf(s); + } + catch (Exception e1) { + return sign == Sign.MINUS ? new BigInteger(s).negate() : new BigInteger(s); + } + } + } + + private void parseDigits() { + for (;;) { + char c = character(); + + if (c >= '0' && c <= '9') + positionInc(); + else + break; + } } private final Field parseZeroOne() { @@ -12089,15 +12081,7 @@ final class DefaultParseContext extends AbstractScope implements ParseContext { @Override public final Long parseUnsignedIntegerLiteralIf() { int p = position(); - - for (;;) { - char c = character(); - - if (c >= '0' && c <= '9') - positionInc(); - else - break; - } + parseDigits(); if (p == position()) return null; diff --git a/pom.xml b/pom.xml index f8471dc6ba..b5ce1b9178 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ 2.5.1 - 42.2.18 + 42.2.19 2.3.1