use of org.jooq.InsertOnConflictDoUpdateStep in project jOOQ by jOOQ.
the class DefaultParseContext method parseInsert.
private final Query parseInsert(WithImpl with, boolean parseResultQuery) {
scopeStart();
parseKeyword("INSERT", "INS");
parseKeywordIf("INTO");
Table<?> table = parseTableNameIf();
if (table == null)
table = table(parseSelect());
Name alias;
if (parseKeywordIf("AS"))
table = table.as(parseIdentifier());
else if (!peekKeyword("DEFAULT VALUES", "SEL", "SELECT", "SET", "VALUES") && (alias = parseIdentifierIf()) != null)
table = table.as(alias);
scope(table);
InsertSetStep<?> s1 = (with == null ? dsl.insertInto(table) : with.insertInto(table));
Field<?>[] fields = null;
if (!peekSelectOrWith(true) && parseIf('(') && !parseIf(')')) {
fields = parseList(',', c -> parseField()).toArray(EMPTY_FIELD);
parse(')');
}
InsertOnDuplicateStep<?> onDuplicate;
InsertReturningStep<?> returning;
try {
// [#11821] The Teradata INSERT INTO t (1, 2) syntax can be recognised:
// When there are non-references fields
boolean hasExpressions = anyMatch(fields, f -> !(f instanceof TableField));
if (hasExpressions || parseKeywordIf("VALUES")) {
List<List<Field<?>>> allValues = new ArrayList<>();
if (hasExpressions) {
allValues.add(asList(fields));
fields = null;
}
valuesLoop: do {
if (hasExpressions && !parseIf(','))
break valuesLoop;
parse('(');
// [#6936] MySQL treats an empty VALUES() clause as the same thing as the standard DEFAULT VALUES
if (fields == null && parseIf(')'))
break valuesLoop;
List<Field<?>> values = parseList(',', c -> c.parseKeywordIf("DEFAULT") ? default_() : c.parseField());
if (fields != null && fields.length != values.size())
throw exception("Insert field size (" + fields.length + ") must match values size (" + values.size() + ")");
allValues.add(values);
parse(')');
} while (parseIf(','));
InsertValuesStepN<?> step2 = (fields != null) ? s1.columns(fields) : (InsertValuesStepN<?>) s1;
for (List<Field<?>> values : allValues) step2 = step2.values(values);
returning = onDuplicate = step2;
} else if (parseKeywordIf("SET")) {
Map<Field<?>, Object> map = parseSetClauseList();
returning = onDuplicate = s1.set(map);
} else if (peekSelectOrWith(true)) {
// [#10954] These are moved into the INSERT .. SELECT clause handling. They should not be necessary here
// either, but it seems we currently don't correctly implement nesting scopes?
scopeEnd(null);
scopeStart();
Select<?> select = parseWithOrSelect();
returning = onDuplicate = (fields == null) ? s1.select(select) : s1.columns(fields).select(select);
} else if (parseKeywordIf("DEFAULT VALUES")) {
if (fields != null)
throw notImplemented("DEFAULT VALUES without INSERT field list");
else
returning = onDuplicate = s1.defaultValues();
} else
throw expected("DEFAULT VALUES", "WITH", "SELECT", "SET", "VALUES");
if (parseKeywordIf("ON")) {
if (parseKeywordIf("DUPLICATE KEY UPDATE")) {
parseKeywordIf("SET");
InsertOnConflictWhereStep<?> where = onDuplicate.onDuplicateKeyUpdate().set(parseSetClauseList());
if (parseKeywordIf("WHERE"))
returning = where.where(parseCondition());
else
returning = where;
} else if (parseKeywordIf("DUPLICATE KEY IGNORE")) {
returning = onDuplicate.onDuplicateKeyIgnore();
} else if (parseKeywordIf("CONFLICT")) {
InsertOnConflictDoUpdateStep<?> doUpdate;
if (parseKeywordIf("ON CONSTRAINT")) {
doUpdate = onDuplicate.onConflictOnConstraint(parseName());
} else if (parseIf('(')) {
InsertOnConflictWhereIndexPredicateStep<?> where = onDuplicate.onConflict(parseList(',', c -> parseFieldName()));
parse(')');
doUpdate = parseKeywordIf("WHERE") ? where.where(parseCondition()) : where;
} else {
doUpdate = onDuplicate.onConflict();
}
parseKeyword("DO");
if (parseKeywordIf("NOTHING")) {
returning = doUpdate.doNothing();
} else if (parseKeywordIf("UPDATE SET")) {
InsertOnConflictWhereStep<?> where = doUpdate.doUpdate().set(parseSetClauseList());
if (parseKeywordIf("WHERE"))
returning = where.where(parseCondition());
else
returning = where;
} else
throw expected("NOTHING", "UPDATE");
} else
throw expected("CONFLICT", "DUPLICATE");
}
return (parseResultQuery ? parseKeyword("RETURNING") : parseKeywordIf("RETURNING")) ? returning.returning(parseSelectList()) : returning;
} finally {
scopeEnd(((InsertImpl) s1).getDelegate());
}
}
Aggregations