Search in sources :

Example 1 with CastMode

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;
            }
    }
}
Also used : CastMode(org.jooq.RenderContext.CastMode) ParamType(org.jooq.conf.ParamType)

Example 2 with CastMode

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]);
        }
    }
}
Also used : BindContext(org.jooq.BindContext) BigInteger(java.math.BigInteger) UInteger(org.jooq.types.UInteger) RenderContext(org.jooq.RenderContext) SQLDialect(org.jooq.SQLDialect) QueryPart(org.jooq.QueryPart) TemplatingException(org.jooq.exception.TemplatingException) CastMode(org.jooq.RenderContext.CastMode)

Example 3 with CastMode

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;
}
Also used : QueryPartInternal(org.jooq.QueryPartInternal) CastMode(org.jooq.RenderContext.CastMode) ParamCastMode(org.jooq.conf.ParamCastMode)

Example 4 with CastMode

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 ]");
}
Also used : THROW(org.jooq.conf.WriteIfReadonly.THROW) Row(org.jooq.Row) UNotYetImplemented(org.jooq.impl.QOM.UNotYetImplemented) IGNORE(org.jooq.conf.WriteIfReadonly.IGNORE) Tools.collect(org.jooq.impl.Tools.collect) Set(java.util.Set) Table(org.jooq.Table) Tools.row0(org.jooq.impl.Tools.row0) Field(org.jooq.Field) POSTGRES(org.jooq.SQLDialect.POSTGRES) DSL.when(org.jooq.impl.DSL.when) Condition(org.jooq.Condition) Tools.filter(org.jooq.impl.Tools.filter) YUGABYTEDB(org.jooq.SQLDialect.YUGABYTEDB) DATA_ON_DUPLICATE_KEY_WHERE(org.jooq.impl.Tools.DataKey.DATA_ON_DUPLICATE_KEY_WHERE) Clause(org.jooq.Clause) Context(org.jooq.Context) CastMode(org.jooq.RenderContext.CastMode) SQLITE(org.jooq.SQLDialect.SQLITE) Map(java.util.Map) Tools.flattenEntrySet(org.jooq.impl.Tools.flattenEntrySet) DataTypeException(org.jooq.exception.DataTypeException) SQLDialect(org.jooq.SQLDialect) Tools.anyMatch(org.jooq.impl.Tools.anyMatch) Condition(org.jooq.Condition) Field(org.jooq.Field) CastMode(org.jooq.RenderContext.CastMode)

Example 5 with CastMode

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);
}
Also used : Field(org.jooq.Field) UnknownField(org.jooq.impl.AbstractStoreQuery.UnknownField) CastMode(org.jooq.RenderContext.CastMode)

Aggregations

CastMode (org.jooq.RenderContext.CastMode)6 Clause (org.jooq.Clause)2 Field (org.jooq.Field)2 QueryPart (org.jooq.QueryPart)2 QueryPartInternal (org.jooq.QueryPartInternal)2 SQLDialect (org.jooq.SQLDialect)2 ParamCastMode (org.jooq.conf.ParamCastMode)2 BigInteger (java.math.BigInteger)1 Map (java.util.Map)1 Set (java.util.Set)1 BindContext (org.jooq.BindContext)1 Condition (org.jooq.Condition)1 Context (org.jooq.Context)1 RenderContext (org.jooq.RenderContext)1 Row (org.jooq.Row)1 POSTGRES (org.jooq.SQLDialect.POSTGRES)1 SQLITE (org.jooq.SQLDialect.SQLITE)1 YUGABYTEDB (org.jooq.SQLDialect.YUGABYTEDB)1 Table (org.jooq.Table)1 ParamType (org.jooq.conf.ParamType)1