Skip to content

Commit

Permalink
[#6485] Support parsing WITH with DML statements
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaseder committed Jan 26, 2018
1 parent 457b5bb commit 94e50fb
Showing 1 changed file with 40 additions and 27 deletions.
67 changes: 40 additions & 27 deletions jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
Expand Up @@ -309,6 +309,7 @@
import org.jooq.MergeFinalStep;
import org.jooq.MergeMatchedStep;
import org.jooq.MergeNotMatchedStep;
import org.jooq.MergeUsingStep;
import org.jooq.Name;
import org.jooq.OrderedAggregateFunction;
import org.jooq.OrderedAggregateFunctionOfDeferredType;
Expand Down Expand Up @@ -344,6 +345,7 @@
import org.jooq.TruncateIdentityStep;
import org.jooq.Update;
import org.jooq.UpdateReturningStep;
import org.jooq.UpdateSetFirstStep;
import org.jooq.User;
// ...
import org.jooq.WindowBeforeOverStep;
Expand Down Expand Up @@ -537,7 +539,7 @@ else if (!resultQuery && peekKeyword(ctx, "COMMENT ON"))
case 'd':
case 'D':
if (!resultQuery && peekKeyword(ctx, "DELETE"))
return parseDelete(ctx);
return parseDelete(ctx, null);
else if (!resultQuery && peekKeyword(ctx, "DROP"))
return parseDrop(ctx);
else if (!resultQuery && peekKeyword(ctx, "DO"))
Expand All @@ -564,14 +566,14 @@ else if (!resultQuery && peekKeyword(ctx, "EXEC"))
case 'i':
case 'I':
if (!resultQuery && peekKeyword(ctx, "INSERT"))
return parseInsert(ctx);
return parseInsert(ctx, null);

break;

case 'm':
case 'M':
if (!resultQuery && peekKeyword(ctx, "MERGE"))
return parseMerge(ctx);
return parseMerge(ctx, null);

break;

Expand Down Expand Up @@ -603,7 +605,7 @@ else if (!resultQuery && peekKeyword(ctx, "SET"))
case 'u':
case 'U':
if (!resultQuery && peekKeyword(ctx, "UPDATE"))
return parseUpdate(ctx);
return parseUpdate(ctx, null);
else if (!resultQuery && peekKeyword(ctx, "USE"))
return parseUse(ctx);

Expand Down Expand Up @@ -660,9 +662,19 @@ private static final Query parseWith(ParserContext ctx) {
while (parseIf(ctx, ','));

// TODO Better model API for WITH clause
return parseSelect(ctx, null, (WithImpl) new WithImpl(ctx.dsl.configuration(), recursive).with(cte.toArray(EMPTY_COMMON_TABLE_EXPRESSION)));

// TODO Other statements than SELECT
WithImpl with = (WithImpl) new WithImpl(ctx.dsl.configuration(), recursive).with(cte.toArray(EMPTY_COMMON_TABLE_EXPRESSION));
if (peekKeyword(ctx, "DELETE"))
return parseDelete(ctx, with);
else if (peekKeyword(ctx, "INSERT"))
return parseInsert(ctx, with);
else if (peekKeyword(ctx, "MERGE"))
return parseMerge(ctx, with);
else if (peekKeyword(ctx, "SELECT"))
return parseSelect(ctx, null, with);
else if (peekKeyword(ctx, "UPDATE"))
return parseUpdate(ctx, with);
else
throw ctx.unexpectedToken();
}

private static final SelectQueryImpl<Record> parseSelect(ParserContext ctx) {
Expand Down Expand Up @@ -1013,7 +1025,7 @@ else if (parseKeywordIf(ctx, "GROUPING SETS")) {
return result;
}

private static final Delete<?> parseDelete(ParserContext ctx) {
private static final Delete<?> parseDelete(ParserContext ctx, WithImpl with) {
parseKeyword(ctx, "DELETE");
parseKeywordIf(ctx, "FROM");
Table<?> tableName = parseTableName(ctx);
Expand All @@ -1023,7 +1035,7 @@ private static final Delete<?> parseDelete(ParserContext ctx) {
DeleteWhereStep<?> s1;
DeleteReturningStep<?> s2;

s1 = ctx.dsl.delete(tableName);
s1 = (with == null ? ctx.dsl.delete(tableName) : with.delete(tableName));
s2 = where
? s1.where(condition)
: s1;
Expand All @@ -1037,9 +1049,10 @@ private static final Delete<?> parseDelete(ParserContext ctx) {
return s2;
}

private static final Insert<?> parseInsert(ParserContext ctx) {
private static final Insert<?> parseInsert(ParserContext ctx, WithImpl with) {
parseKeyword(ctx, "INSERT INTO");
Table<?> tableName = parseTableName(ctx);
InsertSetStep<?> s1 = (with == null ? ctx.dsl.insertInto(tableName) : with.insertInto(tableName));
Field<?>[] fields = null;

if (parseIf(ctx, '(')) {
Expand Down Expand Up @@ -1071,14 +1084,13 @@ private static final Insert<?> parseInsert(ParserContext ctx) {
}
while (parseIf(ctx, ','));

InsertSetStep<?> step1 = ctx.dsl.insertInto(tableName);
if (allValues.isEmpty()) {
returning = onDuplicate = step1.defaultValues();
returning = onDuplicate = s1.defaultValues();
}
else {
InsertValuesStepN<?> step2 = (fields != null)
? step1.columns(fields)
: (InsertValuesStepN<?>) step1;
? s1.columns(fields)
: (InsertValuesStepN<?>) s1;

for (List<Field<?>> values : allValues)
step2 = step2.values(values);
Expand All @@ -1089,20 +1101,20 @@ private static final Insert<?> parseInsert(ParserContext ctx) {
else if (parseKeywordIf(ctx, "SET")) {
Map<Field<?>, Object> map = parseSetClauseList(ctx);

returning = onDuplicate = ctx.dsl.insertInto(tableName).set(map);
returning = onDuplicate = s1.set(map);
}
else if (peekKeyword(ctx, "SELECT", false, true, false)){
SelectQueryImpl<Record> select = parseSelect(ctx);

returning = onDuplicate = (fields == null)
? ctx.dsl.insertInto(tableName).select(select)
: ctx.dsl.insertInto(tableName).columns(fields).select(select);
? s1.select(select)
: s1.columns(fields).select(select);
}
else if (parseKeywordIf(ctx, "DEFAULT VALUES")) {
if (fields != null)
throw ctx.notImplemented("DEFAULT VALUES without INSERT field list");
else
returning = onDuplicate = ctx.dsl.insertInto(tableName).defaultValues();
returning = onDuplicate = s1.defaultValues();
}
else
throw ctx.unexpectedToken();
Expand Down Expand Up @@ -1154,9 +1166,10 @@ else if (parseKeywordIf(ctx, "UPDATE SET")) {
return returning;
}

private static final Update<?> parseUpdate(ParserContext ctx) {
private static final Update<?> parseUpdate(ParserContext ctx, WithImpl with) {
parseKeyword(ctx, "UPDATE");
Table<?> tableName = parseTableName(ctx);
UpdateSetFirstStep<?> s1 = (with == null ? ctx.dsl.update(tableName) : with.update(tableName));
parseKeyword(ctx, "SET");

// TODO Row value expression updates
Expand All @@ -1165,10 +1178,9 @@ private static final Update<?> parseUpdate(ParserContext ctx) {
// TODO support FROM
Condition condition = parseKeywordIf(ctx, "WHERE") ? parseCondition(ctx) : null;

// TODO support RETURNING
UpdateReturningStep<?> returning = condition == null
? ctx.dsl.update(tableName).set(map)
: ctx.dsl.update(tableName).set(map).where(condition);
? s1.set(map)
: s1.set(map).where(condition);

if (parseKeywordIf(ctx, "RETURNING"))
if (parseIf(ctx, '*'))
Expand Down Expand Up @@ -1197,7 +1209,7 @@ private static final Map<Field<?>, Object> parseSetClauseList(ParserContext ctx)
return map;
}

private static final Merge<?> parseMerge(ParserContext ctx) {
private static final Merge<?> parseMerge(ParserContext ctx, WithImpl with) {
parseKeyword(ctx, "MERGE INTO");
Table<?> target = parseTableName(ctx);

Expand Down Expand Up @@ -1255,11 +1267,12 @@ else if (!insert && (insert = parseKeywordIf(ctx, "WHEN NOT MATCHED THEN INSERT"
// TODO support multi clause MERGE
// TODO support DELETE

MergeMatchedStep<?> s1 = ctx.dsl.mergeInto(target).using(usingTable).on(on);
MergeNotMatchedStep<?> s2 = update ? s1.whenMatchedThenUpdate().set(updateSet) : s1;
MergeFinalStep<?> s3 = insert ? s2.whenNotMatchedThenInsert(insertColumns).values(insertValues) : s2;
MergeUsingStep<?> s1 = (with == null ? ctx.dsl.mergeInto(target) : with.mergeInto(target));
MergeMatchedStep<?> s2 = s1.using(usingTable).on(on);
MergeNotMatchedStep<?> s3 = update ? s2.whenMatchedThenUpdate().set(updateSet) : s2;
MergeFinalStep<?> s4 = insert ? s3.whenNotMatchedThenInsert(insertColumns).values(insertValues) : s3;

return s3;
return s4;
}

private static final Query parseSet(ParserContext ctx) {
Expand Down

0 comments on commit 94e50fb

Please sign in to comment.