Search in sources :

Example 21 with Condition

use of org.jooq.Condition in project jOOQ by jOOQ.

the class ParserImpl method parseAlterTable.

private static final DDLQuery parseAlterTable(ParserContext ctx) {
    boolean ifExists = parseKeywordIf(ctx, "IF EXISTS");
    Table<?> tableName = parseTableName(ctx);
    parseWhitespaceIf(ctx);
    AlterTableStep s1 = ifExists ? ctx.dsl.alterTableIfExists(tableName) : ctx.dsl.alterTable(tableName);
    switch(ctx.character()) {
        case 'a':
        case 'A':
            if (parseKeywordIf(ctx, "ADD")) {
                ConstraintTypeStep constraint = null;
                if (parseKeywordIf(ctx, "CONSTRAINT"))
                    constraint = constraint(parseIdentifier(ctx));
                if (parseKeywordIf(ctx, "PRIMARY KEY")) {
                    parse(ctx, '(');
                    Field<?>[] fieldNames = parseFieldNames(ctx).toArray(EMPTY_FIELD);
                    parse(ctx, ')');
                    return constraint == null ? s1.add(primaryKey(fieldNames)) : s1.add(constraint.primaryKey(fieldNames));
                } else if (parseKeywordIf(ctx, "UNIQUE")) {
                    parse(ctx, '(');
                    Field<?>[] fieldNames = parseFieldNames(ctx).toArray(EMPTY_FIELD);
                    parse(ctx, ')');
                    return constraint == null ? s1.add(unique(fieldNames)) : s1.add(constraint.unique(fieldNames));
                } else if (parseKeywordIf(ctx, "FOREIGN KEY")) {
                    parse(ctx, '(');
                    Field<?>[] referencing = parseFieldNames(ctx).toArray(EMPTY_FIELD);
                    parse(ctx, ')');
                    parseKeyword(ctx, "REFERENCES");
                    Table<?> referencedTable = parseTableName(ctx);
                    parse(ctx, '(');
                    Field<?>[] referencedFields = parseFieldNames(ctx).toArray(EMPTY_FIELD);
                    parse(ctx, ')');
                    if (referencing.length != referencedFields.length)
                        throw ctx.exception();
                    return constraint == null ? s1.add(foreignKey(referencing).references(referencedTable, referencedFields)) : s1.add(constraint.foreignKey(referencing).references(referencedTable, referencedFields));
                } else if (parseKeywordIf(ctx, "CHECK")) {
                    parse(ctx, '(');
                    Condition condition = parseCondition(ctx);
                    parse(ctx, ')');
                    return constraint == null ? s1.add(check(condition)) : s1.add(constraint.check(condition));
                } else if (constraint != null) {
                    throw ctx.unexpectedToken();
                } else {
                    parseKeywordIf(ctx, "COLUMN");
                    // The below code is taken from CREATE TABLE, with minor modifications as
                    // https://github.com/jOOQ/jOOQ/issues/5317 has not yet been implemented
                    // Once implemented, we might be able to factor out the common logic into
                    // a new parseXXX() method.
                    String fieldName = parseIdentifier(ctx);
                    DataType type = parseDataType(ctx);
                    boolean nullable = false;
                    boolean defaultValue = false;
                    boolean unique = false;
                    for (; ; ) {
                        if (!nullable) {
                            if (parseKeywordIf(ctx, "NULL")) {
                                type = type.nullable(true);
                                nullable = true;
                                continue;
                            } else if (parseKeywordIf(ctx, "NOT NULL")) {
                                type = type.nullable(false);
                                nullable = true;
                                continue;
                            }
                        }
                        if (!defaultValue) {
                            if (parseKeywordIf(ctx, "DEFAULT")) {
                                type = type.defaultValue(parseField(ctx));
                                defaultValue = true;
                                continue;
                            }
                        }
                        if (!unique) {
                            if (parseKeywordIf(ctx, "PRIMARY KEY")) {
                                throw ctx.unexpectedToken();
                            } else if (parseKeywordIf(ctx, "UNIQUE")) {
                                throw ctx.unexpectedToken();
                            }
                        }
                        if (parseKeywordIf(ctx, "CHECK")) {
                            throw ctx.unexpectedToken();
                        }
                        break;
                    }
                    return s1.add(field(name(fieldName), type), type);
                }
            }
            break;
        case 'd':
        case 'D':
            if (parseKeywordIf(ctx, "DROP")) {
                if (parseKeywordIf(ctx, "COLUMN")) {
                    Field<?> field = parseFieldName(ctx);
                    boolean cascade = parseKeywordIf(ctx, "CASCADE");
                    boolean restrict = !cascade && parseKeywordIf(ctx, "RESTRICT");
                    AlterTableDropStep s2 = s1.dropColumn(field);
                    AlterTableFinalStep s3 = cascade ? s2.cascade() : restrict ? s2.restrict() : s2;
                    return s3;
                } else if (parseKeywordIf(ctx, "CONSTRAINT")) {
                    String constraint = parseIdentifier(ctx);
                    return s1.dropConstraint(constraint);
                }
            }
            break;
        case 'r':
        case 'R':
            if (parseKeywordIf(ctx, "RENAME")) {
                if (parseKeywordIf(ctx, "TO")) {
                    String newName = parseIdentifier(ctx);
                    return s1.renameTo(newName);
                } else if (parseKeywordIf(ctx, "COLUMN")) {
                    String oldName = parseIdentifier(ctx);
                    parseKeyword(ctx, "TO");
                    String newName = parseIdentifier(ctx);
                    return s1.renameColumn(oldName).to(newName);
                } else if (parseKeywordIf(ctx, "CONSTRAINT")) {
                    String oldName = parseIdentifier(ctx);
                    parseKeyword(ctx, "TO");
                    String newName = parseIdentifier(ctx);
                    return s1.renameConstraint(oldName).to(newName);
                }
            }
            break;
    }
    throw ctx.unexpectedToken();
}
Also used : ConstraintTypeStep(org.jooq.ConstraintTypeStep) Condition(org.jooq.Condition) TableField(org.jooq.TableField) GroupField(org.jooq.GroupField) Field(org.jooq.Field) SortField(org.jooq.SortField) AlterTableFinalStep(org.jooq.AlterTableFinalStep) AlterTableStep(org.jooq.AlterTableStep) DataType(org.jooq.DataType) AlterTableDropStep(org.jooq.AlterTableDropStep)

Example 22 with Condition

use of org.jooq.Condition in project jOOQ by jOOQ.

the class SelectQueryImpl method toSQLReference0.

/**
     * This method renders the main part of a query without the LIMIT clause.
     * This part is common to any type of limited query
     */
@SuppressWarnings("unchecked")
private final void toSQLReference0(Context<?> context, Field<?>[] originalFields, Field<?>[] alternativeFields) {
    SQLDialect dialect = context.dialect();
    SQLDialect family = dialect.family();
    int unionOpSize = unionOp.size();
    // The SQL standard specifies:
    //
    // <query expression> ::=
    //    [ <with clause> ] <query expression body>
    //    [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
    //
    // Depending on the dialect and on various syntax elements, parts of the above must be wrapped in
    // synthetic parentheses
    boolean wrapQueryExpressionInDerivedTable;
    boolean wrapQueryExpressionBodyInDerivedTable = false;
    wrapQueryExpressionInDerivedTable = false || //         interpreted as the (missing) INSERT column list's parens.
    (context.data(DATA_INSERT_SELECT_WITHOUT_INSERT_COLUMN_LIST) != null && unionOpSize > 0);
    if (wrapQueryExpressionInDerivedTable)
        context.keyword("select").sql(" *").formatSeparator().keyword("from").sql(" (").formatIndentStart().formatNewLine();
    // all databases, we need to wrap relevant subqueries in parentheses.
    if (unionOpSize > 0) {
        for (int i = unionOpSize - 1; i >= 0; i--) {
            switch(unionOp.get(i)) {
                case EXCEPT:
                    context.start(SELECT_EXCEPT);
                    break;
                case EXCEPT_ALL:
                    context.start(SELECT_EXCEPT_ALL);
                    break;
                case INTERSECT:
                    context.start(SELECT_INTERSECT);
                    break;
                case INTERSECT_ALL:
                    context.start(SELECT_INTERSECT_ALL);
                    break;
                case UNION:
                    context.start(SELECT_UNION);
                    break;
                case UNION_ALL:
                    context.start(SELECT_UNION_ALL);
                    break;
            }
            unionParenthesis(context, "(");
        }
    }
    // SELECT clause
    // -------------
    context.start(SELECT_SELECT).keyword("select").sql(' ');
    // [#1493] Oracle hints come directly after the SELECT keyword
    if (!StringUtils.isBlank(hint)) {
        context.sql(hint).sql(' ');
    }
    if (!distinctOn.isEmpty()) {
        context.keyword("distinct on").sql(" (").visit(distinctOn).sql(") ");
    } else if (distinct) {
        context.keyword("distinct").sql(' ');
    }
    context.declareFields(true);
    // non-ambiguous column names as ambiguous column names are not allowed in subqueries
    if (alternativeFields != null) {
        if (wrapQueryExpressionBodyInDerivedTable && originalFields.length < alternativeFields.length)
            context.visit(new SelectFieldList(Arrays.copyOf(alternativeFields, alternativeFields.length - 1)));
        else
            context.visit(new SelectFieldList(alternativeFields));
    } else // arrays explicitly, as the subquery doesn't form an implicit RVE
    if (context.subquery() && dialect == H2 && context.data(DATA_ROW_VALUE_EXPRESSION_PREDICATE_SUBQUERY) != null) {
        Object data = context.data(DATA_ROW_VALUE_EXPRESSION_PREDICATE_SUBQUERY);
        try {
            context.data(DATA_ROW_VALUE_EXPRESSION_PREDICATE_SUBQUERY, null);
            context.sql('(').visit(getSelect1()).sql(')');
        } finally {
            context.data(DATA_ROW_VALUE_EXPRESSION_PREDICATE_SUBQUERY, data);
        }
    } else // The default behaviour
    {
        context.visit(getSelect1());
    }
    context.declareFields(false).end(SELECT_SELECT);
    //         only in top level SELECTs
    if (!context.subquery() && !asList().contains(family)) {
        context.start(SELECT_INTO);
        Table<?> actualInto = (Table<?>) context.data(DATA_SELECT_INTO_TABLE);
        if (actualInto == null)
            actualInto = into;
        if (actualInto != null && context.data(DATA_OMIT_INTO_CLAUSE) == null && asList(HSQLDB, POSTGRES).contains(family)) {
            context.formatSeparator().keyword("into").sql(' ').visit(actualInto);
        }
        context.end(SELECT_INTO);
    }
    // FROM and JOIN clauses
    // ---------------------
    context.start(SELECT_FROM).declareTables(true);
    // [#....] Some SQL dialects do not require a FROM clause. Others do and
    //         jOOQ generates a "DUAL" table or something equivalent.
    //         See also org.jooq.impl.Dual for details.
    boolean hasFrom = !getFrom().isEmpty() || asList(CUBRID, DERBY, FIREBIRD, HSQLDB, MARIADB, MYSQL).contains(family);
    List<Condition> semiAntiJoinPredicates = null;
    if (hasFrom) {
        Object previousCollect = context.data(DATA_COLLECT_SEMI_ANTI_JOIN, true);
        Object previousCollected = context.data(DATA_COLLECTED_SEMI_ANTI_JOIN, null);
        context.formatSeparator().keyword("from").sql(' ').visit(getFrom());
        semiAntiJoinPredicates = (List<Condition>) context.data(DATA_COLLECTED_SEMI_ANTI_JOIN, previousCollected);
        context.data(DATA_COLLECT_SEMI_ANTI_JOIN, previousCollect);
    }
    context.declareTables(false).end(SELECT_FROM);
    // WHERE clause
    // ------------
    context.start(SELECT_WHERE);
    if (getWhere().getWhere() instanceof TrueCondition && semiAntiJoinPredicates == null)
        ;
    else {
        ConditionProviderImpl where = new ConditionProviderImpl();
        if (semiAntiJoinPredicates != null)
            where.addConditions(semiAntiJoinPredicates);
        if (!(getWhere().getWhere() instanceof TrueCondition))
            where.addConditions(getWhere());
        context.formatSeparator().keyword("where").sql(' ').visit(where);
    }
    context.end(SELECT_WHERE);
    // CONNECT BY clause
    // -----------------
    // CUBRID supports this clause only as [ START WITH .. ] CONNECT BY
    // Oracle also knows the CONNECT BY .. [ START WITH ] alternative
    // syntax
    context.start(SELECT_START_WITH);
    if (!(getConnectByStartWith().getWhere() instanceof TrueCondition)) {
        context.formatSeparator().keyword("start with").sql(' ').visit(getConnectByStartWith());
    }
    context.end(SELECT_START_WITH);
    context.start(SELECT_CONNECT_BY);
    if (!(getConnectBy().getWhere() instanceof TrueCondition)) {
        context.formatSeparator().keyword("connect by");
        if (connectByNoCycle) {
            context.sql(' ').keyword("nocycle");
        }
        context.sql(' ').visit(getConnectBy());
    }
    context.end(SELECT_CONNECT_BY);
    // GROUP BY and HAVING clause
    // --------------------------
    context.start(SELECT_GROUP_BY);
    if (grouping) {
        context.formatSeparator().keyword("group by").sql(' ');
        // [#1665] Empty GROUP BY () clauses need parentheses
        if (getGroupBy().isEmpty()) {
            // [#1681] Use the constant field from the dummy table Sybase ASE, Ingres
            if (asList().contains(family)) {
                context.sql("empty_grouping_dummy_table.dual");
            } else // references, as in the ORDER BY clause!
            if (asList(DERBY).contains(family)) {
                context.sql('0');
            } else // [#4447] CUBRID can't handle subqueries in GROUP BY
            if (family == CUBRID) {
                context.sql("1 + 0");
            } else // [#4292] Some dialects don't support empty GROUP BY () clauses
            if (asList(FIREBIRD, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE).contains(family)) {
                context.sql('(').visit(DSL.select(one())).sql(')');
            } else // Few dialects support the SQL standard "grand total" (i.e. empty grouping set)
            {
                context.sql("()");
            }
        } else {
            context.visit(getGroupBy());
        }
    }
    context.end(SELECT_GROUP_BY);
    // HAVING clause
    // -------------
    context.start(SELECT_HAVING);
    if (!(getHaving().getWhere() instanceof TrueCondition)) {
        context.formatSeparator().keyword("having").sql(' ').visit(getHaving());
    }
    context.end(SELECT_HAVING);
    // WINDOW clause
    // -------------
    context.start(SELECT_WINDOW);
    if (!getWindow().isEmpty() && asList(POSTGRES).contains(family)) {
        context.formatSeparator().keyword("window").sql(' ').declareWindows(true).visit(getWindow()).declareWindows(false);
    }
    context.end(SELECT_WINDOW);
    // ORDER BY clause for local subselect
    // -----------------------------------
    toSQLOrderBy(context, originalFields, alternativeFields, false, wrapQueryExpressionBodyInDerivedTable, orderBy, limit);
    // --------------------------------------------
    if (unionOpSize > 0) {
        unionParenthesis(context, ")");
        for (int i = 0; i < unionOpSize; i++) {
            CombineOperator op = unionOp.get(i);
            for (Select<?> other : union.get(i)) {
                context.formatSeparator().keyword(op.toSQL(dialect)).sql(' ');
                unionParenthesis(context, "(");
                context.visit(other);
                unionParenthesis(context, ")");
            }
            // [#1658] Close parentheses opened previously
            if (i < unionOpSize - 1)
                unionParenthesis(context, ")");
            switch(unionOp.get(i)) {
                case EXCEPT:
                    context.end(SELECT_EXCEPT);
                    break;
                case EXCEPT_ALL:
                    context.end(SELECT_EXCEPT_ALL);
                    break;
                case INTERSECT:
                    context.end(SELECT_INTERSECT);
                    break;
                case INTERSECT_ALL:
                    context.end(SELECT_INTERSECT_ALL);
                    break;
                case UNION:
                    context.end(SELECT_UNION);
                    break;
                case UNION_ALL:
                    context.end(SELECT_UNION_ALL);
                    break;
            }
        }
    }
    // ORDER BY clause for UNION
    // -------------------------
    boolean qualify = context.qualify();
    try {
        context.qualify(false);
        toSQLOrderBy(context, originalFields, alternativeFields, wrapQueryExpressionInDerivedTable, wrapQueryExpressionBodyInDerivedTable, unionOrderBy, unionLimit);
    } finally {
        context.qualify(qualify);
    }
}
Also used : Condition(org.jooq.Condition) Table(org.jooq.Table) SQLDialect(org.jooq.SQLDialect)

Example 23 with Condition

use of org.jooq.Condition in project jOOQ by jOOQ.

the class MergeImpl method getStandardMerge.

// -------------------------------------------------------------------------
// QueryPart API
// -------------------------------------------------------------------------
/**
     * Return a standard MERGE statement emulating the H2-specific syntax
     */
private final QueryPart getStandardMerge() {
    // The SRC for the USING() clause:
    // ------------------------------
    Table<?> src;
    if (upsertSelect != null) {
        List<Field<?>> v = new ArrayList<Field<?>>();
        Row row = upsertSelect.fieldsRow();
        for (int i = 0; i < row.size(); i++) {
            v.add(row.field(i).as("s" + (i + 1)));
        }
        // [#579] TODO: Currently, this syntax may require aliasing
        // on the call-site
        src = DSL.select(v).from(upsertSelect).asTable("src");
    } else {
        List<Field<?>> v = new ArrayList<Field<?>>();
        for (int i = 0; i < getUpsertValues().size(); i++) {
            v.add(getUpsertValues().get(i).as("s" + (i + 1)));
        }
        src = DSL.select(v).asTable("src");
    }
    // The condition for the ON clause:
    // --------------------------------
    Set<Field<?>> onFields = new HashSet<Field<?>>();
    Condition condition = null;
    if (getUpsertKeys().isEmpty()) {
        UniqueKey<?> key = table.getPrimaryKey();
        if (key != null) {
            onFields.addAll(key.getFields());
            for (int i = 0; i < key.getFields().size(); i++) {
                Condition rhs = key.getFields().get(i).equal((Field) src.field(i));
                if (condition == null) {
                    condition = rhs;
                } else {
                    condition = condition.and(rhs);
                }
            }
        } else // This should probably execute an INSERT statement
        {
            throw new IllegalStateException("Cannot omit KEY() clause on a non-Updatable Table");
        }
    } else {
        for (int i = 0; i < getUpsertKeys().size(); i++) {
            int matchIndex = getUpsertFields().indexOf(getUpsertKeys().get(i));
            if (matchIndex == -1) {
                throw new IllegalStateException("Fields in KEY() clause must be part of the fields specified in MERGE INTO table (...)");
            }
            onFields.addAll(getUpsertKeys());
            Condition rhs = getUpsertKeys().get(i).equal((Field) src.field(matchIndex));
            if (condition == null) {
                condition = rhs;
            } else {
                condition = condition.and(rhs);
            }
        }
    }
    // INSERT and UPDATE clauses
    // -------------------------
    Map<Field<?>, Field<?>> update = new LinkedHashMap<Field<?>, Field<?>>();
    Map<Field<?>, Field<?>> insert = new LinkedHashMap<Field<?>, Field<?>>();
    for (int i = 0; i < src.fieldsRow().size(); i++) {
        // Oracle does not allow to update fields from the ON clause
        if (!onFields.contains(getUpsertFields().get(i))) {
            update.put(getUpsertFields().get(i), src.field(i));
        }
        insert.put(getUpsertFields().get(i), src.field(i));
    }
    return DSL.mergeInto(table).using(src).on(condition).whenMatchedThenUpdate().set(update).whenNotMatchedThenInsert().set(insert);
}
Also used : Condition(org.jooq.Condition) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Field(org.jooq.Field) Row(org.jooq.Row) HashSet(java.util.HashSet)

Example 24 with Condition

use of org.jooq.Condition in project jOOQ by jOOQ.

the class ParserImpl method parseDelete.

private static final Delete<?> parseDelete(ParserContext ctx) {
    parseKeyword(ctx, "DELETE");
    parseKeywordIf(ctx, "FROM");
    Table<?> tableName = parseTableName(ctx);
    boolean where = parseKeywordIf(ctx, "WHERE");
    Condition condition = where ? parseCondition(ctx) : null;
    // TODO Implement returning
    // boolean returning = parseKeywordIf(ctx, "RETURNING");
    DeleteWhereStep<?> s1;
    DeleteFinalStep<?> s2;
    s1 = ctx.dsl.delete(tableName);
    s2 = where ? s1.where(condition) : s1;
    return s2;
}
Also used : Condition(org.jooq.Condition)

Example 25 with Condition

use of org.jooq.Condition in project jOOQ by jOOQ.

the class ParserImpl method parseUpdate.

private static final Update<?> parseUpdate(ParserContext ctx) {
    parseKeyword(ctx, "UPDATE");
    Table<?> tableName = parseTableName(ctx);
    parseKeyword(ctx, "SET");
    // TODO Row value expression updates
    Map<Field<?>, Object> map = parseSetClauseList(ctx);
    // TODO support FROM
    Condition condition = parseKeywordIf(ctx, "WHERE") ? parseCondition(ctx) : null;
    // TODO support RETURNING
    return condition == null ? ctx.dsl.update(tableName).set(map) : ctx.dsl.update(tableName).set(map).where(condition);
}
Also used : Condition(org.jooq.Condition) TableField(org.jooq.TableField) GroupField(org.jooq.GroupField) Field(org.jooq.Field) SortField(org.jooq.SortField)

Aggregations

Condition (org.jooq.Condition)29 Field (org.jooq.Field)14 GroupField (org.jooq.GroupField)11 SortField (org.jooq.SortField)11 TableField (org.jooq.TableField)11 ArrayList (java.util.ArrayList)9 List (java.util.List)5 Arrays.asList (java.util.Arrays.asList)3 Comparator (org.jooq.Comparator)3 QueryPartInternal (org.jooq.QueryPartInternal)3 Record (org.jooq.Record)3 SQLDialect (org.jooq.SQLDialect)3 Collections.emptyList (java.util.Collections.emptyList)2 LinkedHashMap (java.util.LinkedHashMap)2 ConstraintTypeStep (org.jooq.ConstraintTypeStep)2 Name (org.jooq.Name)2 Record1 (org.jooq.Record1)2 Row (org.jooq.Row)2 RowN (org.jooq.RowN)2 Table (org.jooq.Table)2