[#4985] Utils.executeImmediate() doesn't work when inlined SQL contains apostrophes

This commit is contained in:
lukaseder 2016-01-24 11:56:42 +01:00
parent e5463bedc2
commit 381a07686f
4 changed files with 63 additions and 18 deletions

View File

@ -58,7 +58,7 @@ import org.jooq.exception.DataAccessException;
public interface Context<C extends Context<C>> extends Scope {
// ------------------------------------------------------------------------
// General methods
// Methods specifying the scope of the SQL being rendered
// ------------------------------------------------------------------------
/**
@ -90,7 +90,7 @@ public interface Context<C extends Context<C>> extends Scope {
boolean declareFields();
/**
* Set the new context value for {@link #declareFields()}
* Set the new context value for {@link #declareFields()}.
*/
C declareFields(boolean declareFields);
@ -102,7 +102,7 @@ public interface Context<C extends Context<C>> extends Scope {
boolean declareTables();
/**
* Set the new context value for {@link #declareTables()}
* Set the new context value for {@link #declareTables()}.
*/
C declareTables(boolean declareTables);
@ -125,7 +125,7 @@ public interface Context<C extends Context<C>> extends Scope {
boolean declareWindows();
/**
* Set the new context value for {@link #declareWindows()}
* Set the new context value for {@link #declareWindows()}.
*/
C declareWindows(boolean declareWindows);
@ -137,20 +137,30 @@ public interface Context<C extends Context<C>> extends Scope {
boolean declareCTE();
/**
* Set the new context value for {@link #declareCTE()}
* Set the new context value for {@link #declareCTE()}.
*/
C declareCTE(boolean declareCTE);
/**
* Whether the current context is rendering a sub-query (nested query)
* Whether the current context is rendering a sub-query (nested query).
*/
boolean subquery();
/**
* Set the new context value for {@link #subquery()}
* Set the new context value for {@link #subquery()}.
*/
C subquery(boolean subquery);
/**
* whether the current context is rendering a string literal.
*/
boolean stringLiteral();
/**
* Set the new context value for {@link #stringLiteral()}.
*/
C stringLiteral(boolean stringLiteral);
/**
* Get the next bind index. This increments an internal counter. This is
* relevant for two use-cases:
@ -166,7 +176,7 @@ public interface Context<C extends Context<C>> extends Scope {
/**
* Peek the next bind index. This won't increment the internal counter,
* unlike {@link #nextIndex()}
* unlike {@link #nextIndex()}.
*/
int peekIndex();

View File

@ -83,6 +83,8 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
boolean declareWindows;
boolean declareCTE;
boolean subquery;
int stringLiteral;
String stringLiteralEscapedApos = "'";
int index;
// [#2665] VisitListener API
@ -466,6 +468,25 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
return (C) this;
}
@Override
public final boolean stringLiteral() {
return stringLiteral > 0;
}
@Override
public final C stringLiteral(boolean s) {
if (s) {
stringLiteral++;
stringLiteralEscapedApos = stringLiteralEscapedApos + stringLiteralEscapedApos;
}
else {
stringLiteral--;
stringLiteralEscapedApos = stringLiteralEscapedApos.substring(0, stringLiteralEscapedApos.length() / 2);
}
return (C) this;
}
@Override
public final int nextIndex() {
return ++index;

View File

@ -186,13 +186,13 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
@Override
public final RenderContext sql(String s, boolean literal) {
if (literal) {
sql.append(s);
}
else {
sql.append(NEWLINE.matcher(s).replaceAll("$0" + indentation()));
}
if (!literal)
s = NEWLINE.matcher(s).replaceAll("$0" + indentation());
if (stringLiteral())
s = StringUtils.replace(s, "'", stringLiteralEscapedApos);
sql.append(s);
return this;
}
@ -200,6 +200,10 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
@Override
public final RenderContext sql(char c) {
sql.append(c);
if (c == '\'' && stringLiteral())
sql.append(c);
return this;
}
@ -285,7 +289,7 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
return this;
}
private Deque<Integer> indentLock() {
private final Deque<Integer> indentLock() {
if (indentLock == null) {
indentLock = new ArrayDeque<Integer>();
}

View File

@ -2786,7 +2786,6 @@ final class Utils {
* <code>BEGIN EXECUTE IMMEDIATE '...' EXCEPTION WHEN ... END;</code>, if
* <code>IF EXISTS</code> is not supported.
*/
@SuppressWarnings("unused")
static final void executeImmediateBegin(Context<?> ctx, DDLStatementType type) {
switch (ctx.family()) {
@ -2824,6 +2823,10 @@ final class Utils {
@ -2833,7 +2836,7 @@ final class Utils {
ctx.keyword("execute block").formatSeparator()
.keyword("as").formatSeparator()
.keyword("begin").formatIndentStart().formatSeparator()
.keyword("execute statement").sql(" '");
.keyword("execute statement").sql(" '").stringLiteral(true).formatIndentStart().formatSeparator();
break;
}
@ -2849,6 +2852,8 @@ final class Utils {
* <code>IF EXISTS</code> is not supported.
*/
static final void executeImmediateEnd(Context<?> ctx, DDLStatementType type) {
boolean drop = asList(DROP_INDEX, DROP_SEQUENCE, DROP_TABLE, DROP_VIEW).contains(type);
switch (ctx.family()) {
@ -2896,6 +2901,11 @@ final class Utils {
@ -2903,7 +2913,7 @@ final class Utils {
case FIREBIRD: {
ctx.sql("';").formatSeparator()
ctx.formatIndentEnd().formatSeparator().stringLiteral(false).sql("';").formatSeparator()
.keyword("when").sql(" sqlcode -607 ").keyword("do").formatIndentStart().formatSeparator()
.keyword("begin end").formatIndentEnd().formatIndentEnd().formatSeparator()
.keyword("end");