[#5764] Add support for inlining SQL Server table valued parameters in SQL

This commit is contained in:
lukaseder 2017-07-06 15:23:35 +02:00
parent a2670855c5
commit 50db69abbd
10 changed files with 136 additions and 26 deletions

View File

@ -86,7 +86,7 @@ import org.jooq.tools.StopWatchListener;
* <h3>Types composing its state:</h3>
* <ul>
* <li>{@link #dialect()}: The {@link SQLDialect} that defines the underlying
* database's behaviour when generating SQL syntax, or binding variables, or
* database's behaviour when generating SQL syntax, or bind variables, or
* when executing the query</li>
* <li>{@link #settings()}: The {@link Settings} that define general jOOQ
* behaviour</li>

View File

@ -2254,7 +2254,7 @@ public interface DSLContext extends Scope , AutoCloseable {
/**
* Create a new query holding plain SQL.
* <p>
* There must not be any binding variables contained in the SQL
* There must not be any bind variables contained in the SQL
* <p>
* Use this method, when you want to take advantage of the many ways to
* fetch results in jOOQ, using {@link ResultQuery}. Some examples:
@ -2300,7 +2300,7 @@ public interface DSLContext extends Scope , AutoCloseable {
/**
* Create a new query holding plain SQL.
* <p>
* There must not be any binding variables contained in the SQL
* There must not be any bind variables contained in the SQL
* <p>
* Use this method, when you want to take advantage of the many ways to
* fetch results in jOOQ, using {@link ResultQuery}. Some examples:

View File

@ -425,7 +425,7 @@ public interface ExecuteListener extends EventListener, Serializable {
void prepareEnd(ExecuteContext ctx);
/**
* Called before binding variables to the <code>PreparedStatement</code>
* Called before bind variables to the <code>PreparedStatement</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
@ -468,7 +468,7 @@ public interface ExecuteListener extends EventListener, Serializable {
void bindStart(ExecuteContext ctx);
/**
* Called after binding variables to the <code>PreparedStatement</code>
* Called after bind variables to the <code>PreparedStatement</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>

View File

@ -449,14 +449,12 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query {
static class Rendered {
String sql;
QueryPartList<Param<?>> bindValues;
int skipUpdateCounts;
Rendered(String sql) {
this(sql, null);
}
Rendered(String sql, QueryPartList<Param<?>> bindValues) {
Rendered(String sql, QueryPartList<Param<?>> bindValues, int skipUpdateCounts) {
this.sql = sql;
this.bindValues = bindValues;
this.skipUpdateCounts = skipUpdateCounts;
}
@Override
@ -471,22 +469,24 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query {
// [#3542] [#4977] Some dialects do not support bind values in DDL statements
if (ctx.type() == DDL) {
ctx.data(DATA_FORCE_STATIC_STATEMENT, true);
result = new Rendered(getSQL(INLINED));
DefaultRenderContext render = new DefaultRenderContext(configuration);
result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts());
}
else if (executePreparedStatements(configuration().settings())) {
try {
DefaultRenderContext render = new DefaultRenderContext(configuration);
render.data(DATA_COUNT_BIND_VALUES, true);
render.visit(this);
result = new Rendered(render.render(), render.bindValues());
result = new Rendered(render.visit(this).render(), render.bindValues(), render.peekSkipUpdateCounts());
}
catch (DefaultRenderContext.ForceInlineSignal e) {
ctx.data(DATA_FORCE_STATIC_STATEMENT, true);
result = new Rendered(getSQL(INLINED));
DefaultRenderContext render = new DefaultRenderContext(configuration);
result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts());
}
}
else {
result = new Rendered(getSQL(INLINED));
DefaultRenderContext render = new DefaultRenderContext(configuration);
result = new Rendered(render.paramType(INLINED).visit(this).render(), null, render.peekSkipUpdateCounts());
}

View File

@ -256,7 +256,7 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
if (ctx.family() == POSTGRES && f != 0 && ctx.connection().getAutoCommit())
log.info("Fetch Size", "A fetch size of " + f + " was set on a auto-commit PostgreSQL connection, which is not recommended. See http://jdbc.postgresql.org/documentation/head/query.html#query-with-cursor");
executeStatementAndGetFirstResultSet(ctx);
executeStatementAndGetFirstResultSet(ctx, rendered.skipUpdateCounts);
listener.executeEnd(ctx);
// Fetch a single result set

View File

@ -502,7 +502,7 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
private final void execute0(ExecuteContext ctx, ExecuteListener listener) throws SQLException {
try {
listener.executeStart(ctx);
executeStatementAndGetFirstResultSet(ctx);
executeStatementAndGetFirstResultSet(ctx, 0);
listener.executeEnd(ctx);
}

View File

@ -85,6 +85,47 @@ package org.jooq.impl;

View File

@ -9109,7 +9109,7 @@ public class DSL {
* <p>
* A plain SQL <code>QueryPart</code> is a <code>QueryPart</code> that can
* contain user-defined plain SQL, because sometimes it is easier to express
* things directly in SQL. There must be as many binding variables contained
* things directly in SQL. There must be as many bind variables contained
* in the SQL, as passed in the bindings parameter
* <p>
* This overload takes a set of bind value arguments which are replaced our
@ -9192,7 +9192,7 @@ public class DSL {
* <p>
* A plain SQL <code>QueryPart</code> is a <code>QueryPart</code> that can
* contain user-defined plain SQL, because sometimes it is easier to express
* things directly in SQL. There must be as many binding variables contained
* things directly in SQL. There must be as many bind variables contained
* in the SQL, as passed in the bindings parameter
* <p>
* <b>NOTE</b>: When inserting plain SQL into jOOQ objects, you must
@ -9328,7 +9328,7 @@ public class DSL {
/**
* Create a new query holding plain SQL.
* <p>
* There must not be any binding variables contained in the SQL
* There must not be any bind variables contained in the SQL
* <p>
* Use this method, when you want to take advantage of the many ways to
* fetch results in jOOQ, using {@link ResultQuery}. Some examples:
@ -9376,7 +9376,7 @@ public class DSL {
/**
* Create a new query holding plain SQL.
* <p>
* There must not be any binding variables contained in the SQL
* There must not be any bind variables contained in the SQL
* <p>
* Use this method, when you want to take advantage of the many ways to
* fetch results in jOOQ, using {@link ResultQuery}. Some examples:
@ -9568,7 +9568,7 @@ public class DSL {
* A plain SQL table is a table that can contain user-defined plain SQL,
* because sometimes it is easier to express things directly in SQL, for
* instance complex, but static subqueries or tables from different schemas.
* There must be as many binding variables contained in the SQL, as passed
* There must be as many bind variables contained in the SQL, as passed
* in the bindings parameter
* <p>
* Example
@ -10144,7 +10144,7 @@ public class DSL {
/**
* Create a new condition holding plain SQL.
* <p>
* There must not be any binding variables contained in the SQL.
* There must not be any bind variables contained in the SQL.
* <p>
* Example:
* <p>
@ -10169,7 +10169,7 @@ public class DSL {
/**
* Create a new condition holding plain SQL.
* <p>
* There must not be any binding variables contained in the SQL.
* There must not be any bind variables contained in the SQL.
* <p>
* Example:
* <p>
@ -10194,7 +10194,7 @@ public class DSL {
/**
* Create a new condition holding plain SQL.
* <p>
* There must be as many binding variables contained in the SQL, as passed
* There must be as many bind variables contained in the SQL, as passed
* in the bindings parameter
* <p>
* Example:

View File

@ -91,6 +91,7 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
private int printMargin = 80;
private boolean separator;
private boolean newline;
private int skipUpdateCounts;
// [#1632] Cached values from Settings
RenderKeywordStyle cachedRenderKeywordStyle;
@ -143,6 +144,14 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
// RenderContext API
// ------------------------------------------------------------------------
final int peekSkipUpdateCounts() {
return skipUpdateCounts;
}
final void incrementSkipUpdateCounts() {
skipUpdateCounts++;
}
@Override
public final String peekAlias() {
return "alias_" + (alias + 1);

View File

@ -47,6 +47,7 @@ import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
import static org.jooq.conf.BackslashEscaping.DEFAULT;
import static org.jooq.conf.BackslashEscaping.ON;
import static org.jooq.conf.ParamType.INLINED;
@ -433,6 +434,25 @@ final class Tools {
* list's parentheses).
*/
DATA_INSERT_SELECT_WITHOUT_INSERT_COLUMN_LIST,
}
/**
@ -3073,7 +3093,7 @@ final class Tools {
* [#5666] Handle the complexity of each dialect's understanding of
* correctly calling {@link Statement#execute()}.
*/
static final void executeStatementAndGetFirstResultSet(ExecuteContext ctx) throws SQLException {
static final void executeStatementAndGetFirstResultSet(ExecuteContext ctx, int skipUpdateCounts) throws SQLException {
PreparedStatement stmt = ctx.statement();
@ -3100,6 +3120,39 @@ final class Tools {
@ -3831,4 +3884,11 @@ final class Tools {
else
return null;
}
static final void increment(Map<Object, Object> data, DataKey key) {
Integer updateCounts = (Integer) data.get(key);
if (updateCounts == null)
updateCounts = 0;
data.put(key, updateCounts + 1);
}
}