[#3000] Add Setting to enable MySQL backslash escaping

This commit is contained in:
Lukas Eder 2014-10-06 14:29:11 +02:00
parent 64306e5596
commit 426255e6fa
2 changed files with 53 additions and 23 deletions

View File

@ -60,10 +60,12 @@ import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
import static org.jooq.conf.BackslashEscaping.ON;
import static org.jooq.conf.ParamType.NAMED;
import static org.jooq.conf.ParamType.NAMED_OR_INLINED;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.using;
import static org.jooq.impl.Utils.settings;
import static org.jooq.tools.StringUtils.leftPad;
import java.math.BigDecimal;
@ -82,6 +84,7 @@ import org.jooq.RenderContext;
import org.jooq.SQLDialect;
import org.jooq.Schema;
import org.jooq.UDTRecord;
import org.jooq.conf.BackslashEscaping;
import org.jooq.tools.StringUtils;
import org.jooq.types.Interval;
@ -408,7 +411,7 @@ class Val<T> extends AbstractParam<T> {
// Interval extends Number, so let Interval come first!
else if (Interval.class.isAssignableFrom(type)) {
context.sql("'")
.sql(escape(val))
.sql(escape(val, context))
.sql("'");
}
@ -423,7 +426,7 @@ class Val<T> extends AbstractParam<T> {
// The SQLite JDBC driver does not implement the escape syntax
// [#1253] SQL Server and Sybase do not implement date literals
if (asList(SQLITE).contains(family)) {
context.sql("'").sql(escape(val)).sql("'");
context.sql("'").sql(escape(val, context)).sql("'");
}
/* [pro] xx
@ -432,23 +435,23 @@ class Val<T> extends AbstractParam<T> {
x
xxxx xx xxxxxxx xx xxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxx
x
xx [/pro] */
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
context.keyword("date('").sql(escape(val)).sql("')");
context.keyword("date('").sql(escape(val, context)).sql("')");
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
context.keyword("{d '").sql(val.toString()).sql("'}");
context.keyword("{d '").sql(escape(val, context)).sql("'}");
}
// Most dialects implement SQL standard date literals
else {
context.keyword("date '").sql(escape(val)).sql("'");
context.keyword("date '").sql(escape(val, context)).sql("'");
}
}
else if (type == Timestamp.class) {
@ -456,7 +459,7 @@ class Val<T> extends AbstractParam<T> {
// The SQLite JDBC driver does not implement the escape syntax
// [#1253] SQL Server and Sybase do not implement timestamp literals
if (asList(SQLITE).contains(family)) {
context.sql("'").sql(escape(val)).sql("'");
context.sql("'").sql(escape(val, context)).sql("'");
}
/* [pro] xx
@ -465,28 +468,28 @@ class Val<T> extends AbstractParam<T> {
x
xxxx xx xxxxxxx xx xxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxxxxxxx
x
xx [/pro] */
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
context.keyword("timestamp('").sql(escape(val)).sql("')");
context.keyword("timestamp('").sql(escape(val, context)).sql("')");
}
// CUBRID timestamps have no fractional seconds
else if (family == CUBRID) {
context.keyword("datetime '").sql(escape(val)).sql("'");
context.keyword("datetime '").sql(escape(val, context)).sql("'");
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
context.keyword("{ts '").sql(val.toString()).sql("'}");
context.keyword("{ts '").sql(escape(val, context)).sql("'}");
}
// Most dialects implement SQL standard timestamp literals
else {
context.keyword("timestamp '").sql(escape(val)).sql("'");
context.keyword("timestamp '").sql(escape(val, context)).sql("'");
}
}
else if (type == Time.class) {
@ -499,33 +502,33 @@ class Val<T> extends AbstractParam<T> {
/* [pro] xx
xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxx
x
xxxx xx xxxxxxx xx xxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxxxxx
x
xx [/pro] */
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
context.keyword("time").sql("('").sql(escape(val)).sql("')");
context.keyword("time").sql("('").sql(escape(val, context)).sql("')");
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
context.keyword("{t '").sql(val.toString()).sql("'}");
context.keyword("{t '").sql(escape(val, context)).sql("'}");
}
/* [pro] xx
xx xxxxxxx xxxxxx xxxxxxx xxxx xxxx xxxxxxxx
xxxx xx xxxxxxx xx xxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx xxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx
x
xx [/pro] */
// Most dialects implement SQL standard time literals
else {
context.keyword("time").sql(" '").sql(escape(val)).sql("'");
context.keyword("time").sql(" '").sql(escape(val, context)).sql("'");
}
}
else if (type.isArray()) {
@ -566,7 +569,7 @@ class Val<T> extends AbstractParam<T> {
}
/* [pro] xx
xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx
xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx xxxxxx
x
xx [/pro] */
else if (EnumType.class.isAssignableFrom(type)) {
@ -589,7 +592,7 @@ class Val<T> extends AbstractParam<T> {
// - UUID
else {
context.sql("'")
.sql(escape(val), true)
.sql(escape(val, context), true)
.sql("'");
}
}
@ -636,10 +639,16 @@ class Val<T> extends AbstractParam<T> {
}
/**
* Escape a string literal by replacing <code>'</code> by <code>''</code>
* Escape a string literal by replacing <code>'</code> by <code>''</code>, and possibly also backslashes.
*/
private final String escape(Object val) {
return val.toString().replace("'", "''");
private final String escape(Object val, Context<?> context) {
BackslashEscaping escaping = settings(context.configuration()).getBackslashEscaping();
String result = val.toString();
if (escaping == ON)
result = result.replace("\\", "\\\\");
return result.replace("'", "''");
}
final void bind0(BindContext context) {

View File

@ -33,6 +33,9 @@
Oracle 11g (and potentially, other databases too) implements scalar subquery caching. With this flag
set to true, users can automatically profit from this feature in all SQL statements. -->
<element name="renderScalarSubqueriesForStoredFunctions" type="boolean" minOccurs="0" maxOccurs="1" default="false"/>
<!-- Whether string literals should be escaped with backslash. -->
<element name="backslashEscaping" type="jooq-runtime:BackslashEscaping" minOccurs="0" maxOccurs="1" default="OFF"/>
<!-- Whether rendered bind values should be rendered as:
@ -194,4 +197,22 @@
<enumeration value="UPPER"/>
</restriction>
</simpleType>
<simpleType name="BackslashEscaping">
<restriction base="string">
<!-- Use the JDBC connection's setting for backslash escaping. In most databases, this
is the same as OFF. In MySQL and MariaDB, the actual setting is extracted.
This is not yet implemented, as the JDBC connection might not be available to the renderer
<enumeration value="AUTO"/>
-->
<!-- Always escape backslashes. -->
<enumeration value="ON"/>
<!-- Never escape backslashes. -->
<enumeration value="OFF"/>
</restriction>
</simpleType>
</schema>