table);
/**
- * Create a new DSL merge statement.
+ * Create a new DSL SQL standard MERGE statement.
*
* This statement is available from DSL syntax only. It is known to be
* supported in some way by any of these dialects:
@@ -610,10 +610,39 @@ public interface FactoryOperations extends Configuration {
* .values(value1, value2)
* .execute();
*
+ *
+ * Note: Using this method, you can also create an H2-specific MERGE
+ * statement without field specification. See also
+ * {@link #mergeInto(Table, Field...)}
*/
@Support({ DB2, HSQLDB, ORACLE, SQLSERVER, SYBASE })
MergeUsingStep mergeInto(Table table);
+ /**
+ * Create a new DSL merge statement (H2-specific syntax)
+ *
+ * This statement is available from DSL syntax only. It is known to be
+ * supported in some way by any of these dialects:
+ *
+ */
+ @Support(H2)
+ MergeKeyStep mergeInto(Table table, Field>... fields);
+
+ /**
+ * Create a new DSL merge statement (H2-specific syntax)
+ *
+ * @see #mergeInto(Table, Field...)
+ */
+ @Support(H2)
+ MergeKeyStep mergeInto(Table table, Collection extends Field>> fields);
+
/**
* Create a new {@link DeleteQuery}
*
diff --git a/jOOQ/src/main/java/org/jooq/MergeKeyStep.java b/jOOQ/src/main/java/org/jooq/MergeKeyStep.java
new file mode 100644
index 0000000000..998410c25f
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/MergeKeyStep.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
+ * All rights reserved.
+ *
+ * This software is licensed to you under the Apache License, Version 2.0
+ * (the "License"); You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name "jOOQ" nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jooq;
+
+import static org.jooq.SQLDialect.H2;
+
+import java.util.Collection;
+
+/**
+ * This type is used for the H2-specific variant of the {@link Merge}'s DSL API.
+ *
+ * Example:
+ * Factory create = new Factory();
+ *
+ * create.mergeInto(table, field1, field2)
+ * .key(id)
+ * .values(value1, value2)
+ * .execute();
+ *
+ *
+ * @author Lukas Eder
+ */
+public interface MergeKeyStep extends MergeValuesStep {
+
+ /**
+ * Specify an optional KEY clause.
+ *
+ * Use this optional clause in order to override using the underlying
+ * PRIMARY KEY.
+ */
+ @Support(H2)
+ MergeValuesStep key(Field>... keys);
+
+ /**
+ * Specify an optional KEY clause.
+ *
+ * Use this optional clause in order to override using the underlying
+ * PRIMARY KEY.
+ */
+ @Support(H2)
+ MergeValuesStep key(Collection extends Field>> keys);
+}
diff --git a/jOOQ/src/main/java/org/jooq/MergeUsingStep.java b/jOOQ/src/main/java/org/jooq/MergeUsingStep.java
index fb5cd12aa2..a1060a5766 100644
--- a/jOOQ/src/main/java/org/jooq/MergeUsingStep.java
+++ b/jOOQ/src/main/java/org/jooq/MergeUsingStep.java
@@ -46,7 +46,7 @@ import static org.jooq.SQLDialect.SYBASE;
*
* Example:
* Factory create = new Factory();
- *
+ *
* create.mergeInto(table)
* .using(select)
* .on(condition)
@@ -57,19 +57,21 @@ import static org.jooq.SQLDialect.SYBASE;
* .values(value1, value2)
* .execute();
*
- *
+ *
* @author Lukas Eder
*/
-public interface MergeUsingStep {
+public interface MergeUsingStep extends MergeKeyStep {
/**
- * Add the USING clause to the MERGE statement
+ * Add the USING clause to the SQL standard MERGE
+ * statement
*/
@Support({ DB2, HSQLDB, ORACLE, SQLSERVER, SYBASE })
MergeOnStep using(TableLike> table);
/**
- * Add a dummy USING clause to the MERGE statement
+ * Add a dummy USING clause to the SQL standard
+ * MERGE statement
*
* This results in USING(SELECT 1 FROM DUAL) for most RDBMS, or
* in USING(SELECT 1) AS [dummy_table(dummy_field)] in SQL
diff --git a/jOOQ/src/main/java/org/jooq/MergeValuesStep.java b/jOOQ/src/main/java/org/jooq/MergeValuesStep.java
new file mode 100644
index 0000000000..f255f9cf54
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/MergeValuesStep.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
+ * All rights reserved.
+ *
+ * This software is licensed to you under the Apache License, Version 2.0
+ * (the "License"); You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name "jOOQ" nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jooq;
+
+import static org.jooq.SQLDialect.H2;
+
+import java.util.Collection;
+
+/**
+ * This type is used for the H2-specific variant of the {@link Merge}'s DSL API.
+ *
+ * Example:
+ * Factory create = new Factory();
+ *
+ * create.mergeInto(table, field1, field2)
+ * .key(id)
+ * .values(value1, value2)
+ * .execute();
+ *
+ *
+ * @author Lukas Eder
+ */
+public interface MergeValuesStep {
+
+ /**
+ * Specify a VALUES clause
+ */
+ @Support(H2)
+ Merge values(Object... values);
+
+ /**
+ * Specify a VALUES clause
+ */
+ @Support(H2)
+ Merge values(Field>... values);
+
+ /**
+ * Specify a VALUES clause
+ */
+ @Support(H2)
+ Merge values(Collection> values);
+
+ /**
+ * Use a SELECT statement as the source of values for the
+ * MERGE statement
+ *
+ * This variant of the MERGE .. SELECT statement expects a
+ * select returning exactly as many fields as specified previously in the
+ * INTO clause:
+ * {@link FactoryOperations#mergeInto(Table, Field...)} or
+ * {@link FactoryOperations#mergeInto(Table, Collection)}
+ */
+ @Support(H2)
+ Merge select(Select> select);
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/Factory.java b/jOOQ/src/main/java/org/jooq/impl/Factory.java
index 7e3efb3d99..0b0d693133 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Factory.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Factory.java
@@ -104,6 +104,7 @@ import org.jooq.InsertQuery;
import org.jooq.InsertSetStep;
import org.jooq.InsertValuesStep;
import org.jooq.LoaderOptionsStep;
+import org.jooq.MergeKeyStep;
import org.jooq.MergeUsingStep;
import org.jooq.Name;
import org.jooq.OrderedAggregateFunction;
@@ -1844,6 +1845,22 @@ public class Factory implements FactoryOperations {
return new MergeImpl(this, table);
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MergeKeyStep mergeInto(Table table, Field>... fields) {
+ return mergeInto(table, Arrays.asList(fields));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MergeKeyStep mergeInto(Table table, Collection extends Field>> fields) {
+ return new MergeImpl(this, table, fields);
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/jOOQ/src/main/java/org/jooq/impl/FactoryProxy.java b/jOOQ/src/main/java/org/jooq/impl/FactoryProxy.java
index 1428d6c657..cbb0fc1696 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FactoryProxy.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FactoryProxy.java
@@ -60,6 +60,7 @@ import org.jooq.InsertQuery;
import org.jooq.InsertSetStep;
import org.jooq.InsertValuesStep;
import org.jooq.LoaderOptionsStep;
+import org.jooq.MergeKeyStep;
import org.jooq.MergeUsingStep;
import org.jooq.Query;
import org.jooq.QueryPart;
@@ -326,6 +327,16 @@ public final class FactoryProxy implements FactoryOperations {
return getDelegate().mergeInto(table);
}
+ @Override
+ public final MergeKeyStep mergeInto(Table table, Field>... fields) {
+ return getDelegate().mergeInto(table, fields);
+ }
+
+ @Override
+ public final MergeKeyStep mergeInto(Table table, Collection extends Field>> fields) {
+ return getDelegate().mergeInto(table, fields);
+ }
+
@Override
public final DeleteQuery deleteQuery(Table table) {
return getDelegate().deleteQuery(table);
diff --git a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java
index baad69d472..5201e30e99 100644
--- a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.SQLDialect.H2;
import static org.jooq.impl.Factory.condition;
import static org.jooq.impl.Factory.exists;
import static org.jooq.impl.Factory.notExists;
@@ -63,14 +64,18 @@ import org.jooq.MergeOnConditionStep;
import org.jooq.MergeOnStep;
import org.jooq.MergeUsingStep;
import org.jooq.Operator;
+import org.jooq.QueryPart;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.TableLike;
+import org.jooq.exception.SQLDialectNotSupportedException;
import org.jooq.tools.StringUtils;
/**
+ * The SQL standard MERGE statement
+ *
* @author Lukas Eder
*/
class MergeImpl extends AbstractQuery
@@ -105,15 +110,110 @@ implements
private boolean notMatchedClause;
private FieldMapForInsert notMatchedInsert;
+ // Objects for the H2-specific syntax
+ private boolean h2Style;
+ private FieldList h2Fields;
+ private FieldList h2Keys;
+ private FieldList h2Values;
+ private Select> h2Select;
+
MergeImpl(Configuration configuration, Table table) {
+ this(configuration, table, null);
+ }
+
+ MergeImpl(Configuration configuration, Table table, Collection extends Field>> fields) {
super(configuration);
this.table = table;
this.on = new ConditionProviderImpl();
+
+ if (fields != null) {
+ h2Style = true;
+ h2Fields = new FieldList(fields);
+ }
}
// -------------------------------------------------------------------------
- // QueryPart API
+ // H2-specific MERGE API
+ // -------------------------------------------------------------------------
+
+ FieldList getH2Fields() {
+ if (h2Fields == null) {
+ h2Fields = new FieldList();
+ h2Fields.addAll(table.getFields());
+ }
+
+ return h2Fields;
+ }
+
+ FieldList getH2Keys() {
+ if (h2Keys == null) {
+ h2Keys = new FieldList();
+ }
+
+ return h2Keys;
+ }
+
+ FieldList getH2Values() {
+ if (h2Values == null) {
+ h2Values = new FieldList();
+ }
+
+ return h2Values;
+ }
+
+ @Override
+ public final MergeImpl select(Select> select) {
+ h2Style = true;
+ h2Select = select;
+ return this;
+ }
+
+ @Override
+ public final MergeImpl key(Field>... k) {
+ return key(Arrays.asList(k));
+ }
+
+ @Override
+ public final MergeImpl key(Collection extends Field>> keys) {
+ h2Style = true;
+ getH2Keys().addAll(keys);
+ return this;
+ }
+
+ // -------------------------------------------------------------------------
+ // Shared MERGE API
+ // -------------------------------------------------------------------------
+
+ @Override
+ public final MergeImpl values(Object... values) {
+
+ // [#1541] The VALUES() clause is also supported in the H2-specific
+ // syntax, in case of which, the USING() was not added
+ if (using == null) {
+ h2Style = true;
+ getH2Values().addAll(vals(convert(getH2Fields(), values)));
+ }
+ else {
+ List> fields = new ArrayList>(notMatchedInsert.keySet());
+ notMatchedInsert.putValues(vals(convert(fields, values)));
+ }
+
+ return this;
+ }
+
+ @Override
+ public final MergeImpl values(Field>... values) {
+ return values((Object[]) values);
+ }
+
+ @Override
+ public final MergeImpl values(Collection> values) {
+ return values(values.toArray());
+ }
+
+ // -------------------------------------------------------------------------
+ // Merge API
// -------------------------------------------------------------------------
@Override
@@ -270,23 +370,6 @@ implements
return this;
}
- @Override
- public final MergeImpl values(Object... values) {
- List> fields = new ArrayList>(notMatchedInsert.keySet());
- notMatchedInsert.putValues(vals(convert(fields, values)));
- return this;
- }
-
- @Override
- public final MergeImpl values(Field>... values) {
- return values((Object[]) values);
- }
-
- @Override
- public final MergeImpl values(Collection> values) {
- return values(values.toArray());
- }
-
@Override
public final MergeImpl where(Condition condition) {
if (matchedClause) {
@@ -314,6 +397,46 @@ implements
@Override
public final void toSQL(RenderContext context) {
+ if (h2Style) {
+ toSQLH2(context);
+ }
+ else {
+ toSQLStandard(context);
+ }
+ }
+
+ private final void toSQLH2(RenderContext context) {
+ if (context.getDialect() != H2) {
+ throw new SQLDialectNotSupportedException("The H2-specific MERGE syntax is only supported in H2");
+ }
+
+ context.keyword("merge into ")
+ .declareTables(true)
+ .sql(table)
+ .formatSeparator();
+
+ context.sql("(");
+ Util.toSQLNames(context, getH2Fields());
+ context.sql(")");
+
+ if (!getH2Keys().isEmpty()) {
+ context.keyword(" key (");
+ Util.toSQLNames(context, getH2Keys());
+ context.sql(")");
+ }
+
+ if (h2Select != null) {
+ context.sql(" ")
+ .sql(h2Select);
+ }
+ else {
+ context.keyword(" values (")
+ .sql(getH2Values())
+ .sql(")");
+ }
+ }
+
+ private final void toSQLStandard(RenderContext context) {
context.keyword("merge into ")
.declareTables(true)
.sql(table)
@@ -405,6 +528,25 @@ implements
@Override
public final void bind(BindContext context) {
+ if (h2Style) {
+ bindH2(context);
+ }
+ else {
+ bindStandard(context);
+ }
+ }
+
+ private final void bindH2(BindContext context) {
+ context.declareTables(true)
+ .bind(table)
+ .declareTables(false)
+ .bind((QueryPart) getH2Fields())
+ .bind((QueryPart) getH2Keys())
+ .bind(h2Select)
+ .bind((QueryPart) getH2Values());
+ }
+
+ private final void bindStandard(BindContext context) {
context.declareTables(true)
.bind(table)
.bind(using)
@@ -425,6 +567,10 @@ implements
matchedWhere,
matchedDeleteWhere,
notMatchedInsert,
- notMatchedWhere);
+ notMatchedWhere,
+ h2Fields,
+ h2Keys,
+ h2Select,
+ h2Values);
}
}