use of org.jooq.RenderContext.CastMode in project jOOQ by jOOQ.
the class Limit method accept.
@Override
public final void accept(Context<?> ctx) {
ParamType paramType = ctx.paramType();
CastMode castMode = ctx.castMode();
switch(ctx.dialect()) {
// -------------------------------------------
case CUBRID:
{
ctx.castMode(NEVER).formatSeparator().visit(K_LIMIT).sql(' ').visit(offsetOrZero).sql(", ").visit(limitOrMax).castMode(castMode);
break;
}
case DERBY:
case FIREBIRD:
case H2:
case MARIADB:
case POSTGRES:
{
// OFFSET .. FETCH syntax on H2 only when strictly needed
if (ctx.family() == H2 && !withTies() && !percent())
acceptDefault(ctx, castMode);
else
acceptStandard(ctx, castMode);
break;
}
case MYSQL:
case SQLITE:
{
acceptDefaultLimitMandatory(ctx, castMode);
break;
}
default:
{
acceptDefault(ctx, castMode);
break;
}
}
}
use of org.jooq.RenderContext.CastMode in project jOOQ by jOOQ.
the class Tools method renderAndBind.
/**
* Render and bind a list of {@link QueryPart} to plain SQL
* <p>
* This will perform two actions:
* <ul>
* <li>When {@link RenderContext} is provided, it will render plain SQL to
* the context, substituting {numbered placeholders} and bind values if
* {@link RenderContext#inline()} is set</li>
* <li>When {@link BindContext} is provided, it will bind the list of
* {@link QueryPart} according to the {numbered placeholders} and bind
* values in the sql string</li>
* </ul>
*/
@SuppressWarnings("null")
static final void renderAndBind(Context<?> ctx, String sql, List<QueryPart> substitutes) {
RenderContext render = ctx instanceof RenderContext ? (RenderContext) ctx : null;
BindContext bind = ctx instanceof BindContext ? (BindContext) ctx : null;
int substituteIndex = 0;
char[] sqlChars = sql.toCharArray();
// [#1593] Create a dummy renderer if we're in bind mode
if (render == null)
render = new DefaultRenderContext(bind.configuration());
SQLDialect family = render.family();
boolean mysql = SUPPORTS_HASH_COMMENT_SYNTAX.contains(render.dialect());
char[][][] quotes = QUOTES.get(family);
// [#3630] Depending on this setting, we need to consider backslashes as escape characters within string literals.
boolean needsBackslashEscaping = needsBackslashEscaping(ctx.configuration());
characterLoop: for (int i = 0; i < sqlChars.length; i++) {
// where id = ?
if (peek(sqlChars, i, TOKEN_SINGLE_LINE_COMMENT) || peek(sqlChars, i, TOKEN_SINGLE_LINE_COMMENT_C) || // http://bugs.mysql.com/bug.php?id=76623
(mysql && peek(sqlChars, i, TOKEN_HASH))) {
// Consume the complete comment
for (; i < sqlChars.length && sqlChars[i] != '\r' && sqlChars[i] != '\n'; render.sql(sqlChars[i++])) ;
// Consume the newline character
if (i < sqlChars.length)
render.sql(sqlChars[i]);
} else // from t_book where id = ?
if (peek(sqlChars, i, TOKEN_MULTI_LINE_COMMENT_OPEN)) {
int nestedMultilineCommentLevel = 1;
// Consume the complete comment
do {
render.sql(sqlChars[i++]);
if (peek(sqlChars, i, TOKEN_MULTI_LINE_COMMENT_OPEN))
nestedMultilineCommentLevel++;
else if (peek(sqlChars, i, TOKEN_MULTI_LINE_COMMENT_CLOSE))
nestedMultilineCommentLevel--;
} while (nestedMultilineCommentLevel != 0);
// Consume the comment delimiter
render.sql(sqlChars[i]);
} else // insert into x values ('Hello? Anybody out there?');
if (sqlChars[i] == '\'') {
// Consume the initial string literal delimiter
render.sql(sqlChars[i++]);
// Consume the whole string literal
for (; ; ) {
// of some vendor specific comment syntax
if (i >= sqlChars.length)
break characterLoop;
else // [#3000] [#3630] Consume backslash-escaped characters if needed
if (sqlChars[i] == '\\' && needsBackslashEscaping)
render.sql(sqlChars[i++]);
else // Consume an escaped apostrophe
if (peek(sqlChars, i, TOKEN_ESCAPED_APOS))
render.sql(sqlChars[i++]);
else // Break on the terminal string literal delimiter
if (peek(sqlChars, i, TOKEN_APOS))
break;
// Consume string literal content
render.sql(sqlChars[i++]);
}
// Consume the terminal string literal delimiter
render.sql(sqlChars[i]);
} else // [#6704] PostgreSQL supports additional quoted string literals, which we must skip: E'...'
if ((sqlChars[i] == 'e' || sqlChars[i] == 'E') && SUPPORT_POSTGRES_LITERALS.contains(ctx.dialect()) && i + 1 < sqlChars.length && sqlChars[i + 1] == '\'') {
// Consume the initial string literal delimiters
render.sql(sqlChars[i++]);
render.sql(sqlChars[i++]);
// Consume the whole string literal
for (; ; ) {
// [#3000] [#3630] Consume backslash-escaped characters if needed
if (sqlChars[i] == '\\')
render.sql(sqlChars[i++]);
else // Consume an escaped apostrophe
if (peek(sqlChars, i, TOKEN_ESCAPED_APOS))
render.sql(sqlChars[i++]);
else // Break on the terminal string literal delimiter
if (peek(sqlChars, i, TOKEN_APOS))
break;
// Consume string literal content
render.sql(sqlChars[i++]);
}
// Consume the terminal string literal delimiter
render.sql(sqlChars[i]);
} else // update x set v = "Column Name with a ? (question mark)"
if (peekAny(sqlChars, i, quotes[QUOTE_START_DELIMITER])) {
// Main identifier delimiter or alternative one?
int delimiter = 0;
for (int d = 0; d < quotes[QUOTE_START_DELIMITER].length; d++) {
if (peek(sqlChars, i, quotes[QUOTE_START_DELIMITER][d])) {
delimiter = d;
break;
}
}
// Consume the initial identifier delimiter
for (int d = 0; d < quotes[QUOTE_START_DELIMITER][delimiter].length; d++) render.sql(sqlChars[i++]);
// Consume the whole identifier
identifierLoop: for (; ; ) {
// of some vendor specific comment syntax
if (i >= sqlChars.length)
break characterLoop;
else // Consume an escaped quote
if (peek(sqlChars, i, quotes[QUOTE_END_DELIMITER_ESCAPED][delimiter])) {
for (int d = 0; d < quotes[QUOTE_END_DELIMITER_ESCAPED][delimiter].length; d++) render.sql(sqlChars[i++]);
continue identifierLoop;
} else // Break on the terminal identifier delimiter
if (peek(sqlChars, i, quotes[QUOTE_END_DELIMITER][delimiter]))
break identifierLoop;
// Consume identifier content
render.sql(sqlChars[i++]);
}
// Consume the terminal identifier delimiter
for (int d = 0; d < quotes[QUOTE_END_DELIMITER][delimiter].length; d++) {
if (d > 0)
i++;
render.sql(sqlChars[i]);
}
} else // Inline bind variables only outside of string literals
if (substituteIndex < substitutes.size() && ((sqlChars[i] == '?') || // Watch out for the PostgreSQL cast operator ::
(sqlChars[i] == ':' && i + 1 < sqlChars.length && isJavaIdentifierPart(sqlChars[i + 1]) && (i - 1 < 0 || sqlChars[i - 1] != ':')))) {
// [#5307] Consume PostgreSQL style operators. These aren't bind variables!
if (sqlChars[i] == '?' && i + 1 < sqlChars.length && SUPPORT_NON_BIND_VARIABLE_SUFFIXES.contains(ctx.dialect())) {
nonBindSuffixLoop: for (char[] candidate : NON_BIND_VARIABLE_SUFFIXES) {
if (peek(sqlChars, i + 1, candidate)) {
for (char[] exclude : BIND_VARIABLE_SUFFIXES) if (peek(sqlChars, i + 1, exclude))
continue nonBindSuffixLoop;
for (int j = i; i - j <= candidate.length; i++) render.sql(sqlChars[i]);
render.sql(sqlChars[i]);
continue characterLoop;
}
}
}
// [#4131] Consume the named bind variable
if (sqlChars[i] == ':')
while (i + 1 < sqlChars.length && isJavaIdentifierPart(sqlChars[i + 1])) i++;
QueryPart substitute = substitutes.get(substituteIndex++);
if (render.paramType() == INLINED || render.paramType() == NAMED || render.paramType() == NAMED_OR_INLINED) {
render.visit(substitute);
} else {
CastMode previous = render.castMode();
render.castMode(CastMode.NEVER).visit(substitute).castMode(previous);
}
if (bind != null)
bind.visit(substitute);
} else // [#1432] Inline substitues for {numbered placeholders} outside of string literals
if (sqlChars[i] == '{') {
// [#1461] Be careful not to match any JDBC escape syntax
if (peekAny(sqlChars, i, JDBC_ESCAPE_PREFIXES, true)) {
render.sql(sqlChars[i]);
} else // Consume the whole token
{
int start = ++i;
for (; i < sqlChars.length && sqlChars[i] != '}'; i++) ;
int end = i;
// Try getting the {numbered placeholder}
Integer index = Ints.tryParse(sql, start, end);
if (index != null) {
if (index < 0 || index >= substitutes.size())
throw new TemplatingException("No substitute QueryPart provided for placeholder {" + index + "} in plain SQL template: " + sql);
QueryPart substitute = substitutes.get(index);
render.visit(substitute);
if (bind != null)
bind.visit(substitute);
} else {
// Then we're dealing with a {keyword}
render.visit(DSL.keyword(sql.substring(start, end)));
}
}
} else // Any other character
{
render.sql(sqlChars[i]);
}
}
}
use of org.jooq.RenderContext.CastMode in project jOOQ by jOOQ.
the class AbstractContext method visit0.
// ------------------------------------------------------------------------
// XXX Context API
// ------------------------------------------------------------------------
private final C visit0(QueryPart part) {
if (part != null) {
QueryPartInternal internal = (QueryPartInternal) part;
// We're declaring fields, but "part" does not declare fields
if (declareFields() && !internal.declaresFields()) {
boolean aliases = declareAliases();
declareFields(false);
visit0(internal);
declareFields(true);
declareAliases(aliases);
} else // We're declaring tables, but "part" does not declare tables
if (declareTables() && !internal.declaresTables()) {
boolean aliases = declareAliases();
declareTables(false);
visit0(internal);
declareTables(true);
declareAliases(aliases);
} else // We're declaring windows, but "part" does not declare windows
if (declareWindows() && !internal.declaresWindows()) {
declareWindows(false);
visit0(internal);
declareWindows(true);
} else // We're declaring cte, but "part" does not declare cte
if (declareCTE() && !internal.declaresCTE()) {
declareCTE(false);
visit0(internal);
declareCTE(true);
} else if (!castModeOverride && castMode() != CastMode.DEFAULT && !internal.generatesCast()) {
CastMode previous = castMode();
castMode(CastMode.DEFAULT);
visit0(internal);
castMode(previous);
} else // We're not declaring, or "part" can declare
{
visit0(internal);
}
}
return (C) this;
}
use of org.jooq.RenderContext.CastMode in project jOOQ by jOOQ.
the class FieldMapForUpdate method accept.
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public final void accept(Context<?> ctx) {
if (size() > 0) {
String separator = "";
// [#989] Some dialects do not support qualified column references
// in the UPDATE statement's SET clause
// [#2055] Other dialects require qualified column references to
// disambiguated columns in queries like
// UPDATE t1 JOIN t2 .. SET t1.val = ..., t2.val = ...
boolean supportsQualify = !NO_SUPPORT_QUALIFY.contains(ctx.dialect()) && ctx.qualify();
// [#2823] [#10034] Few dialects need bind value casts for UPDATE .. SET
// Some regressions have been observed e.g. in PostgreSQL with JSON types, so let's be careful.
CastMode previous = ctx.castMode();
if (!CASTS_NEEDED.contains(ctx.dialect()))
ctx.castMode(CastMode.NEVER);
for (Entry<Field<?>, Field<?>> entry : removeReadonly(ctx, flattenEntrySet(entrySet(), true))) {
if (!"".equals(separator))
ctx.sql(separator).formatSeparator();
ctx.start(assignmentClause).qualify(supportsQualify, c -> c.visit(entry.getKey())).sql(" = ");
// [#8479] Emulate WHERE clause using CASE
Condition condition = (Condition) ctx.data(DATA_ON_DUPLICATE_KEY_WHERE);
if (condition != null)
ctx.visit(when(condition, (Field) entry.getValue()).else_(entry.getKey()));
else
ctx.visit(entry.getValue());
ctx.end(assignmentClause);
separator = ",";
}
if (!CASTS_NEEDED.contains(ctx.dialect()))
ctx.castMode(previous);
} else
ctx.sql("[ no fields are updated ]");
}
use of org.jooq.RenderContext.CastMode in project jOOQ by jOOQ.
the class FieldMapsForInsert method toSQL92Values.
final void toSQL92Values(Context<?> ctx, boolean emulateBulkInsertReturning) {
boolean indent = (values.size() > 1);
boolean castFirstRowNumericValues = false;
// [#2823] [#10033] Few dialects need bind value casts for INSERT .. VALUES(?, ?)
// Some regressions have been observed e.g. in PostgreSQL with JSON types, so let's be careful.
CastMode previous = ctx.castMode();
if (!CASTS_NEEDED.contains(ctx.dialect()))
ctx.castMode(CastMode.NEVER);
for (int row = 0; row < rows; row++) {
if (row > 0)
ctx.sql(", ");
ctx.start(FIELD_ROW).sql('(');
if (indent)
ctx.formatIndentStart();
String separator = "";
int i = 0;
for (List<Field<?>> list : valuesFlattened(ctx).values()) {
ctx.sql(separator);
if (indent)
ctx.formatNewLine();
ctx.visit(list.get(row));
separator = ", ";
}
if (indent)
ctx.formatIndentEnd().formatNewLine();
ctx.sql(')').end(FIELD_ROW);
}
if (!CASTS_NEEDED.contains(ctx.dialect()))
ctx.castMode(previous);
}
Aggregations