use of org.jooq.Clause in project jOOQ by jOOQ.
the class InsertQueryImpl method toInsertSelect.
@SuppressWarnings("unchecked")
private final QueryPart toInsertSelect(Context<?> ctx) {
List<List<? extends Field<?>>> keys = conflictingKeys(ctx);
if (!keys.isEmpty()) {
Select<Record> rows = null;
Set<Field<?>> fields = insertMaps.keysFlattened(ctx);
// [#10989] INSERT .. SELECT .. ON DUPLICATE KEY IGNORE
if (select != null) {
Map<Field<?>, Field<?>> map = new HashMap<>();
Field<?>[] names = Tools.fields(select.fields().length);
List<Field<?>> f = new ArrayList<>(fields);
for (int i = 0; i < fields.size() && i < names.length; i++) map.put(f.get(i), names[i]);
rows = (Select<Record>) selectFrom(select.asTable(DSL.table(name("t")), names)).whereNotExists(selectOne().from(table()).where(matchByConflictingKeys(ctx, map)));
} else // [#5089] Multi-row inserts need to explicitly generate UNION ALL
// here. TODO: Refactor this logic to be more generally
// reusable - i.e. ordinary UNION ALL emulation should be
// re-used.
{
for (Map<Field<?>, Field<?>> map : insertMaps.maps()) {
Select<Record> row = select(aliasedFields(map.entrySet().stream().filter(e -> fields.contains(e.getKey())).map(Entry::getValue).collect(toList()))).whereNotExists(selectOne().from(table()).where(matchByConflictingKeys(ctx, map)));
if (rows == null)
rows = row;
else
rows = rows.unionAll(row);
}
}
return ctx.dsl().insertInto(table()).columns(fields).select(selectFrom(rows.asTable("t")));
} else
return DSL.sql("[ The ON DUPLICATE KEY IGNORE/UPDATE clause cannot be emulated when inserting into tables without any known keys : " + table() + " ]");
}
use of org.jooq.Clause in project jOOQ by jOOQ.
the class SelectQueryImpl method accept0.
final void accept0(Context<?> context) {
boolean topLevelCte = false;
// Subquery scopes are started in AbstractContext
if (context.subqueryLevel() == 0) {
context.scopeStart();
if (topLevelCte |= (context.data(DATA_TOP_LEVEL_CTE) == null))
context.data(DATA_TOP_LEVEL_CTE, new TopLevelCte());
}
SQLDialect dialect = context.dialect();
// [#2791] TODO: Instead of explicitly manipulating these data() objects, future versions
// of jOOQ should implement a push / pop semantics to clearly delimit such scope.
Object renderTrailingLimit = context.data(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE);
Object localWindowDefinitions = context.data(DATA_WINDOW_DEFINITIONS);
Name[] selectAliases = (Name[]) context.data(DATA_SELECT_ALIASES);
try {
List<Field<?>> originalFields = null;
List<Field<?>> alternativeFields = null;
if (selectAliases != null) {
context.data().remove(DATA_SELECT_ALIASES);
alternativeFields = map(originalFields = getSelect(), (f, i) -> i < selectAliases.length ? f.as(selectAliases[i]) : f);
}
if (TRUE.equals(renderTrailingLimit))
context.data().remove(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE);
// [#5127] Lazy initialise this map
if (localWindowDefinitions != null)
context.data(DATA_WINDOW_DEFINITIONS, null);
if (intoTable != null && !TRUE.equals(context.data(DATA_OMIT_INTO_CLAUSE)) && EMULATE_SELECT_INTO_AS_CTAS.contains(dialect)) {
context.data(DATA_OMIT_INTO_CLAUSE, true, c -> c.visit(createTable(intoTable).as(this)));
return;
}
if (with != null)
context.visit(with);
else if (topLevelCte)
markTopLevelCteAndAccept(context, c -> {
});
pushWindow(context);
Boolean wrapDerivedTables = (Boolean) context.data(DATA_WRAP_DERIVED_TABLES_IN_PARENTHESES);
if (TRUE.equals(wrapDerivedTables)) {
context.sqlIndentStart('(').data().remove(DATA_WRAP_DERIVED_TABLES_IN_PARENTHESES);
}
switch(dialect) {
case CUBRID:
case FIREBIRD:
case MYSQL:
case YUGABYTEDB:
{
if (getLimit().isApplicable() && getLimit().withTies())
toSQLReferenceLimitWithWindowFunctions(context);
else
toSQLReferenceLimitDefault(context, originalFields, alternativeFields);
break;
}
// By default, render the dialect's limit clause
default:
{
toSQLReferenceLimitDefault(context, originalFields, alternativeFields);
break;
}
}
// [#1296] [#7328] FOR UPDATE is emulated in some dialects using hints
if (forLock != null)
context.visit(forLock);
// end-of-query clauses are appended to the end of a query
if (!StringUtils.isBlank(option))
context.formatSeparator().sql(option);
if (TRUE.equals(wrapDerivedTables))
context.sqlIndentEnd(')').data(DATA_WRAP_DERIVED_TABLES_IN_PARENTHESES, true);
} finally {
context.data(DATA_WINDOW_DEFINITIONS, localWindowDefinitions);
if (renderTrailingLimit != null)
context.data(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE, renderTrailingLimit);
if (selectAliases != null)
context.data(DATA_SELECT_ALIASES, selectAliases);
}
if (context.subqueryLevel() == 0)
context.scopeEnd();
}
use of org.jooq.Clause in project jOOQ by jOOQ.
the class MergeImpl method toSQLStandard.
private final void toSQLStandard(Context<?> ctx) {
ctx.start(MERGE_MERGE_INTO).visit(K_MERGE_INTO).sql(' ').declareTables(true, c -> c.visit(table)).end(MERGE_MERGE_INTO).formatSeparator().start(MERGE_USING).visit(K_USING).sql(' ');
ctx.declareTables(true, c1 -> c1.data(DATA_WRAP_DERIVED_TABLES_IN_PARENTHESES, true, c2 -> {
// in its MERGE statement.
if (usingDual) {
switch(c2.family()) {
case DERBY:
c2.visit(new Dual());
break;
default:
c2.visit(DSL.selectOne());
break;
}
} else
c2.visit(using);
}));
boolean onParentheses = false;
ctx.end(MERGE_USING).formatSeparator().start(MERGE_ON).visit(K_ON).sql(onParentheses ? " (" : " ").visit(on).sql(onParentheses ? ")" : "").end(MERGE_ON).start(MERGE_WHEN_MATCHED_THEN_UPDATE).start(MERGE_SET);
// [#7291] Multi MATCHED emulation
boolean emulate = false;
boolean requireMatchedConditions = false;
// [#10054] TODO: Skip all WHEN MATCHED clauses after a WHEN MATCHED clause with no search condition
if (NO_SUPPORT_CONDITION_AFTER_NO_CONDITION.contains(ctx.dialect())) {
boolean withoutMatchedConditionFound = false;
for (MatchedClause m : matched) {
if (requireMatchedConditions |= withoutMatchedConditionFound)
break;
withoutMatchedConditionFound |= m.condition instanceof NoCondition;
}
}
emulateCheck: if ((NO_SUPPORT_MULTI.contains(ctx.dialect()) && matched.size() > 1)) {
boolean matchUpdate = false;
boolean matchDelete = false;
for (MatchedClause m : matched) {
if (m.delete) {
if (emulate |= matchDelete)
break emulateCheck;
matchDelete = true;
} else {
if (emulate |= matchUpdate)
break emulateCheck;
matchUpdate = true;
}
}
}
if (emulate) {
MatchedClause update = null;
MatchedClause delete = null;
Condition negate = noCondition();
for (MatchedClause m : matched) {
Condition condition = negate.and(m.condition);
if (m.delete) {
if (delete == null)
delete = new MatchedClause(noCondition(), true);
delete.condition = delete.condition.or(condition);
} else {
if (update == null)
update = new MatchedClause(noCondition());
for (Entry<Field<?>, Field<?>> e : m.updateMap.entrySet()) {
Field<?> exp = update.updateMap.get(e.getKey());
if (exp instanceof CaseConditionStepImpl)
((CaseConditionStepImpl) exp).when(negate.and(condition), e.getValue());
else
update.updateMap.put(e.getKey(), when(negate.and(condition), (Field) e.getValue()).else_(e.getKey()));
}
update.condition = update.condition.or(condition);
}
if (REQUIRE_NEGATION.contains(ctx.dialect()))
negate = negate.andNot(m.condition instanceof NoCondition ? trueCondition() : m.condition);
}
{
if (delete != null)
toSQLMatched(ctx, delete, requireMatchedConditions);
if (update != null)
toSQLMatched(ctx, update, requireMatchedConditions);
}
} else // [#7291] Workaround for https://github.com/h2database/h2database/issues/2552
if (REQUIRE_NEGATION.contains(ctx.dialect())) {
Condition negate = noCondition();
for (MatchedClause m : matched) {
toSQLMatched(ctx, new MatchedClause(negate.and(m.condition), m.delete, m.updateMap), requireMatchedConditions);
negate = negate.andNot(m.condition instanceof NoCondition ? trueCondition() : m.condition);
}
} else {
for (MatchedClause m : matched) toSQLMatched(ctx, m, requireMatchedConditions);
}
ctx.end(MERGE_SET).end(MERGE_WHEN_MATCHED_THEN_UPDATE).start(MERGE_WHEN_NOT_MATCHED_THEN_INSERT);
for (NotMatchedClause m : notMatched) toSQLNotMatched(ctx, m);
ctx.end(MERGE_WHEN_NOT_MATCHED_THEN_INSERT);
}
use of org.jooq.Clause 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, List<Field<?>> originalFields, List<Field<?>> alternativeFields) {
SQLDialect family = context.family();
boolean qualify = context.qualify();
int unionOpSize = unionOp.size();
boolean unionParensRequired = false;
boolean unionOpNesting = false;
// 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;
boolean applySeekOnDerivedTable = applySeekOnDerivedTable();
wrapQueryExpressionInDerivedTable = false;
if (wrapQueryExpressionInDerivedTable)
context.visit(K_SELECT).sql(" *").formatSeparator().visit(K_FROM).sql(" (").formatIndentStart().formatNewLine();
wrapQueryExpressionBodyInDerivedTable = false || // predicate must be applied on a derived table, not on the individual subqueries
applySeekOnDerivedTable;
if (wrapQueryExpressionBodyInDerivedTable) {
context.visit(K_SELECT).sql(' ');
context.formatIndentStart().formatNewLine().sql("t.*");
if (alternativeFields != null && originalFields.size() < alternativeFields.size())
context.sql(", ").formatSeparator().declareFields(true, c -> c.visit(alternativeFields.get(alternativeFields.size() - 1)));
context.formatIndentEnd().formatSeparator().visit(K_FROM).sql(" (").formatIndentStart().formatNewLine();
}
// all databases, we need to wrap relevant subqueries in parentheses.
if (unionOpSize > 0) {
if (!TRUE.equals(context.data(DATA_NESTED_SET_OPERATIONS)))
context.data(DATA_NESTED_SET_OPERATIONS, unionOpNesting = unionOpNesting());
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;
}
// [#3676] There might be cases where nested set operations do not
// imply required parentheses in some dialects, but better
// play safe than sorry
unionParenthesis(context, '(', alternativeFields != null ? alternativeFields : getSelect(), derivedTableRequired(context, this), unionParensRequired = unionOpNesting || unionParensRequired(context));
}
}
traverseJoins(getFrom(), t -> {
if (t instanceof TableImpl)
context.scopeRegister(t, true);
});
for (Entry<QueryPart, QueryPart> entry : localQueryPartMapping.entrySet()) context.scopeRegister(entry.getKey(), true, entry.getValue());
// SELECT clause
// -------------
context.start(SELECT_SELECT).visit(K_SELECT).separatorRequired(true);
// [#1493] Oracle hints come directly after the SELECT keyword
if (!StringUtils.isBlank(hint))
context.sql(' ').sql(hint).separatorRequired(true);
if (Tools.isNotEmpty(distinctOn))
context.visit(K_DISTINCT_ON).sql(" (").visit(distinctOn).sql(')').separatorRequired(true);
else if (distinct)
context.visit(K_DISTINCT).separatorRequired(true);
if (TRUE.equals(context.data(BooleanDataKey.DATA_RENDERING_DATA_CHANGE_DELTA_TABLE)))
context.qualify(false);
context.declareFields(true);
// non-ambiguous column names as ambiguous column names are not allowed in subqueries
if (alternativeFields != null)
if (wrapQueryExpressionBodyInDerivedTable && originalFields.size() < alternativeFields.size())
context.visit(new SelectFieldList<>(alternativeFields.subList(0, originalFields.size())));
else
context.visit(new SelectFieldList<>(alternativeFields));
else
// The default behaviour
context.visit(getSelectResolveUnsupportedAsterisks(context.configuration()));
if (TRUE.equals(context.data(BooleanDataKey.DATA_RENDERING_DATA_CHANGE_DELTA_TABLE)))
context.qualify(qualify);
context.declareFields(false).end(SELECT_SELECT);
// only in top level SELECTs
if (!context.subquery()) {
context.start(SELECT_INTO);
QueryPart actualIntoTable = (QueryPart) context.data(DATA_SELECT_INTO_TABLE);
if (actualIntoTable == null)
actualIntoTable = intoTable;
if (actualIntoTable != null && !TRUE.equals(context.data(DATA_OMIT_INTO_CLAUSE)) && (SUPPORT_SELECT_INTO_TABLE.contains(context.dialect()) || !(actualIntoTable instanceof Table))) {
context.formatSeparator().visit(K_INTO).sql(' ').visit(actualIntoTable);
}
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() || !OPTIONAL_FROM_CLAUSE.contains(context.dialect());
List<Condition> semiAntiJoinPredicates = null;
ConditionProviderImpl where = getWhere(context);
if (hasFrom) {
Object previousCollect = context.data(DATA_COLLECT_SEMI_ANTI_JOIN, true);
Object previousCollected = context.data(DATA_COLLECTED_SEMI_ANTI_JOIN, null);
TableList tablelist = getFrom();
tablelist = transformInlineDerivedTables(tablelist, where);
context.formatSeparator().visit(K_FROM).separatorRequired(true).visit(tablelist);
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 (TRUE.equals(context.data().get(BooleanDataKey.DATA_SELECT_NO_DATA)))
context.formatSeparator().visit(K_WHERE).sql(' ').visit(falseCondition());
else if (!where.hasWhere() && semiAntiJoinPredicates == null)
;
else {
ConditionProviderImpl actual = new ConditionProviderImpl();
if (semiAntiJoinPredicates != null)
actual.addConditions(semiAntiJoinPredicates);
if (where.hasWhere())
actual.addConditions(where.getWhere());
context.formatSeparator().visit(K_WHERE).sql(' ').visit(actual);
}
context.end(SELECT_WHERE);
// GROUP BY and HAVING clause
// --------------------------
context.start(SELECT_GROUP_BY);
if (!getGroupBy().isEmpty()) {
context.formatSeparator().visit(K_GROUP_BY);
if (groupByDistinct)
context.sql(' ').visit(K_DISTINCT);
context.separatorRequired(true);
context.visit(groupBy);
}
context.end(SELECT_GROUP_BY);
// HAVING clause
// -------------
context.start(SELECT_HAVING);
if (getHaving().hasWhere())
context.formatSeparator().visit(K_HAVING).sql(' ').visit(getHaving());
context.end(SELECT_HAVING);
// WINDOW clause
// -------------
context.start(SELECT_WINDOW);
if (Tools.isNotEmpty(window) && !NO_SUPPORT_WINDOW_CLAUSE.contains(context.dialect()))
context.formatSeparator().visit(K_WINDOW).separatorRequired(true).declareWindows(true, c -> c.visit(window));
context.end(SELECT_WINDOW);
if (getQualify().hasWhere())
context.formatSeparator().visit(K_QUALIFY).sql(' ').visit(getQualify());
// ORDER BY clause for local subselect
// -----------------------------------
toSQLOrderBy(context, originalFields, alternativeFields, false, wrapQueryExpressionBodyInDerivedTable, orderBy, limit);
// --------------------------------------------
if (unionOpSize > 0) {
unionParenthesis(context, ')', null, derivedTableRequired(context, this), unionParensRequired);
for (int i = 0; i < unionOpSize; i++) {
CombineOperator op = unionOp.get(i);
for (Select<?> other : union.get(i)) {
boolean derivedTableRequired = derivedTableRequired(context, other);
context.formatSeparator().visit(op.toKeyword(family));
if (unionParensRequired)
context.sql(' ');
else
context.formatSeparator();
unionParenthesis(context, '(', other.getSelect(), derivedTableRequired, unionParensRequired);
context.visit(other);
unionParenthesis(context, ')', null, derivedTableRequired, unionParensRequired);
}
// [#1658] Close parentheses opened previously
if (i < unionOpSize - 1)
unionParenthesis(context, ')', null, derivedTableRequired(context, this), unionParensRequired);
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;
}
}
if (unionOpNesting)
context.data().remove(DATA_NESTED_SET_OPERATIONS);
}
if (wrapQueryExpressionBodyInDerivedTable) {
context.formatIndentEnd().formatNewLine().sql(") t");
if (applySeekOnDerivedTable) {
context.formatSeparator().visit(K_WHERE).sql(' ').qualify(false, c -> c.visit(getSeekCondition()));
}
}
// ORDER BY clause for UNION
// -------------------------
context.qualify(false, c -> toSQLOrderBy(context, originalFields, alternativeFields, wrapQueryExpressionInDerivedTable, wrapQueryExpressionBodyInDerivedTable, unionOrderBy, unionLimit));
}
use of org.jooq.Clause 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 ]");
}
Aggregations