[#2665] Implement SPI for RenderContext and BindContext listening to

allow for custom SQL transformation

 * INSERT statement refactoring to correctly implement clause events.
This commit is contained in:
Lukas Eder 2013-08-12 16:09:24 +02:00
parent 1c4c459076
commit 094be3cdfb
5 changed files with 69 additions and 56 deletions

View File

@ -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<?>, 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<?>, 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<?>, Field<?>> {
@Override
public final Clause[] clauses(Context<?> ctx) {
return new Clause[] { DUMMY };
return null;
}
final void putFields(Collection<? extends Field<?>> fields) {

View File

@ -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<FieldMapForInsert> insertMaps;
final List<FieldMapForInsert> insertMaps;
FieldMapsForInsert() {
insertMaps = new ArrayList<FieldMapForInsert>();
@ -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<Record> 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++;

View File

@ -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<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> 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);

View File

@ -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

View File

@ -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)
));
}