Repository: ignite
Updated Branches:
  refs/heads/ignite-6022-proto [created] 771422cb1


IGNITE-4490 Query-less INSERT and MERGE


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d362da5f
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d362da5f
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d362da5f

Branch: refs/heads/ignite-6022-proto
Commit: d362da5fdb0671d17672b0096d064ce30254638f
Parents: c040c37
Author: Alexander Paschenko <[email protected]>
Authored: Mon Dec 26 18:39:10 2016 +0300
Committer: Alexander Paschenko <[email protected]>
Committed: Mon Dec 26 18:39:10 2016 +0300

----------------------------------------------------------------------
 .../query/h2/DmlStatementsProcessor.java        | 91 +++++++++++++++-----
 .../query/h2/dml/FastUpdateArguments.java       | 36 ++++++++
 .../processors/query/h2/dml/UpdatePlan.java     | 43 +++++----
 .../query/h2/dml/UpdatePlanBuilder.java         | 59 +++++++++----
 .../processors/query/h2/sql/DmlAstUtils.java    | 55 +++---------
 .../IgniteCacheUpdateSqlQuerySelfTest.java      |  2 -
 6 files changed, 184 insertions(+), 102 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/d362da5f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
index 4030758..f660148 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
@@ -58,6 +58,7 @@ import 
org.apache.ignite.internal.processors.query.GridQueryFieldsResultAdapter;
 import org.apache.ignite.internal.processors.query.GridQueryProperty;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.h2.dml.FastUpdateArgument;
 import org.apache.ignite.internal.processors.query.h2.dml.FastUpdateArguments;
 import org.apache.ignite.internal.processors.query.h2.dml.KeyValueSupplier;
 import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlan;
@@ -241,13 +242,15 @@ public class DmlStatementsProcessor {
             return new UpdateResult(doSingleUpdate(plan, params), 
X.EMPTY_OBJECT_ARRAY);
         }
 
-        assert !F.isEmpty(plan.selectQry);
+        assert !F.isEmpty(plan.rows) ^ !F.isEmpty(plan.selectQry);
 
-        QueryCursorImpl<List<?>> cur;
+        Iterable<List<?>> cur;
 
         // Do a two-step query only if locality flag is not set AND if plan's 
SELECT corresponds to an actual
         // subquery and not some dummy stuff like "select 1, 2, 3;"
         if (!loc && !plan.isLocSubqry) {
+            assert !F.isEmpty(plan.selectQry);
+
             SqlFieldsQuery newFieldsQry = new SqlFieldsQuery(plan.selectQry, 
fieldsQry.isCollocated())
                 .setArgs(params)
                 .setDistributedJoins(fieldsQry.isDistributedJoins())
@@ -256,13 +259,13 @@ public class DmlStatementsProcessor {
                 .setPageSize(fieldsQry.getPageSize())
                 .setTimeout(fieldsQry.getTimeout(), TimeUnit.MILLISECONDS);
 
-            cur = (QueryCursorImpl<List<?>>) indexing.queryTwoStep(cctx, 
newFieldsQry, cancel);
+            cur = indexing.queryTwoStep(cctx, newFieldsQry, cancel);
         }
-        else {
+        else if (F.isEmpty(plan.rows)) {
             final GridQueryFieldsResult res = 
indexing.queryLocalSqlFields(cctx.name(), plan.selectQry, F.asList(params),
                 filters, fieldsQry.isEnforceJoinOrder(), 
fieldsQry.getTimeout(), cancel);
 
-            cur = new QueryCursorImpl<>(new Iterable<List<?>>() {
+            QueryCursorImpl<List<?>> resCur = new QueryCursorImpl<>(new 
Iterable<List<?>>() {
                 @Override public Iterator<List<?>> iterator() {
                     try {
                         return new 
GridQueryCacheObjectsIterator(res.iterator(), cctx, cctx.keepBinary());
@@ -273,7 +276,34 @@ public class DmlStatementsProcessor {
                 }
             }, cancel);
 
-            cur.fieldsMeta(res.metaData());
+            resCur.fieldsMeta(res.metaData());
+
+            cur = resCur;
+        }
+        else {
+            assert plan.rowsNum > 0 && !F.isEmpty(plan.colNames);
+
+            List<List<?>> args = new ArrayList<>(plan.rowsNum);
+
+            GridH2RowDescriptor desc = plan.tbl.rowDescriptor();
+
+            for (List<FastUpdateArgument> argRow : plan.rows) {
+                List<Object> row = new ArrayList<>();
+
+                for (int j = 0; j < plan.colNames.length; j++) {
+                    Object colVal = argRow.get(j).apply(fieldsQry.getArgs());
+
+                    if (j == plan.keyColIdx || j == plan.valColIdx)
+                        colVal = convert(colVal, j == plan.keyColIdx ? 
desc.type().keyClass() : desc.type().valueClass(),
+                            desc);
+
+                    row.add(colVal);
+                }
+
+                args.add(row);
+            }
+
+            cur = args;
         }
 
         int pageSize = loc ? 0 : fieldsQry.getPageSize();
@@ -379,7 +409,7 @@ public class DmlStatementsProcessor {
      * @return Results of DELETE (number of items affected AND keys that 
failed to be updated).
      */
     @SuppressWarnings({"unchecked", "ConstantConditions", 
"ThrowableResultOfMethodCallIgnored"})
-    private UpdateResult doDelete(GridCacheContext cctx, 
QueryCursorImpl<List<?>> cursor, int pageSize)
+    private UpdateResult doDelete(GridCacheContext cctx, Iterable<List<?>> 
cursor, int pageSize)
         throws IgniteCheckedException {
         // With DELETE, we have only two columns - key and value.
         long res = 0;
@@ -449,7 +479,7 @@ public class DmlStatementsProcessor {
      *     had been modified concurrently (arguments for a re-run)].
      */
     @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
-    private UpdateResult doUpdate(UpdatePlan plan, QueryCursorImpl<List<?>> 
cursor, int pageSize)
+    private UpdateResult doUpdate(UpdatePlan plan, Iterable<List<?>> cursor, 
int pageSize)
         throws IgniteCheckedException {
         GridH2RowDescriptor desc = plan.tbl.rowDescriptor();
 
@@ -492,7 +522,7 @@ public class DmlStatementsProcessor {
                     continue;
 
                 newColVals.put(plan.colNames[i], convert(e.get(i + 2), 
plan.colNames[i],
-                    plan.tbl.rowDescriptor(), plan.colTypes[i]));
+                    plan.tbl.rowDescriptor()));
             }
 
             newVal = plan.valSupplier.apply(e);
@@ -585,12 +615,11 @@ public class DmlStatementsProcessor {
      * @param val Source value.
      * @param colName Column name to search for property.
      * @param desc Row descriptor.
-     * @param type Expected column type to convert to.
      * @return Converted object.
      * @throws IgniteCheckedException if failed.
      */
     @SuppressWarnings({"ConstantConditions", "SuspiciousSystemArraycopy"})
-    private static Object convert(Object val, String colName, 
GridH2RowDescriptor desc, int type)
+    private static Object convert(Object val, String colName, 
GridH2RowDescriptor desc)
         throws IgniteCheckedException {
         if (val == null)
             return null;
@@ -601,6 +630,21 @@ public class DmlStatementsProcessor {
 
         Class<?> expCls = prop.type();
 
+        return convert(val, expCls, desc);
+    }
+
+    /**
+     * Convert value to column's expected type by means of H2.
+     *
+     * @param val Source value.
+     * @param expCls Expected property class.
+     * @param desc Row descriptor.
+     * @return Converted object.
+     * @throws IgniteCheckedException if failed.
+     */
+    @SuppressWarnings({"ConstantConditions", "SuspiciousSystemArraycopy"})
+    private static Object convert(Object val, Class<?> expCls, 
GridH2RowDescriptor desc)
+        throws IgniteCheckedException {
         Class<?> currCls = val.getClass();
 
         if (val instanceof Date && currCls != Date.class && expCls == 
Date.class) {
@@ -609,6 +653,8 @@ public class DmlStatementsProcessor {
             return new Date(((Date) val).getTime());
         }
 
+        int type = DataType.getTypeFromClass(expCls);
+
         // We have to convert arrays of reference types manually - see 
https://issues.apache.org/jira/browse/IGNITE-4327
         // Still, we only can convert from Object[] to something more precise.
         if (type == Value.ARRAY && currCls != expCls) {
@@ -689,14 +735,14 @@ public class DmlStatementsProcessor {
      * @throws IgniteCheckedException if failed.
      */
     @SuppressWarnings("unchecked")
-    private long doMerge(UpdatePlan plan, QueryCursorImpl<List<?>> cursor, int 
pageSize) throws IgniteCheckedException {
+    private long doMerge(UpdatePlan plan, Iterable<List<?>> cursor, int 
pageSize) throws IgniteCheckedException {
         GridH2RowDescriptor desc = plan.tbl.rowDescriptor();
 
         GridCacheContext cctx = desc.context();
 
         // If we have just one item to put, just do so
         if (plan.rowsNum == 1) {
-            IgniteBiTuple t = rowToKeyValue(cctx, 
cursor.iterator().next().toArray(), plan.colNames, plan.colTypes, 
plan.keySupplier,
+            IgniteBiTuple t = rowToKeyValue(cctx, 
cursor.iterator().next().toArray(), plan.colNames, plan.keySupplier,
                 plan.valSupplier, plan.keyColIdx, plan.valColIdx, desc);
 
             cctx.cache().put(t.getKey(), t.getValue());
@@ -709,7 +755,7 @@ public class DmlStatementsProcessor {
             for (Iterator<List<?>> it = cursor.iterator(); it.hasNext();) {
                 List<?> row = it.next();
 
-                IgniteBiTuple t = rowToKeyValue(cctx, row.toArray(), 
plan.colNames, plan.colTypes, plan.keySupplier, plan.valSupplier,
+                IgniteBiTuple t = rowToKeyValue(cctx, row.toArray(), 
plan.colNames, plan.keySupplier, plan.valSupplier,
                     plan.keyColIdx, plan.valColIdx, desc);
 
                 rows.put(t.getKey(), t.getValue());
@@ -735,14 +781,14 @@ public class DmlStatementsProcessor {
      * @throws IgniteCheckedException if failed, particularly in case of 
duplicate keys.
      */
     @SuppressWarnings({"unchecked", "ConstantConditions"})
-    private long doInsert(UpdatePlan plan, QueryCursorImpl<List<?>> cursor, 
int pageSize) throws IgniteCheckedException {
+    private long doInsert(UpdatePlan plan, Iterable<List<?>> cursor, int 
pageSize) throws IgniteCheckedException {
         GridH2RowDescriptor desc = plan.tbl.rowDescriptor();
 
         GridCacheContext cctx = desc.context();
 
         // If we have just one item to put, just do so
         if (plan.rowsNum == 1) {
-            IgniteBiTuple t = rowToKeyValue(cctx, 
cursor.iterator().next().toArray(), plan.colNames, plan.colTypes,
+            IgniteBiTuple t = rowToKeyValue(cctx, 
cursor.iterator().next().toArray(), plan.colNames,
                 plan.keySupplier, plan.valSupplier, plan.keyColIdx, 
plan.valColIdx, desc);
 
             if (cctx.cache().putIfAbsent(t.getKey(), t.getValue()))
@@ -768,7 +814,7 @@ public class DmlStatementsProcessor {
             while (it.hasNext()) {
                 List<?> row = it.next();
 
-                final IgniteBiTuple t = rowToKeyValue(cctx, row.toArray(), 
plan.colNames, plan.colTypes, plan.keySupplier,
+                final IgniteBiTuple t = rowToKeyValue(cctx, row.toArray(), 
plan.colNames, plan.keySupplier,
                     plan.valSupplier, plan.keyColIdx, plan.valColIdx, desc);
 
                 rows.put(t.getKey(), new InsertEntryProcessor(t.getValue()));
@@ -838,7 +884,6 @@ public class DmlStatementsProcessor {
      * @param cctx Cache context.
      * @param row Row to process.
      * @param cols Query cols.
-     * @param colTypes Column types to convert data from {@code row} to.
      * @param keySupplier Key instantiation method.
      * @param valSupplier Key instantiation method.
      * @param keyColIdx Key column index, or {@code -1} if no key column is 
mentioned in {@code cols}.
@@ -848,10 +893,12 @@ public class DmlStatementsProcessor {
      */
     @SuppressWarnings({"unchecked", "ConstantConditions", 
"ResultOfMethodCallIgnored"})
     private IgniteBiTuple<?, ?> rowToKeyValue(GridCacheContext cctx, Object[] 
row, String[] cols,
-        int[] colTypes, KeyValueSupplier keySupplier, KeyValueSupplier 
valSupplier, int keyColIdx, int valColIdx,
+        KeyValueSupplier keySupplier, KeyValueSupplier valSupplier, int 
keyColIdx, int valColIdx,
         GridH2RowDescriptor rowDesc) throws IgniteCheckedException {
-        Object key = keySupplier.apply(F.asList(row));
-        Object val = valSupplier.apply(F.asList(row));
+        List<Object> rowList = F.asList(row);
+
+        Object key = keySupplier.apply(rowList);
+        Object val = valSupplier.apply(rowList);
 
         if (key == null)
             throw new IgniteSQLException("Key for INSERT or MERGE must not be 
null",  IgniteQueryErrorCode.NULL_KEY);
@@ -865,7 +912,7 @@ public class DmlStatementsProcessor {
             if (i == keyColIdx || i == valColIdx)
                 continue;
 
-            desc.setValue(cols[i], key, val, convert(row[i], cols[i], rowDesc, 
colTypes[i]));
+            desc.setValue(cols[i], key, val, convert(row[i], cols[i], 
rowDesc));
         }
 
         if (cctx.binaryMarshaller()) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/d362da5f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdateArguments.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdateArguments.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdateArguments.java
index cb47704..056dfaa 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdateArguments.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdateArguments.java
@@ -50,4 +50,40 @@ public final class FastUpdateArguments {
             return null;
         }
     };
+
+    /** Simple constant value based operand. */
+    public final static class ValueArgument implements FastUpdateArgument {
+        /** Value to return. */
+        private final Object val;
+
+        /** */
+        public ValueArgument(Object val) {
+            this.val = val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public Object apply(Object[] arg) throws 
IgniteCheckedException {
+            return val;
+        }
+    }
+
+    /** Simple constant value based operand. */
+    public final static class ParamArgument implements FastUpdateArgument {
+        /** Value to return. */
+        private final int paramIdx;
+
+        /** */
+        public ParamArgument(int paramIdx) {
+            assert paramIdx >= 0;
+
+            this.paramIdx = paramIdx;
+        }
+
+        /** {@inheritDoc} */
+        @Override public Object apply(Object[] arg) throws 
IgniteCheckedException {
+            assert arg.length > paramIdx;
+
+            return arg[paramIdx];
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d362da5f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
index b81ac60..9bd1ecf 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.query.h2.dml;
 
+import java.util.List;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
 import org.apache.ignite.internal.util.typedef.F;
 
@@ -33,12 +34,6 @@ public final class UpdatePlan {
     /** Column names to set or update. */
     public final String[] colNames;
 
-    /**
-     * Expected column types to set or insert/merge.
-     * @see org.h2.value.Value
-     */
-    public final int[] colTypes;
-
     /** Method to create key for INSERT or MERGE, ignored for UPDATE and 
DELETE. */
     public final KeyValueSupplier keySupplier;
 
@@ -58,6 +53,9 @@ public final class UpdatePlan {
     /** Subquery flag - {@code true} if {@link #selectQry} is an actual 
subquery that retrieves data from some cache. */
     public final boolean isLocSubqry;
 
+    /** */
+    public final Iterable<List<FastUpdateArgument>> rows;
+
     /** Number of rows in rows based MERGE or INSERT. */
     public final int rowsNum;
 
@@ -65,11 +63,11 @@ public final class UpdatePlan {
     public final FastUpdateArguments fastUpdateArgs;
 
     /** */
-    private UpdatePlan(UpdateMode mode, GridH2Table tbl, String[] colNames, 
int[] colTypes, KeyValueSupplier keySupplier,
+    private UpdatePlan(UpdateMode mode, GridH2Table tbl, String[] colNames, 
KeyValueSupplier keySupplier,
         KeyValueSupplier valSupplier, int keyColIdx, int valColIdx, String 
selectQry, boolean isLocSubqry,
-        int rowsNum, FastUpdateArguments fastUpdateArgs) {
+        Iterable<List<FastUpdateArgument>> rows, int rowsNum, 
FastUpdateArguments fastUpdateArgs) {
         this.colNames = colNames;
-        this.colTypes = colTypes;
+        this.rows = rows;
         this.rowsNum = rowsNum;
         assert mode != null;
         assert tbl != null;
@@ -86,43 +84,44 @@ public final class UpdatePlan {
     }
 
     /** */
-    public static UpdatePlan forMerge(GridH2Table tbl, String[] colNames, 
int[] colTypes, KeyValueSupplier keySupplier,
+    public static UpdatePlan forMerge(GridH2Table tbl, String[] colNames, 
KeyValueSupplier keySupplier,
         KeyValueSupplier valSupplier, int keyColIdx, int valColIdx, String 
selectQry, boolean isLocSubqry,
-        int rowsNum) {
+        Iterable<List<FastUpdateArgument>> rows, int rowsNum) {
         assert !F.isEmpty(colNames);
 
-        return new UpdatePlan(UpdateMode.MERGE, tbl, colNames, colTypes, 
keySupplier, valSupplier, keyColIdx, valColIdx,
-            selectQry, isLocSubqry, rowsNum, null);
+        return new UpdatePlan(UpdateMode.MERGE, tbl, colNames, keySupplier, 
valSupplier, keyColIdx, valColIdx,
+            selectQry, isLocSubqry, rows, rowsNum, null);
     }
 
     /** */
-    public static UpdatePlan forInsert(GridH2Table tbl, String[] colNames, 
int[] colTypes, KeyValueSupplier keySupplier,
-        KeyValueSupplier valSupplier, int keyColIdx, int valColIdx, String 
selectQry, boolean isLocSubqry, int rowsNum) {
+    public static UpdatePlan forInsert(GridH2Table tbl, String[] colNames, 
KeyValueSupplier keySupplier,
+        KeyValueSupplier valSupplier, int keyColIdx, int valColIdx, String 
selectQry, boolean isLocSubqry,
+        Iterable<List<FastUpdateArgument>> rows, int rowsNum) {
         assert !F.isEmpty(colNames);
 
-        return new UpdatePlan(UpdateMode.INSERT, tbl, colNames, colTypes, 
keySupplier, valSupplier, keyColIdx, valColIdx,
-            selectQry, isLocSubqry, rowsNum, null);
+        return new UpdatePlan(UpdateMode.INSERT, tbl, colNames, keySupplier, 
valSupplier, keyColIdx, valColIdx,
+            selectQry, isLocSubqry, rows, rowsNum, null);
     }
 
     /** */
-    public static UpdatePlan forUpdate(GridH2Table tbl, String[] colNames, 
int[] colTypes, KeyValueSupplier valSupplier,
+    public static UpdatePlan forUpdate(GridH2Table tbl, String[] colNames, 
KeyValueSupplier valSupplier,
         int valColIdx, String selectQry) {
         assert !F.isEmpty(colNames);
 
-        return new UpdatePlan(UpdateMode.UPDATE, tbl, colNames, colTypes, 
null, valSupplier, -1, valColIdx, selectQry,
-            false, 0, null);
+        return new UpdatePlan(UpdateMode.UPDATE, tbl, colNames, null, 
valSupplier, -1, valColIdx, selectQry,
+            false, null, 0, null);
     }
 
     /** */
     public static UpdatePlan forDelete(GridH2Table tbl, String selectQry) {
-        return new UpdatePlan(UpdateMode.DELETE, tbl, null, null, null, null, 
-1, -1, selectQry, false, 0, null);
+        return new UpdatePlan(UpdateMode.DELETE, tbl, null, null, null, -1, 
-1, selectQry, false, null, 0, null);
     }
 
     /** */
     public static UpdatePlan forFastUpdate(UpdateMode mode, GridH2Table tbl, 
FastUpdateArguments fastUpdateArgs) {
         assert mode == UpdateMode.UPDATE || mode == UpdateMode.DELETE;
 
-        return new UpdatePlan(mode, tbl, null, null, null, null, -1, -1, null, 
false, 0, fastUpdateArgs);
+        return new UpdatePlan(mode, tbl, null, null, null, -1, -1, null, 
false, null, 0, fastUpdateArgs);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d362da5f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
index fdcd164..0303fa4 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.query.h2.dml;
 
 import java.lang.reflect.Constructor;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -36,10 +37,12 @@ import 
org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
 import org.apache.ignite.internal.processors.query.h2.sql.DmlAstUtils;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn;
+import org.apache.ignite.internal.processors.query.h2.sql.GridSqlConst;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlDelete;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlElement;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlInsert;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlMerge;
+import org.apache.ignite.internal.processors.query.h2.sql.GridSqlParameter;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQuery;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlSelect;
@@ -107,6 +110,10 @@ public final class UpdatePlanBuilder {
 
         GridH2RowDescriptor desc;
 
+        List<GridSqlElement[]> elRows = null;
+
+        List<List<FastUpdateArgument>> rows = null;
+
         if (stmt instanceof GridSqlInsert) {
             GridSqlInsert ins = (GridSqlInsert) stmt;
             target = ins.into();
@@ -116,6 +123,10 @@ public final class UpdatePlanBuilder {
 
             cols = ins.columns();
             sel = DmlAstUtils.selectForInsertOrMerge(cols, ins.rows(), 
ins.query(), desc);
+
+            if (sel == null)
+                elRows = ins.rows();
+
             isTwoStepSubqry = (ins.query() != null);
             rowsNum = isTwoStepSubqry ? 0 : ins.rows().size();
         }
@@ -137,14 +148,40 @@ public final class UpdatePlanBuilder {
 
             cols = merge.columns();
             sel = DmlAstUtils.selectForInsertOrMerge(cols, merge.rows(), 
merge.query(), desc);
+
+            if (sel == null)
+                elRows = merge.rows();
+
             isTwoStepSubqry = (merge.query() != null);
             rowsNum = isTwoStepSubqry ? 0 : merge.rows().size();
         }
         else throw new IgniteSQLException("Unexpected DML operation [cls=" + 
stmt.getClass().getName() + ']',
                 IgniteQueryErrorCode.UNEXPECTED_OPERATION);
 
+        if (elRows != null) {
+            assert sel == null;
+
+            rows = new ArrayList<>(elRows.size());
+
+            for (GridSqlElement[] elRow : elRows) {
+                List<FastUpdateArgument> row = new ArrayList<>(cols.length);
+
+                for (GridSqlElement e : elRow) {
+                    if (e instanceof GridSqlConst)
+                        row.add(new 
FastUpdateArguments.ValueArgument(((GridSqlConst) e).value().getObject()));
+                    else if (e instanceof GridSqlParameter)
+                        row.add(new 
FastUpdateArguments.ParamArgument(((GridSqlParameter) e).index()));
+                    else
+                        throw new IgniteSQLException("Unexpected element type: 
" + e.getClass().getSimpleName(),
+                            IgniteQueryErrorCode.UNEXPECTED_ELEMENT_TYPE);
+                }
+
+                rows.add(row);
+            }
+        }
+
         // Let's set the flag only for subqueries that have their FROM 
specified.
-        isTwoStepSubqry = (isTwoStepSubqry && (sel instanceof GridSqlUnion ||
+        isTwoStepSubqry &= (sel != null && (sel instanceof GridSqlUnion ||
             (sel instanceof GridSqlSelect && ((GridSqlSelect) sel).from() != 
null)));
 
         int keyColIdx = -1;
@@ -161,8 +198,6 @@ public final class UpdatePlanBuilder {
 
         String[] colNames = new String[cols.length];
 
-        int[] colTypes = new int[cols.length];
-
         for (int i = 0; i < cols.length; i++) {
             GridSqlColumn col = cols[i];
 
@@ -170,8 +205,6 @@ public final class UpdatePlanBuilder {
 
             colNames[i] = colName;
 
-            colTypes[i] = col.resultType().type();
-
             if (KEY_FIELD_NAME.equals(colName)) {
                 keyColIdx = i;
                 continue;
@@ -196,11 +229,11 @@ public final class UpdatePlanBuilder {
         KeyValueSupplier valSupplier = createSupplier(cctx, desc.type(), 
valColIdx, hasValProps, false);
 
         if (stmt instanceof GridSqlMerge)
-            return UpdatePlan.forMerge(tbl.dataTable(), colNames, colTypes, 
keySupplier, valSupplier, keyColIdx,
-                valColIdx, sel.getSQL(), !isTwoStepSubqry, rowsNum);
+            return UpdatePlan.forMerge(tbl.dataTable(), colNames, keySupplier, 
valSupplier, keyColIdx,
+                valColIdx, sel != null ? sel.getSQL() : null, 
!isTwoStepSubqry, rows, rowsNum);
         else
-            return UpdatePlan.forInsert(tbl.dataTable(), colNames, colTypes, 
keySupplier, valSupplier, keyColIdx,
-                valColIdx, sel.getSQL(), !isTwoStepSubqry, rowsNum);
+            return UpdatePlan.forInsert(tbl.dataTable(), colNames, 
keySupplier, valSupplier, keyColIdx,
+                valColIdx, sel != null ? sel.getSQL() : null, 
!isTwoStepSubqry, rows, rowsNum);
     }
 
     /**
@@ -261,13 +294,9 @@ public final class UpdatePlanBuilder {
 
                 String[] colNames = new String[updatedCols.size()];
 
-                int[] colTypes = new int[updatedCols.size()];
-
                 for (int i = 0; i < updatedCols.size(); i++) {
                     colNames[i] = updatedCols.get(i).columnName();
 
-                    colTypes[i] = updatedCols.get(i).resultType().type();
-
                     if (VAL_FIELD_NAME.equals(colNames[i]))
                         valColIdx = i;
                 }
@@ -299,7 +328,7 @@ public final class UpdatePlanBuilder {
 
                 sel = DmlAstUtils.selectForUpdate((GridSqlUpdate) stmt, 
errKeysPos);
 
-                return UpdatePlan.forUpdate(gridTbl, colNames, colTypes, 
newValSupplier, valColIdx, sel.getSQL());
+                return UpdatePlan.forUpdate(gridTbl, colNames, newValSupplier, 
valColIdx, sel.getSQL());
             }
             else {
                 sel = DmlAstUtils.selectForDelete((GridSqlDelete) stmt, 
errKeysPos);
@@ -323,7 +352,7 @@ public final class UpdatePlanBuilder {
      */
     @SuppressWarnings({"ConstantConditions", "unchecked"})
     private static KeyValueSupplier createSupplier(final GridCacheContext<?, 
?> cctx, GridQueryTypeDescriptor desc,
-                                                   final int colIdx, boolean 
hasProps, final boolean key) throws IgniteCheckedException {
+        final int colIdx, boolean hasProps, final boolean key) throws 
IgniteCheckedException {
         final String typeName = key ? desc.keyTypeName() : 
desc.valueTypeName();
 
         //Try to find class for the key locally.

http://git-wip-us.apache.org/repos/asf/ignite/blob/d362da5f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/DmlAstUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/DmlAstUtils.java
 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/DmlAstUtils.java
index 6deb146..8df786c 100644
--- 
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/DmlAstUtils.java
+++ 
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/DmlAstUtils.java
@@ -21,7 +21,6 @@ import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
@@ -67,7 +66,7 @@ public final class DmlAstUtils {
      * @param rows Rows to create pseudo-SELECT upon.
      * @param subQry Subquery to use rather than rows.
      * @param desc Row descriptor.
-     * @return Subquery or pseudo-SELECT to evaluate inserted expressions.
+     * @return Subquery or pseudo-SELECT to evaluate inserted expressions, or 
{@code null} no query needs to be run.
      */
     public static GridSqlQuery selectForInsertOrMerge(GridSqlColumn[] cols, 
List<GridSqlElement[]> rows,
         GridSqlQuery subQry, GridH2RowDescriptor desc) {
@@ -82,6 +81,8 @@ public final class DmlAstUtils {
 
             GridSqlArray[] args = new GridSqlArray[cols.length];
 
+            boolean noQry = true;
+
             for (int i = 0; i < cols.length; i++) {
                 GridSqlArray arr = new GridSqlArray(rows.size());
 
@@ -105,10 +106,18 @@ public final class DmlAstUtils {
             for (GridSqlElement[] row : rows) {
                 assert cols.length == row.length;
 
-                for (int i = 0; i < row.length; i++)
+                for (int i = 0; i < row.length; i++) {
+                    GridSqlElement el = row[i];
+
+                    noQry &= (el instanceof GridSqlConst || el instanceof 
GridSqlParameter);
+
                     args[i].addChild(row[i]);
+                }
             }
 
+            if (noQry)
+                return null;
+
             return sel;
         }
         else {
@@ -202,9 +211,9 @@ public final class DmlAstUtils {
             return FastUpdateArguments.NULL_ARGUMENT;
 
         if (el instanceof GridSqlConst)
-            return new ValueArgument(((GridSqlConst)el).value().getObject());
+            return new 
FastUpdateArguments.ValueArgument(((GridSqlConst)el).value().getObject());
         else
-            return new ParamArgument(((GridSqlParameter)el).index());
+            return new 
FastUpdateArguments.ParamArgument(((GridSqlParameter)el).index());
     }
 
     /**
@@ -577,40 +586,4 @@ public final class DmlAstUtils {
             }
         });
     }
-
-    /** Simple constant value based operand. */
-    private final static class ValueArgument implements FastUpdateArgument {
-        /** Value to return. */
-        private final Object val;
-
-        /** */
-        private ValueArgument(Object val) {
-            this.val = val;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Object apply(Object[] arg) throws 
IgniteCheckedException {
-            return val;
-        }
-    }
-
-    /** Simple constant value based operand. */
-    private final static class ParamArgument implements FastUpdateArgument {
-        /** Value to return. */
-        private final int paramIdx;
-
-        /** */
-        private ParamArgument(int paramIdx) {
-            assert paramIdx >= 0;
-
-            this.paramIdx = paramIdx;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Object apply(Object[] arg) throws 
IgniteCheckedException {
-            assert arg.length > paramIdx;
-
-            return arg[paramIdx];
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d362da5f/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java
index 332a082..5ee21b2 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheUpdateSqlQuerySelfTest.java
@@ -182,8 +182,6 @@ public class IgniteCacheUpdateSqlQuerySelfTest extends 
IgniteCacheAbstractSqlDml
         cache.query(new SqlFieldsQuery("insert into \"AllTypes\"(_key, _val, 
\"dateCol\", \"booleanCol\"," +
             "\"tsCol\") values(2, ?, '2016-11-30 12:00:00', false, DATE 
'2016-12-01')").setArgs(new AllTypes(2L)));
 
-        List<?> ll = cache.query(new SqlFieldsQuery("select 
\"primitiveIntsCol\" from \"AllTypes\"")).getAll();
-
         cache.query(new SqlFieldsQuery("update \"AllTypes\" set \"doubleCol\" 
= CAST('50' as INT)," +
             " \"booleanCol\" = 80, \"innerTypeCol\" = ?, \"strCol\" = PI(), 
\"shortCol\" = " +
             "CAST(WEEK(PARSEDATETIME('2016-11-30', 'yyyy-MM-dd')) as VARCHAR), 
" +

Reply via email to