[jOOQ/jOOQ#8821] Add Settings.parseNamedParamPrefix to support dialect
specific named parameter placeholders
This commit is contained in:
parent
a49950b831
commit
c6d049d9d7
@ -265,6 +265,8 @@ public class Settings
|
||||
protected String parseDateFormat = "YYYY-MM-DD";
|
||||
@XmlElement(defaultValue = "YYYY-MM-DD HH24:MI:SS.FF")
|
||||
protected String parseTimestampFormat = "YYYY-MM-DD HH24:MI:SS.FF";
|
||||
@XmlElement(defaultValue = ":")
|
||||
protected String parseNamedParamPrefix = ":";
|
||||
@XmlElement(defaultValue = "DEFAULT")
|
||||
@XmlSchemaType(name = "string")
|
||||
protected ParseNameCase parseNameCase = ParseNameCase.DEFAULT;
|
||||
@ -450,12 +452,12 @@ public class Settings
|
||||
}
|
||||
|
||||
/**
|
||||
* The prefix to use for named parameters.
|
||||
* The prefix to use for named parameters in generated SQL.
|
||||
* <p>
|
||||
* Named parameter syntax defaults to <code>:name</code> (such as supported by Oracle, JPA, Spring), but
|
||||
* vendor specific parameters may look differently. This flag can be used to determine the prefix to be
|
||||
* used by named parameters, such as <code>@</code> for SQL Server's <code>@name</code> or <code>$</code>
|
||||
* for PostgreSQL's <code>$name</code>.
|
||||
* for PostgreSQL's <code>$name</code>, when generating SQL.
|
||||
* <p>
|
||||
* "Named indexed" parameters can be obtained in the same way by specifingy {@code ParamType#NAMED} and not
|
||||
* providing a name to parameters, resulting in <code>:1</code> or <code>@1</code> or <code>$1</code>, etc.
|
||||
@ -466,12 +468,12 @@ public class Settings
|
||||
}
|
||||
|
||||
/**
|
||||
* The prefix to use for named parameters.
|
||||
* The prefix to use for named parameters in generated SQL.
|
||||
* <p>
|
||||
* Named parameter syntax defaults to <code>:name</code> (such as supported by Oracle, JPA, Spring), but
|
||||
* vendor specific parameters may look differently. This flag can be used to determine the prefix to be
|
||||
* used by named parameters, such as <code>@</code> for SQL Server's <code>@name</code> or <code>$</code>
|
||||
* for PostgreSQL's <code>$name</code>.
|
||||
* for PostgreSQL's <code>$name</code>, when generating SQL.
|
||||
* <p>
|
||||
* "Named indexed" parameters can be obtained in the same way by specifingy {@code ParamType#NAMED} and not
|
||||
* providing a name to parameters, resulting in <code>:1</code> or <code>@1</code> or <code>$1</code>, etc.
|
||||
@ -2389,6 +2391,38 @@ public class Settings
|
||||
this.parseTimestampFormat = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The prefix to use for named parameters in parsed SQL.
|
||||
* <p>
|
||||
* Named parameter syntax defaults to <code>:name</code> (such as supported by Oracle, JPA, Spring), but
|
||||
* vendor specific parameters may look differently. This flag can be used to determine the prefix to be
|
||||
* used by named parameters, such as <code>@</code> for SQL Server's <code>@name</code> or <code>$</code>
|
||||
* for PostgreSQL's <code>$name</code> when parsing SQL.
|
||||
* <p>
|
||||
* "Named indexed" parameters can be obtained in the same way by specifingy {@code ParamType#NAMED} and not
|
||||
* providing a name to parameters, resulting in <code>:1</code> or <code>@1</code> or <code>$1</code>, etc.
|
||||
*
|
||||
*/
|
||||
public String getParseNamedParamPrefix() {
|
||||
return parseNamedParamPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* The prefix to use for named parameters in parsed SQL.
|
||||
* <p>
|
||||
* Named parameter syntax defaults to <code>:name</code> (such as supported by Oracle, JPA, Spring), but
|
||||
* vendor specific parameters may look differently. This flag can be used to determine the prefix to be
|
||||
* used by named parameters, such as <code>@</code> for SQL Server's <code>@name</code> or <code>$</code>
|
||||
* for PostgreSQL's <code>$name</code> when parsing SQL.
|
||||
* <p>
|
||||
* "Named indexed" parameters can be obtained in the same way by specifingy {@code ParamType#NAMED} and not
|
||||
* providing a name to parameters, resulting in <code>:1</code> or <code>@1</code> or <code>$1</code>, etc.
|
||||
*
|
||||
*/
|
||||
public void setParseNamedParamPrefix(String value) {
|
||||
this.parseNamedParamPrefix = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* [#7337] The default name case for parsed identifiers.
|
||||
*
|
||||
@ -2676,12 +2710,12 @@ public class Settings
|
||||
}
|
||||
|
||||
/**
|
||||
* The prefix to use for named parameters.
|
||||
* The prefix to use for named parameters in generated SQL.
|
||||
* <p>
|
||||
* Named parameter syntax defaults to <code>:name</code> (such as supported by Oracle, JPA, Spring), but
|
||||
* vendor specific parameters may look differently. This flag can be used to determine the prefix to be
|
||||
* used by named parameters, such as <code>@</code> for SQL Server's <code>@name</code> or <code>$</code>
|
||||
* for PostgreSQL's <code>$name</code>.
|
||||
* for PostgreSQL's <code>$name</code>, when generating SQL.
|
||||
* <p>
|
||||
* "Named indexed" parameters can be obtained in the same way by specifingy {@code ParamType#NAMED} and not
|
||||
* providing a name to parameters, resulting in <code>:1</code> or <code>@1</code> or <code>$1</code>, etc.
|
||||
@ -3355,6 +3389,23 @@ public class Settings
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The prefix to use for named parameters in parsed SQL.
|
||||
* <p>
|
||||
* Named parameter syntax defaults to <code>:name</code> (such as supported by Oracle, JPA, Spring), but
|
||||
* vendor specific parameters may look differently. This flag can be used to determine the prefix to be
|
||||
* used by named parameters, such as <code>@</code> for SQL Server's <code>@name</code> or <code>$</code>
|
||||
* for PostgreSQL's <code>$name</code> when parsing SQL.
|
||||
* <p>
|
||||
* "Named indexed" parameters can be obtained in the same way by specifingy {@code ParamType#NAMED} and not
|
||||
* providing a name to parameters, resulting in <code>:1</code> or <code>@1</code> or <code>$1</code>, etc.
|
||||
*
|
||||
*/
|
||||
public Settings withParseNamedParamPrefix(String value) {
|
||||
setParseNamedParamPrefix(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* [#7337] The default name case for parsed identifiers.
|
||||
*
|
||||
@ -3590,6 +3641,7 @@ public class Settings
|
||||
builder.append("parseLocale", parseLocale);
|
||||
builder.append("parseDateFormat", parseDateFormat);
|
||||
builder.append("parseTimestampFormat", parseTimestampFormat);
|
||||
builder.append("parseNamedParamPrefix", parseNamedParamPrefix);
|
||||
builder.append("parseNameCase", parseNameCase);
|
||||
builder.append("parseWithMetaLookups", parseWithMetaLookups);
|
||||
builder.append("parseSetCommands", parseSetCommands);
|
||||
@ -4488,6 +4540,15 @@ public class Settings
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (parseNamedParamPrefix == null) {
|
||||
if (other.parseNamedParamPrefix!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!parseNamedParamPrefix.equals(other.parseNamedParamPrefix)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (parseNameCase == null) {
|
||||
if (other.parseNameCase!= null) {
|
||||
return false;
|
||||
@ -4708,6 +4769,7 @@ public class Settings
|
||||
result = ((prime*result)+((parseLocale == null)? 0 :parseLocale.hashCode()));
|
||||
result = ((prime*result)+((parseDateFormat == null)? 0 :parseDateFormat.hashCode()));
|
||||
result = ((prime*result)+((parseTimestampFormat == null)? 0 :parseTimestampFormat.hashCode()));
|
||||
result = ((prime*result)+((parseNamedParamPrefix == null)? 0 :parseNamedParamPrefix.hashCode()));
|
||||
result = ((prime*result)+((parseNameCase == null)? 0 :parseNameCase.hashCode()));
|
||||
result = ((prime*result)+((parseWithMetaLookups == null)? 0 :parseWithMetaLookups.hashCode()));
|
||||
result = ((prime*result)+((parseSetCommands == null)? 0 :parseSetCommands.hashCode()));
|
||||
|
||||
@ -596,7 +596,7 @@ final class DiagnosticsResultSet extends DefaultResultSet {
|
||||
// XXX Utilities
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private final void wasPrimitive(int columnIndex) {
|
||||
private final void wasPrimitive(int columnIndex) throws SQLException {
|
||||
checkPrimitive();
|
||||
|
||||
wasColumnIndex = columnIndex;
|
||||
@ -608,7 +608,7 @@ final class DiagnosticsResultSet extends DefaultResultSet {
|
||||
wasPrimitive(super.findColumn(columnLabel));
|
||||
}
|
||||
|
||||
private final void checkPrimitive() {
|
||||
private final void checkPrimitive() throws SQLException {
|
||||
if (wasPrimitive && wasNullable) {
|
||||
DefaultDiagnosticsContext ctx = ctx();
|
||||
ctx.resultSetMissingWasNullCall = true;
|
||||
@ -628,7 +628,7 @@ final class DiagnosticsResultSet extends DefaultResultSet {
|
||||
read(super.findColumn(columnLabel));
|
||||
}
|
||||
|
||||
private final DefaultDiagnosticsContext ctx() {
|
||||
private final DefaultDiagnosticsContext ctx() throws SQLException {
|
||||
DefaultDiagnosticsContext ctx = new DefaultDiagnosticsContext(sql);
|
||||
|
||||
ctx.resultSet = super.getDelegate();
|
||||
|
||||
@ -748,7 +748,7 @@ final class LoaderImpl<R extends Record> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
public void close() throws SQLException {
|
||||
for (CachedPS ps : map.values())
|
||||
safeClose(ps.getDelegate());
|
||||
}
|
||||
|
||||
@ -83,6 +83,7 @@ import static org.jooq.impl.Tools.aliased;
|
||||
import static org.jooq.impl.Tools.normaliseNameCase;
|
||||
import static org.jooq.impl.XMLPassingMechanism.BY_REF;
|
||||
import static org.jooq.impl.XMLPassingMechanism.BY_VALUE;
|
||||
import static org.jooq.tools.StringUtils.defaultIfNull;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigDecimal;
|
||||
@ -7049,9 +7050,15 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
|
||||
|
||||
|
||||
switch (characterUpper()) {
|
||||
|
||||
// [#8821] Known prefixes so far:
|
||||
case ':':
|
||||
case '@':
|
||||
case '?':
|
||||
return parseBindVariable();
|
||||
if ((field = parseBindVariableIf()) != null)
|
||||
return field;
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
@ -7065,7 +7072,9 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
|
||||
return inline(parseStringLiteral());
|
||||
|
||||
case '$':
|
||||
if ((value = parseDollarQuotedStringLiteralIf()) != null)
|
||||
if ((field = parseBindVariableIf()) != null)
|
||||
return field;
|
||||
else if ((value = parseDollarQuotedStringLiteralIf()) != null)
|
||||
return inline((String) value);
|
||||
|
||||
break;
|
||||
@ -11501,10 +11510,8 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
|
||||
return c;
|
||||
}
|
||||
|
||||
private final Field<?> parseBindVariable() {
|
||||
|
||||
// [#11074] Bindings can be Param or even Field types
|
||||
Object binding = nextBinding();
|
||||
private final Field<?> parseBindVariableIf() {
|
||||
int p = position();
|
||||
String paramName;
|
||||
|
||||
switch (character()) {
|
||||
@ -11513,16 +11520,28 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
|
||||
paramName = "" + bindIndex;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
parse(':', false);
|
||||
Name identifier = parseIdentifier();
|
||||
paramName = identifier.last();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw exception("Illegal bind variable character");
|
||||
String prefix = defaultIfNull(settings().getParseNamedParamPrefix(), ":");
|
||||
|
||||
if (parseIf(prefix, false)) {
|
||||
Name identifier = parseIdentifier();
|
||||
paramName = identifier.last();
|
||||
|
||||
// [#8821] Avoid conflicts with dollar quoted string literals
|
||||
if ("$".equals(prefix) && paramName.endsWith("$")) {
|
||||
position(p);
|
||||
return null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
// [#11074] Bindings can be Param or even Field types
|
||||
Object binding = nextBinding();
|
||||
|
||||
if (binding instanceof Field)
|
||||
return (Field<?>) binding;
|
||||
|
||||
@ -11684,8 +11703,10 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
|
||||
private final String parseDollarQuotedStringLiteralIf() {
|
||||
int previous = position();
|
||||
|
||||
if (!parseIf('$'))
|
||||
if (!peek('$'))
|
||||
return null;
|
||||
else
|
||||
parse('$');
|
||||
|
||||
int openTokenStart = previous;
|
||||
int openTokenEnd = previous;
|
||||
@ -12044,7 +12065,15 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
|
||||
|
||||
private final Field<Long> parseUnsignedIntegerOrBindVariable() {
|
||||
Long i = parseUnsignedIntegerLiteralIf();
|
||||
return i != null ? DSL.inline(i) : (Field<Long>) parseBindVariable();
|
||||
|
||||
if (i != null)
|
||||
return DSL.inline(i);
|
||||
|
||||
Field<?> f = parseBindVariableIf();
|
||||
if (f != null)
|
||||
return (Field<Long>) f;
|
||||
|
||||
throw expected("Unsigned integer or bind variable");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -76,6 +76,7 @@ final class ParsingConnectionFactory implements ConnectionFactory {
|
||||
ParsingConnectionFactory(Configuration configuration) {
|
||||
this.configuration = configuration.derive();
|
||||
this.configuration.set(SettingsTools.clone(configuration.settings())
|
||||
.withParseNamedParamPrefix("$")
|
||||
.withRenderNamedParamPrefix("$")
|
||||
.withParamType(ParamType.NAMED));
|
||||
}
|
||||
|
||||
@ -41,35 +41,24 @@ import static org.jooq.conf.ParamType.NAMED;
|
||||
import static org.jooq.impl.Tools.recordFactory;
|
||||
import static org.jooq.tools.StringUtils.defaultIfNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Date;
|
||||
import java.sql.NClob;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.RowId;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.SQLType;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.sql.Wrapper;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Calendar;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jooq.BindingGetResultSetContext;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Cursor;
|
||||
import org.jooq.DataType;
|
||||
@ -78,6 +67,7 @@ import org.jooq.Record;
|
||||
import org.jooq.conf.SettingsTools;
|
||||
import org.jooq.impl.DefaultRenderContext.Rendered;
|
||||
import org.jooq.tools.jdbc.DefaultPreparedStatement;
|
||||
import org.jooq.tools.jdbc.DefaultResultSet;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.reactivestreams.Subscriber;
|
||||
@ -85,6 +75,7 @@ import org.reactivestreams.Subscription;
|
||||
|
||||
import io.r2dbc.spi.ColumnMetadata;
|
||||
import io.r2dbc.spi.Connection;
|
||||
import io.r2dbc.spi.Row;
|
||||
import io.r2dbc.spi.RowMetadata;
|
||||
import io.r2dbc.spi.Statement;
|
||||
|
||||
@ -159,13 +150,21 @@ final class R2DBC {
|
||||
RecordDelegate<AbstractRecord> delegate = Tools.newRecord(true, (Supplier<AbstractRecord>) recordFactory(query.getRecordType(), Tools.row0(fields)), query.configuration());
|
||||
|
||||
return (R) delegate.operate(record -> {
|
||||
// TODO: Go through Field.getBinding()
|
||||
|
||||
// TODO: What data to pass here?
|
||||
DefaultBindingGetResultSetContext<?> ctx = new DefaultBindingGetResultSetContext<>(
|
||||
query.configuration(),
|
||||
query.configuration().data(),
|
||||
new R2DBCResultSet(query.configuration(), row),
|
||||
0
|
||||
);
|
||||
|
||||
// TODO: Make sure all the embeddable records, and other types of nested records are supported
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Field<?> f = fields[i];
|
||||
Object value = row.get(i, f.getType());
|
||||
record.values[i] = value;
|
||||
record.originals[i] = value;
|
||||
ctx.index(i + 1);
|
||||
fields[i].getBinding().get((BindingGetResultSetContext) ctx);
|
||||
record.values[i] = ctx.value();
|
||||
record.originals[i] = ctx.value();
|
||||
}
|
||||
|
||||
return record;
|
||||
@ -208,20 +207,15 @@ final class R2DBC {
|
||||
public final void onNext(Connection c) {
|
||||
try {
|
||||
DefaultRenderContext render = new DefaultRenderContext(query.configuration().derive(
|
||||
SettingsTools.clone(query.configuration().settings()).withParamType(NAMED).withRenderNamedParamPrefix("$")
|
||||
SettingsTools.clone(query.configuration().settings())
|
||||
.withParseNamedParamPrefix("$")
|
||||
.withRenderNamedParamPrefix("$")
|
||||
.withParamType(NAMED)
|
||||
));
|
||||
|
||||
Rendered r = new Rendered(render.paramType(NAMED).visit(query).render(), render.bindValues(), render.skipUpdateCounts());
|
||||
Statement stmt = c.createStatement(r.sql);
|
||||
new DefaultBindContext(query.configuration(), new R2DBCPreparedStatement(query.configuration(), stmt)).visit(r.bindValues);
|
||||
// ;
|
||||
// int i = 0;
|
||||
// for (Param<?> p : r.bindValues)
|
||||
// if (p.getValue() == null)
|
||||
// stmt.bindNull(i++, p.getType());
|
||||
// else
|
||||
// stmt.bind(i++, p.getValue());
|
||||
|
||||
stmt.execute().subscribe(new ResultSubscriber<>(query, this));
|
||||
}
|
||||
|
||||
@ -328,28 +322,13 @@ final class R2DBC {
|
||||
// JDBC to R2DBC bridges for better interop, where it doesn't matter
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static abstract class R2DBCWrapper implements Wrapper {
|
||||
|
||||
@Override
|
||||
public final <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("R2DBC can't unwrap JDBC types");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static final class R2DBCPreparedStatement extends DefaultPreparedStatement {
|
||||
|
||||
final Configuration c;
|
||||
final Statement s;
|
||||
|
||||
R2DBCPreparedStatement(Configuration c, Statement s) {
|
||||
|
||||
// TODO: Refactor super class to throw a custom exception if trying to dereference this null pointer.
|
||||
super(null);
|
||||
super(null, null, () -> new SQLFeatureNotSupportedException("Unsupported operation of the JDBC to R2DBC bridge."));
|
||||
|
||||
this.c = c;
|
||||
this.s = s;
|
||||
@ -367,7 +346,7 @@ final class R2DBC {
|
||||
if (x == null)
|
||||
s.bindNull(parameterIndex - 1, type);
|
||||
else
|
||||
bindNonNull(parameterIndex - 1, conversion.apply(x));
|
||||
bindNonNull(parameterIndex, conversion.apply(x));
|
||||
}
|
||||
|
||||
private final void bindNonNull(int parameterIndex, Object x) {
|
||||
@ -483,154 +462,122 @@ final class R2DBC {
|
||||
public final void setObject(int parameterIndex, Object x, SQLType targetSqlType) throws SQLException {
|
||||
setObject(parameterIndex, x, defaultIfNull(targetSqlType.getVendorTypeNumber(), Types.OTHER));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
static final class R2DBCResultSet extends DefaultResultSet {
|
||||
|
||||
final Configuration c;
|
||||
final Row r;
|
||||
boolean wasNull;
|
||||
|
||||
R2DBCResultSet(Configuration c, Row r) {
|
||||
super(null, null, () -> new SQLFeatureNotSupportedException("Unsupported operation of the JDBC to R2DBC bridge."));
|
||||
|
||||
this.c = c;
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
private final <T> T wasNull(T nullable) {
|
||||
wasNull = nullable == null;
|
||||
return nullable;
|
||||
}
|
||||
|
||||
private final <T> T nullable(int columnIndex, Class<T> type) {
|
||||
return nullable(columnIndex, type, t -> t);
|
||||
}
|
||||
|
||||
private final <T, U> U nullable(int columnIndex, Class<T> type, Function<? super T, ? extends U> conversion) {
|
||||
T t = wasNull(r.get(columnIndex - 1, type));
|
||||
return wasNull ? null : conversion.apply(t);
|
||||
}
|
||||
|
||||
private final <T> T nonNull(int columnIndex, Class<T> type, T nullValue) {
|
||||
T t = wasNull(r.get(columnIndex - 1, type));
|
||||
return wasNull ? nullValue : t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final boolean wasNull() throws SQLException {
|
||||
return wasNull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final boolean getBoolean(int columnIndex) throws SQLException {
|
||||
return nonNull(columnIndex, Boolean.class, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final byte getByte(int columnIndex) throws SQLException {
|
||||
return nonNull(columnIndex, Byte.class, (byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setRef(int parameterIndex, Ref x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final short getShort(int columnIndex) throws SQLException {
|
||||
return nonNull(columnIndex, Short.class, (short) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBlob(int parameterIndex, Blob x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final int getInt(int columnIndex) throws SQLException {
|
||||
return nonNull(columnIndex, Integer.class, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setClob(int parameterIndex, Clob x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final long getLong(int columnIndex) throws SQLException {
|
||||
return nonNull(columnIndex, Long.class, 0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setArray(int parameterIndex, Array x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final float getFloat(int columnIndex) throws SQLException {
|
||||
return nonNull(columnIndex, Float.class, 0.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final double getDouble(int columnIndex) throws SQLException {
|
||||
return nonNull(columnIndex, Double.class, 0.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final BigDecimal getBigDecimal(int columnIndex) throws SQLException {
|
||||
return nullable(columnIndex, BigDecimal.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final String getString(int columnIndex) throws SQLException {
|
||||
return nullable(columnIndex, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setURL(int parameterIndex, URL x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final byte[] getBytes(int columnIndex) throws SQLException {
|
||||
return nullable(columnIndex, byte[].class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setRowId(int parameterIndex, RowId x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final Date getDate(int columnIndex) throws SQLException {
|
||||
return nullable(columnIndex, LocalDate.class, Date::valueOf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final Time getTime(int columnIndex) throws SQLException {
|
||||
return nullable(columnIndex, LocalTime.class, Time::valueOf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setNClob(int parameterIndex, NClob value) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final Timestamp getTimestamp(int columnIndex) throws SQLException {
|
||||
return nullable(columnIndex, LocalDateTime.class, Timestamp::valueOf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final Object getObject(int columnIndex) throws SQLException {
|
||||
return getObject(columnIndex, Object.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setClob(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setNClob(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("The JDBC to R2DBC bridge doesn't support this data type");
|
||||
public final <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
|
||||
return nullable(columnIndex, type);
|
||||
}
|
||||
}
|
||||
|
||||
static final class R2DBCResultSetMetaData extends R2DBCWrapper implements ResultSetMetaData {
|
||||
static final class R2DBCResultSetMetaData implements ResultSetMetaData {
|
||||
|
||||
final Configuration c;
|
||||
final RowMetadata m;
|
||||
@ -644,6 +591,16 @@ final class R2DBC {
|
||||
return m.getColumnMetadata(column - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
throw new SQLFeatureNotSupportedException("R2DBC can't unwrap JDBC types");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getColumnCount() throws SQLException {
|
||||
return m.getColumnNames().size();
|
||||
|
||||
@ -43,6 +43,7 @@ import static org.jooq.impl.QueryPartListView.wrap;
|
||||
import static org.jooq.impl.SQLDataType.OTHER;
|
||||
import static org.jooq.impl.Tools.embeddedFields;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_LIST_ALREADY_INDENTED;
|
||||
import static org.jooq.tools.StringUtils.defaultIfNull;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
@ -163,7 +164,7 @@ final class Val<T> extends AbstractParam<T> {
|
||||
final String getBindVariable(Context<?> ctx) {
|
||||
if (ctx.paramType() == NAMED || ctx.paramType() == NAMED_OR_INLINED) {
|
||||
int index = ctx.nextIndex();
|
||||
String prefix = StringUtils.defaultIfNull(ctx.settings().getRenderNamedParamPrefix(), ":");
|
||||
String prefix = defaultIfNull(ctx.settings().getRenderNamedParamPrefix(), ":");
|
||||
|
||||
if (StringUtils.isBlank(getParamName()))
|
||||
return prefix + index;
|
||||
|
||||
@ -75,11 +75,11 @@ public class DefaultCallableStatement extends DefaultPreparedStatement implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement getDelegate() {
|
||||
public CallableStatement getDelegate() throws SQLException {
|
||||
return getDelegateCallableStatement();
|
||||
}
|
||||
|
||||
public CallableStatement getDelegateCallableStatement() {
|
||||
public CallableStatement getDelegateCallableStatement() throws SQLException {
|
||||
return (CallableStatement) getDelegateStatement();
|
||||
}
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@ import java.sql.Statement;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A default JDBC PreparedStatement implementation delegating all JDBC 4.0 calls
|
||||
@ -81,12 +82,16 @@ public class DefaultPreparedStatement extends DefaultStatement implements Prepar
|
||||
super(delegate, creator);
|
||||
}
|
||||
|
||||
protected DefaultPreparedStatement(Statement delegate, Connection creator, Supplier<? extends SQLException> errorIfUnsupported) {
|
||||
super(delegate, creator, errorIfUnsupported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement getDelegate() {
|
||||
public PreparedStatement getDelegate() throws SQLException {
|
||||
return getDelegatePreparedStatement();
|
||||
}
|
||||
|
||||
public final PreparedStatement getDelegatePreparedStatement() {
|
||||
public final PreparedStatement getDelegatePreparedStatement() throws SQLException {
|
||||
return (PreparedStatement) getDelegateStatement();
|
||||
}
|
||||
|
||||
|
||||
@ -59,6 +59,7 @@ import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A default JDBC ResultSet implementation delegating all JDBC 4.0 calls to an
|
||||
@ -68,20 +69,29 @@ import java.util.Map;
|
||||
*/
|
||||
public class DefaultResultSet extends JDBC41ResultSet implements ResultSet {
|
||||
|
||||
private final ResultSet delegate;
|
||||
private final Statement creator;
|
||||
private final ResultSet delegate;
|
||||
private final Statement creator;
|
||||
private final Supplier<? extends SQLException> errorIfUnsupported;
|
||||
|
||||
public DefaultResultSet(ResultSet delegate) {
|
||||
this(delegate, null);
|
||||
this(delegate, null, null);
|
||||
}
|
||||
|
||||
public DefaultResultSet(ResultSet delegate, Statement creator) {
|
||||
this.delegate = delegate;
|
||||
this.creator = creator;
|
||||
this(delegate, creator, null);
|
||||
}
|
||||
|
||||
public ResultSet getDelegate() {
|
||||
return delegate;
|
||||
public DefaultResultSet(ResultSet delegate, Statement creator, Supplier<? extends SQLException> errorIfUnsupported) {
|
||||
this.delegate = delegate;
|
||||
this.creator = creator;
|
||||
this.errorIfUnsupported = errorIfUnsupported;
|
||||
}
|
||||
|
||||
public ResultSet getDelegate() throws SQLException {
|
||||
if (delegate != null || errorIfUnsupported == null)
|
||||
return delegate;
|
||||
else
|
||||
throw errorIfUnsupported.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -42,6 +42,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Statement;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A default JDBC Statement implementation delegating all JDBC 4.0 calls to an
|
||||
@ -51,24 +52,33 @@ import java.sql.Statement;
|
||||
*/
|
||||
public class DefaultStatement extends JDBC41Statement implements Statement {
|
||||
|
||||
private final Statement delegate;
|
||||
private final Connection creator;
|
||||
private final Statement delegate;
|
||||
private final Connection creator;
|
||||
private final Supplier<? extends SQLException> errorIfUnsupported;
|
||||
|
||||
public DefaultStatement(Statement delegate) {
|
||||
this(delegate, null);
|
||||
this(delegate, null, null);
|
||||
}
|
||||
|
||||
public DefaultStatement(Statement delegate, Connection creator) {
|
||||
this.delegate = delegate;
|
||||
this.creator = creator;
|
||||
this(delegate, creator, null);
|
||||
}
|
||||
|
||||
public Statement getDelegate() {
|
||||
public DefaultStatement(Statement delegate, Connection creator, Supplier<? extends SQLException> errorIfUnsupported) {
|
||||
this.delegate = delegate;
|
||||
this.creator = creator;
|
||||
this.errorIfUnsupported = errorIfUnsupported;
|
||||
}
|
||||
|
||||
public Statement getDelegate() throws SQLException {
|
||||
return getDelegateStatement();
|
||||
}
|
||||
|
||||
public Statement getDelegateStatement() {
|
||||
return delegate;
|
||||
public Statement getDelegateStatement() throws SQLException {
|
||||
if (delegate != null || errorIfUnsupported == null)
|
||||
return delegate;
|
||||
else
|
||||
throw errorIfUnsupported.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@ -69,12 +69,12 @@ This is set to "QUOTED" by default for backwards-compatibility.
|
||||
</element>
|
||||
|
||||
<element name="renderNamedParamPrefix" type="string" minOccurs="0" maxOccurs="1" default=":">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The prefix to use for named parameters.
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The prefix to use for named parameters in generated SQL.
|
||||
<p>
|
||||
Named parameter syntax defaults to <code>:name</code> (such as supported by Oracle, JPA, Spring), but
|
||||
vendor specific parameters may look differently. This flag can be used to determine the prefix to be
|
||||
used by named parameters, such as <code>@</code> for SQL Server's <code>@name</code> or <code>$</code>
|
||||
for PostgreSQL's <code>$name</code>.
|
||||
for PostgreSQL's <code>$name</code>, when generating SQL.
|
||||
<p>
|
||||
"Named indexed" parameters can be obtained in the same way by specifingy {@code ParamType#NAMED} and not
|
||||
providing a name to parameters, resulting in <code>:1</code> or <code>@1</code> or <code>$1</code>, etc.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
@ -568,7 +568,19 @@ jOOQ queries, for which no specific fetchSize value was specified.]]></jxb:javad
|
||||
<element name="parseTimestampFormat" type="string" minOccurs="0" maxOccurs="1" default="YYYY-MM-DD HH24:MI:SS.FF">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The timestamp format to use when parsing functions whose behaviour depends on some session date format, such as NLS_TIMESTAMP_FORMAT in Oracle]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
|
||||
<element name="parseNamedParamPrefix" type="string" minOccurs="0" maxOccurs="1" default=":">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The prefix to use for named parameters in parsed SQL.
|
||||
<p>
|
||||
Named parameter syntax defaults to <code>:name</code> (such as supported by Oracle, JPA, Spring), but
|
||||
vendor specific parameters may look differently. This flag can be used to determine the prefix to be
|
||||
used by named parameters, such as <code>@</code> for SQL Server's <code>@name</code> or <code>$</code>
|
||||
for PostgreSQL's <code>$name</code> when parsing SQL.
|
||||
<p>
|
||||
"Named indexed" parameters can be obtained in the same way by specifingy {@code ParamType#NAMED} and not
|
||||
providing a name to parameters, resulting in <code>:1</code> or <code>@1</code> or <code>$1</code>, etc.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="parseNameCase" type="jooq-runtime:ParseNameCase" minOccurs="0" maxOccurs="1" default="DEFAULT">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#7337] The default name case for parsed identifiers.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user