From 094be3cdfbf6651d176efce85857de9ca6365825 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 12 Aug 2013 16:09:24 +0200 Subject: [PATCH] [#2665] Implement SPI for RenderContext and BindContext listening to allow for custom SQL transformation * INSERT statement refactoring to correctly implement clause events. --- .../java/org/jooq/impl/FieldMapForInsert.java | 66 ++++++++----------- .../org/jooq/impl/FieldMapsForInsert.java | 23 +++++-- .../java/org/jooq/impl/InsertQueryImpl.java | 9 ++- .../main/java/org/jooq/impl/MergeImpl.java | 6 +- .../java/org/jooq/test/VisitContextTest.java | 21 ++++-- 5 files changed, 69 insertions(+), 56 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java index 2bcc59678c..a9557cb257 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java @@ -35,8 +35,6 @@ */ package org.jooq.impl; -import static org.jooq.Clause.DUMMY; -import static org.jooq.Clause.INSERT_VALUES; import static org.jooq.impl.Utils.visitAll; import java.util.Collection; @@ -64,13 +62,32 @@ class FieldMapForInsert extends AbstractQueryPartMap, Field> { @Override public final void toSQL(RenderContext context) { - toSQLReferenceKeys(context); - context.formatSeparator() - .start(INSERT_VALUES) - .keyword("values") - .sql(" "); - toSQLReferenceValues(context); - context.end(INSERT_VALUES); + boolean indent = (size() > 1); + + context.sql("("); + + if (indent) { + context.formatIndentStart(); + } + + String separator = ""; + for (Field field : values()) { + context.sql(separator); + + if (indent) { + context.formatNewLine(); + } + + context.visit(field); + separator = ", "; + } + + if (indent) { + context.formatIndentEnd() + .formatNewLine(); + } + + context.sql(")"); } final void toSQLReferenceKeys(RenderContext context) { @@ -108,35 +125,6 @@ class FieldMapForInsert extends AbstractQueryPartMap, Field> { context.sql(")"); } - final void toSQLReferenceValues(RenderContext context) { - boolean indent = (size() > 1); - - context.sql("("); - - if (indent) { - context.formatIndentStart(); - } - - String separator = ""; - for (Field field : values()) { - context.sql(separator); - - if (indent) { - context.formatNewLine(); - } - - context.visit(field); - separator = ", "; - } - - if (indent) { - context.formatIndentEnd() - .formatNewLine(); - } - - context.sql(")"); - } - @Override public final void bind(BindContext context) { visitAll(context, keySet()); @@ -145,7 +133,7 @@ class FieldMapForInsert extends AbstractQueryPartMap, Field> { @Override public final Clause[] clauses(Context ctx) { - return new Clause[] { DUMMY }; + return null; } final void putFields(Collection> fields) { diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java index 04de579624..b2e6f238e9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java @@ -36,6 +36,7 @@ package org.jooq.impl; import static org.jooq.Clause.INSERT_SELECT; +import static org.jooq.Clause.INSERT_VALUES; import static org.jooq.impl.Utils.visitAll; import java.util.ArrayList; @@ -56,9 +57,9 @@ class FieldMapsForInsert extends AbstractQueryPart { /** * Generated UID */ - private static final long serialVersionUID = -6227074228534414225L; + private static final long serialVersionUID = -6227074228534414225L; - private final List insertMaps; + final List insertMaps; FieldMapsForInsert() { insertMaps = new ArrayList(); @@ -77,7 +78,12 @@ class FieldMapsForInsert extends AbstractQueryPart { // Single record inserts can use the standard syntax in any dialect else if (insertMaps.size() == 1 || insertMaps.get(1) == null) { - context.visit(insertMaps.get(0)); + context.formatSeparator() + .start(INSERT_VALUES) + .keyword("values") + .sql(" ") + .visit(insertMaps.get(0)) + .end(INSERT_VALUES); } // True SQL92 multi-record inserts aren't always supported @@ -97,7 +103,12 @@ class FieldMapsForInsert extends AbstractQueryPart { break; default: + context.formatSeparator() + .start(INSERT_VALUES) + .keyword("values") + .sql(" "); toSQL92Values(context); + context.end(INSERT_VALUES); break; } @@ -105,8 +116,7 @@ class FieldMapsForInsert extends AbstractQueryPart { } private void toSQLInsertSelect(RenderContext context) { - insertMaps.get(0).toSQLReferenceKeys(context); - context.sql(" "); + context.start(INSERT_SELECT); Select select = null; for (FieldMapForInsert map : insertMaps) { @@ -123,6 +133,7 @@ class FieldMapsForInsert extends AbstractQueryPart { } context.visit(select); + context.end(INSERT_SELECT); } private void toSQL92Values(RenderContext context) { @@ -132,7 +143,7 @@ class FieldMapsForInsert extends AbstractQueryPart { for (FieldMapForInsert map : insertMaps) { if (map != null && i > 0) { context.sql(", "); - map.toSQLReferenceValues(context); + context.visit(map); } i++; diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java index 6094a16771..b6fe7d9ba8 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java @@ -39,6 +39,7 @@ package org.jooq.impl; import static java.util.Arrays.asList; import static org.jooq.Clause.INSERT; import static org.jooq.Clause.INSERT_INSERT_INTO; +import static org.jooq.Clause.INSERT_ON_DUPLICATE_KEY_UPDATE; import static org.jooq.Clause.INSERT_ON_DUPLICATE_KEY_UPDATE_ASSIGNMENT; import static org.jooq.Clause.INSERT_RETURNING; import static org.jooq.SQLDialect.MARIADB; @@ -152,9 +153,11 @@ class InsertQueryImpl extends AbstractStoreQuery implements case MYSQL: { toSQLInsert(context); context.formatSeparator() + .start(INSERT_ON_DUPLICATE_KEY_UPDATE) .keyword("on duplicate key update") .sql(" ") - .visit(updateMap); + .visit(updateMap) + .end(INSERT_ON_DUPLICATE_KEY_UPDATE); break; } @@ -336,8 +339,10 @@ class InsertQueryImpl extends AbstractStoreQuery implements .keyword("into") .sql(" ") .visit(getInto()) + .sql(" "); + insertMaps.insertMaps.get(0).toSQLReferenceKeys(context); + context.sql(" ") .end(INSERT_INSERT_INTO) - .sql(" ") .visit(insertMaps); context.start(INSERT_RETURNING); diff --git a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java index a1f25b59fd..d70ffc3614 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java @@ -1145,8 +1145,10 @@ implements // [#999] WHEN NOT MATCHED clause is optional if (notMatchedInsert != null) { context.formatSeparator() - .keyword("when not matched then insert").sql(" ") - .visit(notMatchedInsert); + .keyword("when not matched then insert").sql(" "); + notMatchedInsert.toSQLReferenceKeys(context); + context.formatSeparator().keyword("values") + .sql(" ").visit(notMatchedInsert); } // [#998] Oracle MERGE extension: WHEN NOT MATCHED THEN INSERT .. WHERE diff --git a/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java b/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java index 12b227998a..c7e56ffa5f 100644 --- a/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java +++ b/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java @@ -59,6 +59,7 @@ import static org.jooq.Clause.FIELD_ROW; import static org.jooq.Clause.FIELD_VALUE; import static org.jooq.Clause.INSERT; import static org.jooq.Clause.INSERT_INSERT_INTO; +import static org.jooq.Clause.INSERT_RETURNING; import static org.jooq.Clause.INSERT_VALUES; import static org.jooq.Clause.SELECT; import static org.jooq.Clause.SELECT_CONNECT_BY; @@ -215,14 +216,20 @@ public class VisitContextTest extends AbstractTest { asList(INSERT, INSERT_INSERT_INTO), asList(INSERT, INSERT_INSERT_INTO, TABLE), asList(INSERT, INSERT_INSERT_INTO, TABLE, TABLE_REFERENCE), + asList(INSERT, INSERT_INSERT_INTO, FIELD), + asList(INSERT, INSERT_INSERT_INTO, FIELD, FIELD_REFERENCE), + asList(INSERT, INSERT_INSERT_INTO, FIELD), + asList(INSERT, INSERT_INSERT_INTO, FIELD, FIELD_REFERENCE), + asList(INSERT, INSERT_INSERT_INTO, FIELD), + asList(INSERT, INSERT_INSERT_INTO, FIELD, FIELD_REFERENCE), asList(INSERT, INSERT_VALUES), - asList(INSERT, INSERT_VALUES, FIELD_ROW), - asList(INSERT, INSERT_VALUES, FIELD_ROW, FIELD), - asList(INSERT, INSERT_VALUES, FIELD_ROW, FIELD, FIELD_VALUE), - asList(INSERT, INSERT_VALUES, FIELD_ROW, FIELD), - asList(INSERT, INSERT_VALUES, FIELD_ROW, FIELD, FIELD_VALUE), - asList(INSERT, INSERT_VALUES, FIELD_ROW, FIELD), - asList(INSERT, INSERT_VALUES, FIELD_ROW, FIELD, FIELD_VALUE) + asList(INSERT, INSERT_VALUES, FIELD), + asList(INSERT, INSERT_VALUES, FIELD, FIELD_VALUE), + asList(INSERT, INSERT_VALUES, FIELD), + asList(INSERT, INSERT_VALUES, FIELD, FIELD_VALUE), + asList(INSERT, INSERT_VALUES, FIELD), + asList(INSERT, INSERT_VALUES, FIELD, FIELD_VALUE), + asList(INSERT, INSERT_RETURNING) )); }