* Inlining abstraction
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private final void toSQL(BindingSQLContext<U> ctx, Object val) {
SQLDialect family = ctx.family();
RenderContext render = ctx.render();
if (render.paramType() == INLINED) {
// [#2223] Some type-casts in this section may seem unnecessary, e.g.
// ((Boolean) val).toString(). They have been put in place to avoid
// accidental type confusions where type != val.getClass(), and thus
// SQL injection may occur
if (val == null) {
render.keyword("null");
}
else if (type == Boolean.class) {
// [#1153] Some dialects don't support boolean literals TRUE and FALSE
if (asList(FIREBIRD, SQLITE).contains(family)) {
render.sql(((Boolean) val) ? "1" : "0");
}
/* [pro] xx
xxxx xx xxxxxxx xx xxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxx xxxx x xxxxx x xxxxxxx
x
xx [/pro] */
else {
render.keyword(((Boolean) val).toString());
}
}
// [#1154] Binary data cannot always be inlined
else if (type == byte[].class) {
byte[] binary = (byte[]) val;
if (asList().contains(family)) {
render.sql("0x")
.sql(convertBytesToHex(binary));
}
/* [pro] xx
xxxx xx xxxxxxx xx xxxx x
xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxx
x
xx [/pro] */
else if (asList(DERBY, H2, HSQLDB, MARIADB, MYSQL, SQLITE).contains(family)) {
render.sql("X'")
.sql(convertBytesToHex(binary))
.sql("'");
}
else if (asList().contains(family)) {
render.keyword("hextoraw('")
.sql(convertBytesToHex(binary))
.sql("')");
}
else if (family == POSTGRES) {
render.sql("E'")
.sql(convertBytesToPostgresOctal(binary))
.keyword("'::bytea");
}
// This default behaviour is used in debug logging for dialects
// that do not support inlining binary data
else {
render.sql("X'")
.sql(convertBytesToHex(binary))
.sql("'");
}
}
// Interval extends Number, so let Interval come first!
else if (Interval.class.isAssignableFrom(type)) {
render.sql("'")
.sql(escape(val, render))
.sql("'");
}
else if (Number.class.isAssignableFrom(type)) {
render.sql(((Number) val).toString());
}
// [#1156] Date/Time data types should be inlined using JDBC
// escape syntax
else if (type == Date.class) {
// 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)) {
render.sql("'").sql(escape(val, render)).sql("'");
}
/* [pro] xx
xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
x
xxxx xx xxxxxxx xx xxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxx
x
xx [/pro] */
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
render.keyword("date('").sql(escape(val, render)).sql("')");
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
render.keyword("{d '").sql(escape(val, render)).sql("'}");
}
// Most dialects implement SQL standard date literals
else {
render.keyword("date '").sql(escape(val, render)).sql("'");
}
}
else if (type == Timestamp.class) {
// 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)) {
render.sql("'").sql(escape(val, render)).sql("'");
}
/* [pro] xx
xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
x
xxxx xx xxxxxxx xx xxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxxxxxxx
x
xx [/pro] */
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
render.keyword("timestamp('").sql(escape(val, render)).sql("')");
}
// CUBRID timestamps have no fractional seconds
else if (family == CUBRID) {
render.keyword("datetime '").sql(escape(val, render)).sql("'");
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
render.keyword("{ts '").sql(escape(val, render)).sql("'}");
}
// Most dialects implement SQL standard timestamp literals
else {
render.keyword("timestamp '").sql(escape(val, render)).sql("'");
}
}
else if (type == Time.class) {
// The SQLite JDBC driver does not implement the escape syntax
// [#1253] SQL Server and Sybase do not implement time literals
if (asList(SQLITE).contains(family)) {
render.sql("'").sql(new SimpleDateFormat("HH:mm:ss").format((Time) val)).sql("'");
}
/* [pro] xx
xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
xxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx
x
xxxx xx xxxxxxx xx xxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxxxxx
x
xx [/pro] */
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
render.keyword("time").sql("('").sql(escape(val, render)).sql("')");
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
render.keyword("{t '").sql(escape(val, render)).sql("'}");
}
/* [pro] xx
xx xxxxxxx xxxxxx xxxxxxx xxxx xxxx xxxxxxxx
xxxx xx xxxxxxx xx xxxxxxx x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx xxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
x
xx [/pro] */
// Most dialects implement SQL standard time literals
else {
render.keyword("time").sql(" '").sql(escape(val, render)).sql("'");
}
}
else if (type.isArray()) {
String separator = "";
// H2 renders arrays as rows
if (family == H2) {
render.sql("(");
for (Object o : ((Object[]) val)) {
render.sql(separator);
new DefaultBinding<Object, Object>(new IdentityConverter(type.getComponentType()), isLob).sql(new DefaultBindingSQLContext<Object>(ctx.configuration(), ctx.render(), o));
separator = ", ";
}
render.sql(")");
}
// By default, render HSQLDB / POSTGRES syntax
else {
render.keyword("ARRAY");
render.sql("[");
for (Object o : ((Object[]) val)) {
render.sql(separator);
new DefaultBinding<Object, Object>(new IdentityConverter(type.getComponentType()), isLob).sql(new DefaultBindingSQLContext<Object>(ctx.configuration(), ctx.render(), o));
separator = ", ";
}
render.sql("]");
// [#3214] Some PostgreSQL array type literals need explicit casting
if (family == POSTGRES && EnumType.class.isAssignableFrom(type.getComponentType())) {
render.sql("::")
.keyword(DefaultDataType.getDataType(family, type).getCastTypeName(render.configuration()));
}
}
}
/* [pro] xx
xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
xxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxx
x
xx [/pro] */
else if (EnumType.class.isAssignableFrom(type)) {
String literal = ((EnumType) val).getLiteral();
if (literal == null) {
new DefaultBinding<Object, Object>(new IdentityConverter(String.class), isLob).sql(new DefaultBindingSQLContext<Object>(ctx.configuration(), ctx.render(), literal));
}
else {
new DefaultBinding<Object, Object>(new IdentityConverter(String.class), isLob).sql(new DefaultBindingSQLContext<Object>(ctx.configuration(), ctx.render(), literal));
}
}
else if (UDTRecord.class.isAssignableFrom(type)) {
render.sql("[UDT]");
}
// Known fall-through types:
// - Blob, Clob (both not supported by jOOQ)
// - String
// - UUID
else {
render.sql("'")
.sql(escape(val, render), true)
.sql("'");
}
}
// In Postgres, some additional casting must be done in some cases...
else if (family == SQLDialect.POSTGRES) {
// Postgres needs explicit casting for array types
if (type.isArray() && byte[].class != type) {
render.sql(getBindVariable(render));
render.sql("::");
render.keyword(DefaultDataType.getDataType(family, type).getCastTypeName(render.configuration()));
}
// ... and also for enum types
else if (EnumType.class.isAssignableFrom(type)) {
render.sql(getBindVariable(render));
// [#968] Don't cast "synthetic" enum types (note, val can be null!)
EnumType e = (EnumType) type.getEnumConstants()[0];
Schema schema = e.getSchema();
if (schema != null) {
render.sql("::");
schema = using(render.configuration()).map(schema);
if (schema != null && TRUE.equals(render.configuration().settings().isRenderSchema())) {
render.visit(schema);
render.sql(".");
}
render.visit(name(e.getName()));
}
}
else {
render.sql(getBindVariable(render));
}
}
else {
render.sql(getBindVariable(render));
}
}