use of org.jooq.QueryPart in project jOOQ by jOOQ.
the class Function method toSQLArguments1.
final void toSQLArguments1(Context<?> ctx, QueryPartList<QueryPart> args) {
if (distinct) {
ctx.keyword("distinct");
// [#2883] PostgreSQL can use the DISTINCT keyword with formal row value expressions.
if (ctx.family() == POSTGRES && args.size() > 1) {
ctx.sql('(');
} else {
ctx.sql(' ');
}
}
if (!args.isEmpty()) {
if (filter == null || HSQLDB == ctx.family() || POSTGRES_9_4.precedes(ctx.dialect())) {
ctx.visit(args);
} else {
QueryPartList<Field<?>> expressions = new QueryPartList<Field<?>>();
for (QueryPart argument : args) expressions.add(DSL.when(filter, argument == ASTERISK ? one() : argument));
ctx.visit(expressions);
}
}
if (distinct)
if (ctx.family() == POSTGRES && args.size() > 1)
ctx.sql(')');
if (ignoreNulls) {
ctx.sql(' ').keyword("ignore nulls");
} else if (respectNulls) {
ctx.sql(' ').keyword("respect nulls");
}
}
use of org.jooq.QueryPart 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 = (RenderContext) ((ctx instanceof RenderContext) ? ctx : null);
BindContext bind = (BindContext) ((ctx instanceof 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 dialect = render.configuration().dialect();
SQLDialect family = dialect.family();
boolean mysql = asList(MARIADB, MYSQL).contains(family);
String[][] 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, "--") || // http://bugs.mysql.com/bug.php?id=76623
(mysql && peek(sqlChars, i, "#"))) {
// 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, "/*")) {
// Consume the complete comment
for (; !peek(sqlChars, i, "*/"); render.sql(sqlChars[i++])) ;
// Consume the comment delimiter
render.sql(sqlChars[i++]);
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 (; ; ) {
// [#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, "''")) {
render.sql(sqlChars[i++]);
} else // Break on the terminal string literal delimiter
if (peek(sqlChars, i, "'")) {
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
for (; ; ) {
// 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++]);
} else // Break on the terminal identifier delimiter
if (peek(sqlChars, i, quotes[QUOTE_END_DELIMITER][delimiter])) {
break;
}
// 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) {
for (String suffix : NON_BIND_VARIABLE_SUFFIXES) {
if (peek(sqlChars, i + 1, suffix)) {
for (int j = i; i - j <= suffix.length(); i++) render.sql(sqlChars[i]);
render.sql(sqlChars[i]);
continue characterLoop;
}
}
}
// [#4131] Consume the named bind variable
if (sqlChars[i] == ':')
while (++i < sqlChars.length && isJavaIdentifierPart(sqlChars[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;
String token = sql.substring(start, end);
// Try getting the {numbered placeholder}
try {
QueryPart substitute = substitutes.get(Integer.valueOf(token));
render.visit(substitute);
if (bind != null) {
bind.visit(substitute);
}
}// If the above failed, then we're dealing with a {keyword}
catch (NumberFormatException e) {
render.keyword(token);
}
}
} else // Any other character
{
render.sql(sqlChars[i]);
}
}
}
use of org.jooq.QueryPart in project jOOQ by jOOQ.
the class Function method toSQLOverClause.
final void toSQLOverClause(Context<?> ctx) {
QueryPart window = window(ctx);
// Render this clause only if needed
if (window == null)
return;
// [#1524] Don't render this clause where it is not supported
if (term == ROW_NUMBER && ctx.configuration().dialect() == HSQLDB)
return;
ctx.sql(' ').keyword("over").sql(' ').visit(window);
}
use of org.jooq.QueryPart in project jOOQ by jOOQ.
the class AbstractContext method visit.
// ------------------------------------------------------------------------
// VisitListener API
// ------------------------------------------------------------------------
@Override
public final C visit(QueryPart part) {
if (part != null) {
// Issue start clause events
// -----------------------------------------------------------------
Clause[] clauses = visitListeners.length > 0 ? clause(part) : null;
if (clauses != null)
for (int i = 0; i < clauses.length; i++) start(clauses[i]);
// Perform the actual visiting, or recurse into the replacement
// -----------------------------------------------------------------
QueryPart original = part;
QueryPart replacement = start(part);
if (original == replacement)
visit0(original);
else
visit0(replacement);
end(replacement);
// -----------------------------------------------------------------
if (clauses != null)
for (int i = clauses.length - 1; i >= 0; i--) end(clauses[i]);
}
return (C) this;
}
Aggregations