[jOOQ/jOOQ#11711] Use floating point literals for inline DOUBLE, FLOAT, and REAL literals

This commit is contained in:
Lukas Eder 2021-03-25 15:23:13 +01:00
parent db6f8efc22
commit 9923e22bb5
6 changed files with 81 additions and 63 deletions

View File

@ -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<C extends Context<C>> 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}.
*/

View File

@ -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<C extends Context<C>> 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<C extends Context<C>> 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;

View File

@ -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<T, U> implements Binding<T, U> {
/**
* Generated UID
*/
private static final long serialVersionUID = -615723070592774059L;
private static final long serialVersionUID = -615723070592774059L;
static final Set<SQLDialect> REQUIRES_LITERAL_CAST = SQLDialect.supportedBy(H2);
DefaultDoubleBinding(DataType<Double> dataType, Converter<Double, U> converter) {
super(dataType, converter);
@ -2370,6 +2372,8 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
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<T, U> implements Binding<T, U> {
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);
}

View File

@ -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<RenderContext> 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<RenderContext> implements Ren
@Override
public final RenderContext sql(double d) {
applyNewLine();
sql.append(d);
sql.append(doubleFormat().format(d));
resetSeparatorFlags();
return this;
}

View File

@ -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<Integer> 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;

View File

@ -33,7 +33,7 @@
<hsqldb.version>2.5.1</hsqldb.version>
<!-- JDBC drivers for jOOQ-xyz-extensions modules -->
<postgres.version>42.2.18</postgres.version>
<postgres.version>42.2.19</postgres.version>
<!-- From JDK 11 onwards, we need to depend on the JAXB API explicitly -->
<jaxb.version>2.3.1</jaxb.version>