ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From voze...@apache.org
Subject [1/2] ignite git commit: IGNITE-7200: SQL: simplified DML module structure and restored encapsulation. This closes #3225.
Date Thu, 14 Dec 2017 12:59:48 GMT
Repository: ignite
Updated Branches:
  refs/heads/master 802a1668b -> 03bb55138


http://git-wip-us.apache.org/repos/asf/ignite/blob/03bb5513/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdate.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdate.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdate.java
new file mode 100644
index 0000000..e662245
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdate.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.query.h2.dml;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
+import org.apache.ignite.internal.processors.query.h2.UpdateResult;
+import org.apache.ignite.internal.processors.query.h2.sql.GridSqlConst;
+import org.apache.ignite.internal.processors.query.h2.sql.GridSqlElement;
+import org.apache.ignite.internal.processors.query.h2.sql.GridSqlParameter;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Arguments for fast, query-less UPDATE or DELETE - key and, optionally, value and new value.
+ */
+public final class FastUpdate {
+    /** Operand that always evaluates as {@code null}. */
+    private final static FastUpdateArgument NULL_ARG = new ConstantArgument(null);
+
+    /** Operand to compute key. */
+    private final FastUpdateArgument keyArg;
+
+    /** Operand to compute value. */
+    private final FastUpdateArgument valArg;
+
+    /** Operand to compute new value. */
+    private final FastUpdateArgument newValArg;
+
+    /**
+     * Create fast update instance.
+     *
+     * @param key Key element.
+     * @param val Value element.
+     * @param newVal New value element (if any)
+     * @return Fast update.
+     */
+    public static FastUpdate create(GridSqlElement key, GridSqlElement val, @Nullable GridSqlElement newVal) {
+        FastUpdateArgument keyArg = argument(key);
+        FastUpdateArgument valArg = argument(val);
+        FastUpdateArgument newValArg = argument(newVal);
+
+        return new FastUpdate(keyArg, valArg, newValArg);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param keyArg Key argument.
+     * @param valArg Value argument.
+     * @param newValArg New value argument.
+     */
+    private FastUpdate(FastUpdateArgument keyArg, FastUpdateArgument valArg, FastUpdateArgument newValArg) {
+        this.keyArg = keyArg;
+        this.valArg = valArg;
+        this.newValArg = newValArg;
+    }
+
+    /**
+     * Perform single cache operation based on given args.
+     *
+     * @param cache Cache.
+     * @param args Query parameters.
+     * @return 1 if an item was affected, 0 otherwise.
+     * @throws IgniteCheckedException if failed.
+     */
+    @SuppressWarnings({"unchecked", "ConstantConditions"})
+    public UpdateResult execute(GridCacheAdapter cache, Object[] args) throws IgniteCheckedException {
+        Object key = keyArg.apply(args);
+
+        assert key != null;
+
+        Object val = valArg.apply(args);
+        Object newVal = newValArg.apply(args);
+
+        boolean res;
+
+        if (newVal != null) {
+            // Update.
+            if (val != null)
+                res = cache.replace(key, val, newVal);
+            else
+                res = cache.replace(key, newVal);
+        }
+        else {
+            // Delete.
+            if (val != null)
+                res = cache.remove(key, val);
+            else
+                res = cache.remove(key);
+        }
+
+        return res ? UpdateResult.ONE : UpdateResult.ZERO;
+    }
+
+    /**
+     * Create argument for AST element.
+     *
+     * @param el Element.
+     * @return Argument.
+     */
+    private static FastUpdateArgument argument(@Nullable GridSqlElement el) {
+        assert el == null ^ (el instanceof GridSqlConst || el instanceof GridSqlParameter);
+
+        if (el == null)
+            return NULL_ARG;
+
+        if (el instanceof GridSqlConst)
+            return new ConstantArgument(((GridSqlConst)el).value().getObject());
+        else
+            return new ParamArgument(((GridSqlParameter)el).index());
+    }
+
+    /**
+     * Value argument.
+     */
+    private static class ConstantArgument implements FastUpdateArgument {
+        /** Value to return. */
+        private final Object val;
+
+        /**
+         * Constructor.
+         *
+         * @param val Value.
+         */
+        private ConstantArgument(Object val) {
+            this.val = val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public Object apply(Object[] arg) throws IgniteCheckedException {
+            return val;
+        }
+    }
+
+    /**
+     * Parameter argument.
+     */
+    private static class ParamArgument implements FastUpdateArgument {
+        /** Value to return. */
+        private final int paramIdx;
+
+        /**
+         * Constructor.
+         *
+         * @param paramIdx Parameter index.
+         */
+        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/03bb5513/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
deleted file mode 100644
index cb47704..0000000
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/FastUpdateArguments.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.processors.query.h2.dml;
-
-import org.apache.ignite.IgniteCheckedException;
-
-/**
- * Arguments for fast, query-less UPDATE or DELETE - key and, optionally, value and new value.
- */
-public final class FastUpdateArguments {
-    /** Operand to compute key. */
-    public final FastUpdateArgument key;
-
-    /** Operand to compute value. */
-    public final FastUpdateArgument val;
-
-    /** Operand to compute new value. */
-    public final FastUpdateArgument newVal;
-
-    /** */
-    public FastUpdateArguments(FastUpdateArgument key, FastUpdateArgument val, FastUpdateArgument newVal) {
-        assert key != null && key != NULL_ARGUMENT;
-        assert val != null;
-        assert newVal != null;
-
-        this.key = key;
-        this.val = val;
-        this.newVal = newVal;
-    }
-
-    /** Operand that always evaluates as {@code null}. */
-    public final static FastUpdateArgument NULL_ARGUMENT = new FastUpdateArgument() {
-        /** {@inheritDoc} */
-        @Override public Object apply(Object[] arg) throws IgniteCheckedException {
-            return null;
-        }
-    };
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/03bb5513/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 a99d811..31dc52d 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,64 +17,108 @@
 
 package org.apache.ignite.internal.processors.query.h2.dml;
 
-import java.util.List;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+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.QueryUtils;
+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.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.T3;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.h2.table.Column;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOnheap.DEFAULT_COLUMNS_COUNT;
 
 /**
  * Update plan - where to take data to update cache from and how to construct new keys and values, if needed.
  */
 public final class UpdatePlan {
     /** Initial statement to drive the rest of the logic. */
-    public final UpdateMode mode;
+    private final UpdateMode mode;
 
     /** Target table to be affected by initial DML statement. */
-    public final GridH2Table tbl;
+    private final GridH2Table tbl;
 
     /** Column names to set or update. */
-    public final String[] colNames;
+    private final String[] colNames;
 
-    /**
-     * Expected column types to set or insert/merge.
-     * @see org.h2.value.Value
-     */
-    public final int[] colTypes;
+    /** Column types to set for insert/merge. */
+    private final int[] colTypes;
 
     /** Method to create key for INSERT or MERGE, ignored for UPDATE and DELETE. */
-    public final KeyValueSupplier keySupplier;
+    private final KeyValueSupplier keySupplier;
 
     /** Method to create value to put to cache, ignored for DELETE. */
-    public final KeyValueSupplier valSupplier;
+    private final KeyValueSupplier valSupplier;
 
-    /** Index of key column, if it's explicitly mentioned in column list of MERGE or INSERT,
-     * ignored for UPDATE and DELETE. */
-    public final int keyColIdx;
+    /** Key column index. */
+    private final int keyColIdx;
 
-    /** Index of value column, if it's explicitly mentioned in column list. Ignored for UPDATE and DELETE. */
-    public final int valColIdx;
+    /** Value column index. */
+    private final int valColIdx;
 
     /** SELECT statement built upon initial DML statement. */
-    public final String selectQry;
+    private final String selectQry;
 
     /** Subquery flag - {@code true} if {@link #selectQry} is an actual subquery that retrieves data from some cache. */
-    public final boolean isLocSubqry;
+    private final boolean isLocSubqry;
 
     /** Number of rows in rows based MERGE or INSERT. */
-    public final int rowsNum;
+    private final int rowsNum;
 
     /** Arguments for fast UPDATE or DELETE. */
-    public final FastUpdateArguments fastUpdateArgs;
+    private final FastUpdate fastUpdate;
 
     /** Additional info for distributed update. */
-    public final DistributedPlanInfo distributed;
+    private final DmlDistributedPlanInfo distributed;
 
-    /** */
-    private UpdatePlan(UpdateMode mode, GridH2Table tbl, String[] colNames, int[] colTypes, KeyValueSupplier keySupplier,
-        KeyValueSupplier valSupplier, int keyColIdx, int valColIdx, String selectQry, boolean isLocSubqry,
-        int rowsNum, FastUpdateArguments fastUpdateArgs, DistributedPlanInfo distributed) {
+    /**
+     * Constructor.
+     *
+     * @param mode Mode.
+     * @param tbl Table.
+     * @param colNames Column names.
+     * @param colTypes Column types.
+     * @param keySupplier Key supplier.
+     * @param valSupplier Value supplier.
+     * @param keyColIdx Key column index.
+     * @param valColIdx value column index.
+     * @param selectQry Select query.
+     * @param isLocSubqry Local subquery flag.
+     * @param rowsNum Rows number.
+     * @param fastUpdate Fast update (if any).
+     * @param distributed Distributed plan (if any)
+     */
+    public UpdatePlan(
+        UpdateMode mode,
+        GridH2Table tbl,
+        String[] colNames,
+        int[] colTypes,
+        KeyValueSupplier keySupplier,
+        KeyValueSupplier valSupplier,
+        int keyColIdx,
+        int valColIdx,
+        String selectQry,
+        boolean isLocSubqry,
+        int rowsNum,
+        @Nullable FastUpdate fastUpdate,
+        @Nullable DmlDistributedPlanInfo distributed
+    ) {
         this.colNames = colNames;
         this.colTypes = colTypes;
         this.rowsNum = rowsNum;
+
         assert mode != null;
         assert tbl != null;
 
@@ -86,85 +130,260 @@ public final class UpdatePlan {
         this.valColIdx = valColIdx;
         this.selectQry = selectQry;
         this.isLocSubqry = isLocSubqry;
-        this.fastUpdateArgs = fastUpdateArgs;
+        this.fastUpdate = fastUpdate;
         this.distributed = distributed;
     }
 
-    /** */
-    public static UpdatePlan forMerge(GridH2Table tbl, String[] colNames, int[] colTypes, KeyValueSupplier keySupplier,
-        KeyValueSupplier valSupplier, int keyColIdx, int valColIdx, String selectQry, boolean isLocSubqry,
-        int rowsNum, DistributedPlanInfo distributed) {
-        assert !F.isEmpty(colNames);
-
-        return new UpdatePlan(UpdateMode.MERGE, tbl, colNames, colTypes, keySupplier, valSupplier, keyColIdx, valColIdx,
-            selectQry, isLocSubqry, rowsNum, null, distributed);
+    /**
+     * Constructor for delete operation or fast update.
+     *
+     * @param mode Mode.
+     * @param tbl Table.
+     * @param selectQry Select query.
+     * @param fastUpdate Fast update arguments (if any).
+     * @param distributed Distributed plan (if any)
+     */
+    public UpdatePlan(
+        UpdateMode mode,
+        GridH2Table tbl,
+        String selectQry,
+        @Nullable FastUpdate fastUpdate,
+        @Nullable DmlDistributedPlanInfo distributed
+    ) {
+        this(
+            mode,
+            tbl,
+            null,
+            null,
+            null,
+            null,
+            -1,
+            -1,
+            selectQry,
+            false,
+            0,
+            fastUpdate,
+            distributed
+        );
     }
 
-    /** */
-    public static UpdatePlan forInsert(GridH2Table tbl, String[] colNames, int[] colTypes, KeyValueSupplier keySupplier,
-        KeyValueSupplier valSupplier, int keyColIdx, int valColIdx, String selectQry, boolean isLocSubqry,
-        int rowsNum, DistributedPlanInfo distributed) {
-        assert !F.isEmpty(colNames);
+    /**
+     * Convert a row into key-value pair.
+     *
+     * @param row Row to process.
+     * @throws IgniteCheckedException if failed.
+     */
+    public IgniteBiTuple<?, ?> processRow(List<?> row) throws IgniteCheckedException {
+        GridH2RowDescriptor rowDesc = tbl.rowDescriptor();
+        GridQueryTypeDescriptor desc = rowDesc.type();
 
-        return new UpdatePlan(UpdateMode.INSERT, tbl, colNames, colTypes, keySupplier, valSupplier, keyColIdx,
-            valColIdx, selectQry, isLocSubqry, rowsNum, null, distributed);
-    }
+        GridCacheContext cctx = rowDesc.context();
 
-    /** */
-    public static UpdatePlan forUpdate(GridH2Table tbl, String[] colNames, int[] colTypes, KeyValueSupplier valSupplier,
-        int valColIdx, String selectQry, DistributedPlanInfo distributed) {
-        assert !F.isEmpty(colNames);
+        Object key = keySupplier.apply(row);
 
-        return new UpdatePlan(UpdateMode.UPDATE, tbl, colNames, colTypes, null, valSupplier, -1, valColIdx, selectQry,
-            false, 0, null, distributed);
-    }
+        if (QueryUtils.isSqlType(desc.keyClass())) {
+            assert keyColIdx != -1;
 
-    /** */
-    public static UpdatePlan forDelete(GridH2Table tbl, String selectQry, DistributedPlanInfo distributed) {
-        return new UpdatePlan(UpdateMode.DELETE, tbl, null, null, null, null, -1, -1, selectQry, false, 0, null,
-            distributed);
-    }
+            key = DmlUtils.convert(key, rowDesc, desc.keyClass(), colTypes[keyColIdx]);
+        }
+
+        Object val = valSupplier.apply(row);
+
+        if (QueryUtils.isSqlType(desc.valueClass())) {
+            assert valColIdx != -1;
+
+            val = DmlUtils.convert(val, rowDesc, desc.valueClass(), colTypes[valColIdx]);
+        }
+
+        if (key == null) {
+            if (F.isEmpty(desc.keyFieldName()))
+                throw new IgniteSQLException("Key for INSERT or MERGE must not be null", IgniteQueryErrorCode.NULL_KEY);
+            else
+                throw new IgniteSQLException("Null value is not allowed for column '" + desc.keyFieldName() + "'",
+                    IgniteQueryErrorCode.NULL_KEY);
+        }
 
-    /** */
-    public static UpdatePlan forFastUpdate(UpdateMode mode, GridH2Table tbl, FastUpdateArguments fastUpdateArgs) {
-        assert mode == UpdateMode.UPDATE || mode == UpdateMode.DELETE;
+        if (val == null) {
+            if (F.isEmpty(desc.valueFieldName()))
+                throw new IgniteSQLException("Value for INSERT, MERGE, or UPDATE must not be null",
+                    IgniteQueryErrorCode.NULL_VALUE);
+            else
+                throw new IgniteSQLException("Null value is not allowed for column '" + desc.valueFieldName() + "'",
+                    IgniteQueryErrorCode.NULL_VALUE);
+        }
+
+        Map<String, Object> newColVals = new HashMap<>();
+
+        for (int i = 0; i < colNames.length; i++) {
+            if (i == keyColIdx || i == valColIdx)
+                continue;
+
+            String colName = colNames[i];
+
+            GridQueryProperty prop = desc.property(colName);
+
+            assert prop != null;
+
+            Class<?> expCls = prop.type();
+
+            newColVals.put(colName, DmlUtils.convert(row.get(i), rowDesc, expCls, colTypes[i]));
+        }
+
+        // We update columns in the order specified by the table for a reason - table's
+        // column order preserves their precedence for correct update of nested properties.
+        Column[] cols = tbl.getColumns();
+
+        // First 3 columns are _key, _val and _ver. Skip 'em.
+        for (int i = DEFAULT_COLUMNS_COUNT; i < cols.length; i++) {
+            if (tbl.rowDescriptor().isKeyValueOrVersionColumn(i))
+                continue;
+
+            String colName = cols[i].getName();
 
-        return new UpdatePlan(mode, tbl, null, null, null, null, -1, -1, null, false, 0, fastUpdateArgs, null);
+            if (!newColVals.containsKey(colName))
+                continue;
+
+            Object colVal = newColVals.get(colName);
+
+            desc.setValue(colName, key, val, colVal);
+        }
+
+        if (cctx.binaryMarshaller()) {
+            if (key instanceof BinaryObjectBuilder)
+                key = ((BinaryObjectBuilder) key).build();
+
+            if (val instanceof BinaryObjectBuilder)
+                val = ((BinaryObjectBuilder) val).build();
+        }
+
+        desc.validateKeyAndValue(key, val);
+
+        return new IgniteBiTuple<>(key, val);
     }
 
     /**
-     * Additional information about distributed update plan.
+     * Convert a row into value.
+     *
+     * @param row Row to process.
+     * @throws IgniteCheckedException if failed.
      */
-    public final static class DistributedPlanInfo {
-        /** Whether update involves only replicated caches. */
-        private final boolean replicatedOnly;
-
-        /** Identifiers of caches involved in update (used for cluster nodes mapping). */
-        private final List<Integer> cacheIds;
-
-        /**
-         * Constructor.
-         *
-         * @param replicatedOnly Whether all caches are replicated.
-         * @param cacheIds List of cache identifiers.
-         */
-        DistributedPlanInfo(boolean replicatedOnly, List<Integer> cacheIds) {
-            this.replicatedOnly = replicatedOnly;
-            this.cacheIds = cacheIds;
+    public T3<Object, Object, Object> processRowForUpdate(List<?> row) throws IgniteCheckedException {
+        GridH2RowDescriptor rowDesc = tbl.rowDescriptor();
+        GridQueryTypeDescriptor desc = rowDesc.type();
+
+        GridCacheContext cctx = rowDesc.context();
+
+        boolean hasNewVal = (valColIdx != -1);
+
+        boolean hasProps = !hasNewVal || colNames.length > 1;
+
+        Object key = row.get(0);
+
+        Object oldVal = row.get(1);
+
+        if (cctx.binaryMarshaller() && !(oldVal instanceof BinaryObject))
+            oldVal = cctx.grid().binary().toBinary(oldVal);
+
+        Object newVal;
+
+        Map<String, Object> newColVals = new HashMap<>();
+
+        for (int i = 0; i < colNames.length; i++) {
+            if (hasNewVal && i == valColIdx - 2)
+                continue;
+
+            GridQueryProperty prop = tbl.rowDescriptor().type().property(colNames[i]);
+
+            assert prop != null : "Unknown property: " + colNames[i];
+
+            newColVals.put(colNames[i], DmlUtils.convert(row.get(i + 2), rowDesc, prop.type(), colTypes[i]));
         }
 
-        /**
-         * @return {@code true} in case all involved caches are replicated.
-         */
-        public boolean isReplicatedOnly() {
-            return replicatedOnly;
+        newVal = valSupplier.apply(row);
+
+        if (newVal == null)
+            throw new IgniteSQLException("New value for UPDATE must not be null", IgniteQueryErrorCode.NULL_VALUE);
+
+        // Skip key and value - that's why we start off with 3rd column
+        for (int i = 0; i < tbl.getColumns().length - DEFAULT_COLUMNS_COUNT; i++) {
+            Column c = tbl.getColumn(i + DEFAULT_COLUMNS_COUNT);
+
+            if (rowDesc.isKeyValueOrVersionColumn(c.getColumnId()))
+                continue;
+
+            GridQueryProperty prop = desc.property(c.getName());
+
+            if (prop.key())
+                continue; // Don't get values of key's columns - we won't use them anyway
+
+            boolean hasNewColVal = newColVals.containsKey(c.getName());
+
+            if (!hasNewColVal)
+                continue;
+
+            Object colVal = newColVals.get(c.getName());
+
+            // UPDATE currently does not allow to modify key or its fields, so we must be safe to pass null as key.
+            rowDesc.setColumnValue(null, newVal, colVal, i);
         }
 
-        /**
-         * @return cache identifiers.
-         */
-        public List<Integer> getCacheIds() {
-            return cacheIds;
+        if (cctx.binaryMarshaller() && hasProps) {
+            assert newVal instanceof BinaryObjectBuilder;
+
+            newVal = ((BinaryObjectBuilder) newVal).build();
         }
+
+        desc.validateKeyAndValue(key, newVal);
+
+        return new T3<>(key, oldVal, newVal);
+    }
+
+    /**
+     * @return Update mode.
+     */
+    public UpdateMode mode() {
+        return mode;
+    }
+
+    /**
+     * @return Cache context.
+     */
+    public GridCacheContext cacheContext() {
+        return tbl.cache();
+    }
+
+    /**
+     * @return Distributed plan info (for skip-reducer mode).
+     */
+    @Nullable public DmlDistributedPlanInfo distributedPlan() {
+        return distributed;
+    }
+
+    /**
+     * @return Row count.
+     */
+    public int rowCount() {
+        return rowsNum;
+    }
+
+    /**
+     * @return Select query.
+     */
+    public String selectQuery() {
+        return selectQry;
+    }
+
+    /**
+     * @return Local subquery flag.
+     */
+    @Nullable public boolean isLocalSubquery() {
+        return isLocSubqry;
+    }
+
+    /**
+     * @return Fast update.
+     */
+    @Nullable public FastUpdate fastUpdate() {
+        return fastUpdate;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/03bb5513/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 c845266..a551639 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
@@ -40,7 +40,6 @@ import org.apache.ignite.internal.processors.query.h2.DmlStatementsProcessor;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
 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.GridSqlDelete;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlElement;
@@ -213,15 +212,26 @@ public final class UpdatePlanBuilder {
 
         String selectSql = sel.getSQL();
 
-        UpdatePlan.DistributedPlanInfo distributed = (rowsNum == 0 && !F.isEmpty(selectSql)) ?
+        DmlDistributedPlanInfo distributed = (rowsNum == 0 && !F.isEmpty(selectSql)) ?
             checkPlanCanBeDistributed(idx, conn, fieldsQuery, loc, selectSql, tbl.dataTable().cacheName()) : null;
 
-        if (stmt instanceof GridSqlMerge)
-            return UpdatePlan.forMerge(tbl.dataTable(), colNames, colTypes, keySupplier, valSupplier, keyColIdx,
-                valColIdx, selectSql, !isTwoStepSubqry, rowsNum, distributed);
-        else
-            return UpdatePlan.forInsert(tbl.dataTable(), colNames, colTypes, keySupplier, valSupplier, keyColIdx,
-                valColIdx, selectSql, !isTwoStepSubqry, rowsNum, distributed);
+        UpdateMode mode = stmt instanceof GridSqlMerge ? UpdateMode.MERGE : UpdateMode.INSERT;
+
+        return new UpdatePlan(
+            mode,
+            tbl.dataTable(),
+            colNames,
+            colTypes,
+            keySupplier,
+            valSupplier,
+            keyColIdx,
+            valColIdx,
+            selectSql,
+            !isTwoStepSubqry,
+            rowsNum,
+            null,
+            distributed
+        );
     }
 
     /**
@@ -241,7 +251,7 @@ public final class UpdatePlanBuilder {
         throws IgniteCheckedException {
         GridSqlElement target;
 
-        FastUpdateArguments fastUpdate;
+        FastUpdate fastUpdate;
 
         UpdateMode mode;
 
@@ -249,7 +259,7 @@ public final class UpdatePlanBuilder {
             // Let's verify that user is not trying to mess with key's columns directly
             verifyUpdateColumns(stmt);
 
-            GridSqlUpdate update = (GridSqlUpdate) stmt;
+            GridSqlUpdate update = (GridSqlUpdate)stmt;
             target = update.target();
             fastUpdate = DmlAstUtils.getFastUpdateArgs(update);
             mode = UpdateMode.UPDATE;
@@ -266,16 +276,23 @@ public final class UpdatePlanBuilder {
 
         GridSqlTable tbl = DmlAstUtils.gridTableForElement(target);
 
-        GridH2Table gridTbl = tbl.dataTable();
+        GridH2Table h2Tbl = tbl.dataTable();
 
-        GridH2RowDescriptor desc = gridTbl.rowDescriptor();
+        GridH2RowDescriptor desc = h2Tbl.rowDescriptor();
 
         if (desc == null)
-            throw new IgniteSQLException("Row descriptor undefined for table '" + gridTbl.getName() + "'",
+            throw new IgniteSQLException("Row descriptor undefined for table '" + h2Tbl.getName() + "'",
                 IgniteQueryErrorCode.NULL_TABLE_DESCRIPTOR);
 
-        if (fastUpdate != null)
-            return UpdatePlan.forFastUpdate(mode, gridTbl, fastUpdate);
+        if (fastUpdate != null) {
+            return new UpdatePlan(
+                mode,
+                h2Tbl,
+                null,
+                fastUpdate,
+                null
+            );
+        }
         else {
             GridSqlSelect sel;
 
@@ -311,28 +328,47 @@ public final class UpdatePlanBuilder {
 
                 int newValColIdx = (hasNewVal ? valColIdx : 1);
 
-                KeyValueSupplier newValSupplier = createSupplier(desc.context(), desc.type(), newValColIdx, hasProps,
+                KeyValueSupplier valSupplier = createSupplier(desc.context(), desc.type(), newValColIdx, hasProps,
                     false, true);
 
                 sel = DmlAstUtils.selectForUpdate((GridSqlUpdate) stmt, errKeysPos);
 
                 String selectSql = sel.getSQL();
 
-                UpdatePlan.DistributedPlanInfo distributed = F.isEmpty(selectSql) ? null :
+                DmlDistributedPlanInfo distributed = F.isEmpty(selectSql) ? null :
                     checkPlanCanBeDistributed(idx, conn, fieldsQuery, loc, selectSql, tbl.dataTable().cacheName());
 
-                return UpdatePlan.forUpdate(gridTbl, colNames, colTypes, newValSupplier, valColIdx, selectSql,
-                    distributed);
+                return new UpdatePlan(
+                    UpdateMode.UPDATE,
+                    h2Tbl,
+                    colNames,
+                    colTypes,
+                    null,
+                    valSupplier,
+                    -1,
+                    valColIdx,
+                    selectSql,
+                    false,
+                    0,
+                    null,
+                    distributed
+                );
             }
             else {
                 sel = DmlAstUtils.selectForDelete((GridSqlDelete) stmt, errKeysPos);
 
                 String selectSql = sel.getSQL();
 
-                UpdatePlan.DistributedPlanInfo distributed = F.isEmpty(selectSql) ? null :
+                DmlDistributedPlanInfo distributed = F.isEmpty(selectSql) ? null :
                     checkPlanCanBeDistributed(idx, conn, fieldsQuery, loc, selectSql, tbl.dataTable().cacheName());
 
-                return UpdatePlan.forDelete(gridTbl, selectSql, distributed);
+                return new UpdatePlan(
+                    UpdateMode.DELETE,
+                    h2Tbl,
+                    selectSql,
+                    null,
+                    distributed
+                );
             }
         }
     }
@@ -546,7 +582,7 @@ public final class UpdatePlanBuilder {
      * @return distributed update plan info, or {@code null} if cannot be distributed.
      * @throws IgniteCheckedException if failed.
      */
-    private static UpdatePlan.DistributedPlanInfo checkPlanCanBeDistributed(IgniteH2Indexing idx,
+    private static DmlDistributedPlanInfo checkPlanCanBeDistributed(IgniteH2Indexing idx,
         Connection conn, SqlFieldsQuery fieldsQry, boolean loc, String selectQry, String cacheName)
         throws IgniteCheckedException {
 
@@ -570,7 +606,7 @@ public final class UpdatePlanBuilder {
                 boolean distributed = qry.skipMergeTable() &&  qry.mapQueries().size() == 1 &&
                     !qry.mapQueries().get(0).hasSubQueries();
 
-                return distributed ? new UpdatePlan.DistributedPlanInfo(qry.isReplicatedOnly(),
+                return distributed ? new DmlDistributedPlanInfo(qry.isReplicatedOnly(),
                     idx.collectCacheIds(CU.cacheId(cacheName), qry)): null;
             }
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/03bb5513/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
deleted file mode 100644
index 4537ffc..0000000
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/DmlAstUtils.java
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.processors.query.h2.sql;
-
-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.cache.query.IgniteQueryErrorCode;
-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.opt.GridH2KeyValueRowOnheap;
-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.util.lang.IgnitePair;
-import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.lang.IgnitePredicate;
-import org.h2.command.Parser;
-import org.h2.expression.Expression;
-import org.h2.table.Column;
-import org.h2.table.Table;
-import org.h2.util.IntArray;
-import org.h2.value.DataType;
-import org.h2.value.Value;
-import org.h2.value.ValueDate;
-import org.h2.value.ValueInt;
-import org.h2.value.ValueString;
-import org.h2.value.ValueTime;
-import org.h2.value.ValueTimestamp;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * AST utils for DML
- */
-public final class DmlAstUtils {
-    /**
-     * Empty ctor to prevent initialization.
-     */
-    private DmlAstUtils() {
-        // No-op.
-    }
-
-    /**
-     * Create SELECT on which subsequent INSERT or MERGE will be based.
-     *
-     * @param cols Columns to insert values into.
-     * @param rows Rows to create pseudo-SELECT upon.
-     * @param subQry Subquery to use rather than rows.
-     * @return Subquery or pseudo-SELECT to evaluate inserted expressions.
-     */
-    public static GridSqlQuery selectForInsertOrMerge(GridSqlColumn[] cols, List<GridSqlElement[]> rows,
-        GridSqlQuery subQry) {
-        if (!F.isEmpty(rows)) {
-            assert !F.isEmpty(cols);
-
-            GridSqlSelect sel = new GridSqlSelect();
-
-            GridSqlFunction from = new GridSqlFunction(GridSqlFunctionType.TABLE);
-
-            sel.from(from);
-
-            GridSqlArray[] args = new GridSqlArray[cols.length];
-
-            for (int i = 0; i < cols.length; i++) {
-                GridSqlArray arr = new GridSqlArray(rows.size());
-
-                String colName = cols[i].columnName();
-
-                GridSqlAlias alias = new GridSqlAlias(colName, arr);
-
-                alias.resultType(cols[i].resultType());
-
-                from.addChild(alias);
-
-                args[i] = arr;
-
-                GridSqlColumn newCol = new GridSqlColumn(null, from, null,"TABLE", colName);
-
-                newCol.resultType(cols[i].resultType());
-
-                sel.addColumn(newCol, true);
-            }
-
-            for (GridSqlElement[] row : rows) {
-                assert cols.length == row.length;
-
-                for (int i = 0; i < row.length; i++)
-                    args[i].addChild(row[i]);
-            }
-
-            return sel;
-        }
-        else {
-            assert subQry != null;
-
-            return subQry;
-        }
-    }
-
-    /**
-     * Generate SQL SELECT based on DELETE's WHERE, LIMIT, etc.
-     *
-     * @param del Delete statement.
-     * @param keysParamIdx Index for .
-     * @return SELECT statement.
-     */
-    public static GridSqlSelect selectForDelete(GridSqlDelete del, @Nullable Integer keysParamIdx) {
-        GridSqlSelect mapQry = new GridSqlSelect();
-
-        mapQry.from(del.from());
-
-        Set<GridSqlTable> tbls = new HashSet<>();
-
-        collectAllGridTablesInTarget(del.from(), tbls);
-
-        assert tbls.size() == 1 : "Failed to determine target table for DELETE";
-
-        GridSqlTable tbl = tbls.iterator().next();
-
-        GridH2Table gridTbl = tbl.dataTable();
-
-        assert gridTbl != null : "Failed to determine target grid table for DELETE";
-
-        Column h2KeyCol = gridTbl.getColumn(GridH2KeyValueRowOnheap.KEY_COL);
-
-        Column h2ValCol = gridTbl.getColumn(GridH2KeyValueRowOnheap.VAL_COL);
-
-        GridSqlColumn keyCol = new GridSqlColumn(h2KeyCol, tbl, h2KeyCol.getName());
-        keyCol.resultType(GridSqlType.fromColumn(h2KeyCol));
-
-        GridSqlColumn valCol = new GridSqlColumn(h2ValCol, tbl, h2ValCol.getName());
-        valCol.resultType(GridSqlType.fromColumn(h2ValCol));
-
-        mapQry.addColumn(keyCol, true);
-        mapQry.addColumn(valCol, true);
-
-        GridSqlElement where = del.where();
-        if (keysParamIdx != null)
-            where = injectKeysFilterParam(where, keyCol, keysParamIdx);
-
-        mapQry.where(where);
-        mapQry.limit(del.limit());
-
-        return mapQry;
-    }
-
-    /**
-     * @param update UPDATE statement.
-     * @return {@code null} if given statement directly updates {@code _val} column with a literal or param value
-     * and filters by single non expression key (and, optionally,  by single non expression value).
-     */
-    public static FastUpdateArguments getFastUpdateArgs(GridSqlUpdate update) {
-        IgnitePair<GridSqlElement> filter = findKeyValueEqualityCondition(update.where());
-
-        if (filter == null)
-            return null;
-
-        if (update.cols().size() != 1)
-            return null;
-
-        Table tbl = update.cols().get(0).column().getTable();
-        if (!(tbl instanceof GridH2Table))
-            return null;
-
-        GridH2RowDescriptor desc = ((GridH2Table)tbl).rowDescriptor();
-        if (!desc.isValueColumn(update.cols().get(0).column().getColumnId()))
-            return null;
-
-        GridSqlElement set = update.set().get(update.cols().get(0).columnName());
-
-        if (!(set instanceof GridSqlConst || set instanceof GridSqlParameter))
-            return null;
-
-        return new FastUpdateArguments(operandForElement(filter.getKey()), operandForElement(filter.getValue()),
-            operandForElement(set));
-    }
-
-    /**
-     * Create operand based on exact type of SQL element.
-     *
-     * @param el element.
-     * @return Operand.
-     */
-    private static FastUpdateArgument operandForElement(GridSqlElement el) {
-        assert el == null ^ (el instanceof GridSqlConst || el instanceof GridSqlParameter);
-
-        if (el == null)
-            return FastUpdateArguments.NULL_ARGUMENT;
-
-        if (el instanceof GridSqlConst)
-            return new ValueArgument(((GridSqlConst)el).value().getObject());
-        else
-            return new ParamArgument(((GridSqlParameter)el).index());
-    }
-
-    /**
-     * @param del DELETE statement.
-     * @return {@code true} if given statement filters by single non expression key.
-     */
-    public static FastUpdateArguments getFastDeleteArgs(GridSqlDelete del) {
-        IgnitePair<GridSqlElement> filter = findKeyValueEqualityCondition(del.where());
-
-        if (filter == null)
-            return null;
-
-        return new FastUpdateArguments(operandForElement(filter.getKey()), operandForElement(filter.getValue()),
-            FastUpdateArguments.NULL_ARGUMENT);
-    }
-
-    /**
-     * @param where Element to test.
-     * @return Whether given element corresponds to {@code WHERE _key = ?}, and key is a literal expressed
-     * in query or a query param.
-     */
-    private static IgnitePair<GridSqlElement> findKeyValueEqualityCondition(GridSqlElement where) {
-        if (where == null || !(where instanceof GridSqlOperation))
-            return null;
-
-        GridSqlOperation whereOp = (GridSqlOperation) where;
-
-        // Does this WHERE limit only by _key?
-        if (isKeyEqualityCondition(whereOp))
-            return new IgnitePair<>((GridSqlElement)whereOp.child(1), null);
-
-        // Or maybe it limits both by _key and _val?
-        if (whereOp.operationType() != GridSqlOperationType.AND)
-            return null;
-
-        GridSqlElement left = whereOp.child(0);
-
-        GridSqlElement right = whereOp.child(1);
-
-        if (!(left instanceof GridSqlOperation && right instanceof GridSqlOperation))
-            return null;
-
-        GridSqlOperation leftOp = (GridSqlOperation) left;
-
-        GridSqlOperation rightOp = (GridSqlOperation) right;
-
-        if (isKeyEqualityCondition(leftOp)) { // _key = ? and _val = ?
-            if (!isValueEqualityCondition(rightOp))
-                return null;
-
-            return new IgnitePair<>((GridSqlElement)leftOp.child(1), (GridSqlElement)rightOp.child(1));
-        }
-        else if (isKeyEqualityCondition(rightOp)) { // _val = ? and _key = ?
-            if (!isValueEqualityCondition(leftOp))
-                return null;
-
-            return new IgnitePair<>((GridSqlElement)rightOp.child(1), (GridSqlElement)leftOp.child(1));
-        }
-        else // Neither
-            return null;
-    }
-
-    /**
-     * @param op Operation.
-     * @param key true - check for key equality condition,
-     *            otherwise check for value equality condition
-     * @return Whether this condition is of form {@code colName} = ?
-     */
-    private static boolean isEqualityCondition(GridSqlOperation op, boolean key) {
-        if (op.operationType() != GridSqlOperationType.EQUAL)
-            return false;
-
-        GridSqlElement left = op.child(0);
-        GridSqlElement right = op.child(1);
-
-        if (!(left instanceof GridSqlColumn))
-            return false;
-
-        GridSqlColumn column = (GridSqlColumn)left;
-        if (!(column.column().getTable() instanceof GridH2Table))
-            return false;
-
-        GridH2RowDescriptor desc =((GridH2Table) column.column().getTable()).rowDescriptor();
-
-        return  (key ? desc.isKeyColumn(column.column().getColumnId()) :
-                       desc.isValueColumn(column.column().getColumnId())) &&
-                (right instanceof GridSqlConst || right instanceof GridSqlParameter);
-    }
-
-    /**
-     * @param op Operation.
-     * @return Whether this condition is of form _key = ?
-     */
-    private static boolean isKeyEqualityCondition(GridSqlOperation op) {
-        return isEqualityCondition(op, true);
-    }
-
-    /**
-     * @param op Operation.
-     * @return Whether this condition is of form _val = ?
-     */
-    private static boolean isValueEqualityCondition(GridSqlOperation op) {
-        return isEqualityCondition(op, false);
-    }
-
-
-    /**
-     * Generate SQL SELECT based on UPDATE's WHERE, LIMIT, etc.
-     *
-     * @param update Update statement.
-     * @param keysParamIdx Index of new param for the array of keys.
-     * @return SELECT statement.
-     */
-    public static GridSqlSelect selectForUpdate(GridSqlUpdate update, @Nullable Integer keysParamIdx) {
-        GridSqlSelect mapQry = new GridSqlSelect();
-
-        mapQry.from(update.target());
-
-        Set<GridSqlTable> tbls = new HashSet<>();
-
-        collectAllGridTablesInTarget(update.target(), tbls);
-
-        assert tbls.size() == 1 : "Failed to determine target table for UPDATE";
-
-        GridSqlTable tbl = tbls.iterator().next();
-
-        GridH2Table gridTbl = tbl.dataTable();
-
-        assert gridTbl != null : "Failed to determine target grid table for UPDATE";
-
-        Column h2KeyCol = gridTbl.getColumn(GridH2KeyValueRowOnheap.KEY_COL);
-
-        Column h2ValCol = gridTbl.getColumn(GridH2KeyValueRowOnheap.VAL_COL);
-
-        GridSqlColumn keyCol = new GridSqlColumn(h2KeyCol, tbl, h2KeyCol.getName());
-        keyCol.resultType(GridSqlType.fromColumn(h2KeyCol));
-
-        GridSqlColumn valCol = new GridSqlColumn(h2ValCol, tbl, h2ValCol.getName());
-        valCol.resultType(GridSqlType.fromColumn(h2ValCol));
-
-        mapQry.addColumn(keyCol, true);
-        mapQry.addColumn(valCol, true);
-
-        for (GridSqlColumn c : update.cols()) {
-            String newColName = Parser.quoteIdentifier("_upd_" + c.columnName());
-            // We have to use aliases to cover cases when the user
-            // wants to update _val field directly (if it's a literal)
-            GridSqlAlias alias = new GridSqlAlias(newColName, elementOrDefault(update.set().get(c.columnName()), c), true);
-            alias.resultType(c.resultType());
-            mapQry.addColumn(alias, true);
-        }
-
-        GridSqlElement where = update.where();
-        if (keysParamIdx != null)
-            where = injectKeysFilterParam(where, keyCol, keysParamIdx);
-
-        mapQry.where(where);
-        mapQry.limit(update.limit());
-
-        return mapQry;
-    }
-
-    /**
-     * Do what we can to compute default value for this column (mimics H2 behavior).
-     * @see Table#getDefaultValue
-     * @see Column#validateConvertUpdateSequence
-     * @param el SQL element.
-     * @param col Column.
-     * @return {@link GridSqlConst#NULL}, if {@code el} is null, or {@code el} if
-     * it's not {@link GridSqlKeyword#DEFAULT}, or computed default value.
-     */
-    private static GridSqlElement elementOrDefault(GridSqlElement el, GridSqlColumn col) {
-        if (el == null)
-            return GridSqlConst.NULL;
-
-        if (el != GridSqlKeyword.DEFAULT)
-            return el;
-
-        Column h2Col = col.column();
-
-        Expression dfltExpr = h2Col.getDefaultExpression();
-
-        Value dfltVal;
-
-        try {
-            dfltVal = dfltExpr != null ? dfltExpr.getValue(null) : null;
-        }
-        catch (Exception ignored) {
-            throw new IgniteSQLException("Failed to evaluate default value for a column " + col.columnName());
-        }
-
-        if (dfltVal != null)
-            return new GridSqlConst(dfltVal);
-
-        int type = h2Col.getType();
-
-        DataType dt = DataType.getDataType(type);
-
-        if (dt.decimal)
-            dfltVal = ValueInt.get(0).convertTo(type);
-        else if (dt.type == Value.TIMESTAMP)
-            dfltVal = ValueTimestamp.fromMillis(U.currentTimeMillis());
-        else if (dt.type == Value.TIME)
-            dfltVal = ValueTime.fromNanos(0);
-        else if (dt.type == Value.DATE)
-            dfltVal = ValueDate.fromMillis(U.currentTimeMillis());
-        else
-            dfltVal = ValueString.get("").convertTo(type);
-
-        return new GridSqlConst(dfltVal);
-    }
-
-    /**
-     * Append additional condition to WHERE for it to select only specific keys.
-     *
-     * @param where Initial condition.
-     * @param keyCol Column to base the new condition on.
-     * @return New condition.
-     */
-    private static GridSqlElement injectKeysFilterParam(GridSqlElement where, GridSqlColumn keyCol, int paramIdx) {
-        // Yes, we need a subquery for "WHERE _key IN ?" to work with param being an array without dirty query rewriting.
-        GridSqlSelect sel = new GridSqlSelect();
-
-        GridSqlFunction from = new GridSqlFunction(GridSqlFunctionType.TABLE);
-
-        sel.from(from);
-
-        GridSqlColumn col = new GridSqlColumn(null, from, null, "TABLE", "_IGNITE_ERR_KEYS");
-
-        sel.addColumn(col, true);
-
-        GridSqlAlias alias = new GridSqlAlias("_IGNITE_ERR_KEYS", new GridSqlParameter(paramIdx));
-
-        alias.resultType(keyCol.resultType());
-
-        from.addChild(alias);
-
-        GridSqlElement e = new GridSqlOperation(GridSqlOperationType.IN, keyCol, new GridSqlSubquery(sel));
-
-        if (where == null)
-            return e;
-        else
-            return new GridSqlOperation(GridSqlOperationType.AND, where, e);
-    }
-
-    /**
-     * @param qry Select.
-     * @param params Parameters.
-     * @param target Extracted parameters.
-     * @param paramIdxs Parameter indexes.
-     * @return Extracted parameters list.
-     */
-    private static List<Object> findParams(GridSqlQuery qry, Object[] params, ArrayList<Object> target,
-                                           IntArray paramIdxs) {
-        if (qry instanceof GridSqlSelect)
-            return findParams((GridSqlSelect)qry, params, target, paramIdxs);
-
-        GridSqlUnion union = (GridSqlUnion)qry;
-
-        findParams(union.left(), params, target, paramIdxs);
-        findParams(union.right(), params, target, paramIdxs);
-
-        findParams((GridSqlElement)qry.limit(), params, target, paramIdxs);
-        findParams((GridSqlElement)qry.offset(), params, target, paramIdxs);
-
-        return target;
-    }
-
-    /**
-     * @param qry Select.
-     * @param params Parameters.
-     * @param target Extracted parameters.
-     * @param paramIdxs Parameter indexes.
-     * @return Extracted parameters list.
-     */
-    private static List<Object> findParams(GridSqlSelect qry, Object[] params, ArrayList<Object> target,
-                                           IntArray paramIdxs) {
-        if (params.length == 0)
-            return target;
-
-        for (GridSqlAst el : qry.columns(false))
-            findParams((GridSqlElement)el, params, target, paramIdxs);
-
-        findParams((GridSqlElement)qry.from(), params, target, paramIdxs);
-        findParams((GridSqlElement)qry.where(), params, target, paramIdxs);
-
-        // Don't search in GROUP BY and HAVING since they expected to be in select list.
-
-        findParams((GridSqlElement)qry.limit(), params, target, paramIdxs);
-        findParams((GridSqlElement)qry.offset(), params, target, paramIdxs);
-
-        return target;
-    }
-
-    /**
-     * @param el Element.
-     * @param params Parameters.
-     * @param target Extracted parameters.
-     * @param paramIdxs Parameter indexes.
-     */
-    private static void findParams(@Nullable GridSqlElement el, Object[] params, ArrayList<Object> target,
-                                   IntArray paramIdxs) {
-        if (el == null)
-            return;
-
-        if (el instanceof GridSqlParameter) {
-            // H2 Supports queries like "select ?5" but first 4 non-existing parameters are need to be set to any value.
-            // Here we will set them to NULL.
-            final int idx = ((GridSqlParameter)el).index();
-
-            while (target.size() < idx)
-                target.add(null);
-
-            if (params.length <= idx)
-                throw new IgniteException("Invalid number of query parameters. " +
-                    "Cannot find " + idx + " parameter.");
-
-            Object param = params[idx];
-
-            if (idx == target.size())
-                target.add(param);
-            else
-                target.set(idx, param);
-
-            paramIdxs.add(idx);
-        }
-        else if (el instanceof GridSqlSubquery)
-            findParams(((GridSqlSubquery)el).subquery(), params, target, paramIdxs);
-        else
-            for (int i = 0; i < el.size(); i++)
-                findParams((GridSqlElement)el.child(i), params, target, paramIdxs);
-    }
-
-    /**
-     * Processes all the tables and subqueries using the given closure.
-     *
-     * @param from FROM element.
-     * @param c Closure each found table and subquery will be passed to. If returns {@code true} the we need to stop.
-     * @return {@code true} If we have found.
-     */
-    private static boolean findTablesInFrom(GridSqlElement from, IgnitePredicate<GridSqlElement> c) {
-        if (from == null)
-            return false;
-
-        if (from instanceof GridSqlTable || from instanceof GridSqlSubquery)
-            return c.apply(from);
-
-        if (from instanceof GridSqlJoin) {
-            // Left and right.
-            if (findTablesInFrom((GridSqlElement)from.child(0), c))
-                return true;
-
-            if (findTablesInFrom((GridSqlElement)from.child(1), c))
-                return true;
-
-            // We don't process ON condition because it is not a joining part of from here.
-            return false;
-        }
-        else if (from instanceof GridSqlAlias)
-            return findTablesInFrom((GridSqlElement)from.child(), c);
-        else if (from instanceof GridSqlFunction)
-            return false;
-
-        throw new IllegalStateException(from.getClass().getName() + " : " + from.getSQL());
-    }
-
-    /**
-     * @param from From element.
-     * @param tbls Tables.
-     */
-    public static void collectAllGridTablesInTarget(GridSqlElement from, final Set<GridSqlTable> tbls) {
-        findTablesInFrom(from, new IgnitePredicate<GridSqlElement>() {
-            @Override public boolean apply(GridSqlElement el) {
-                if (el instanceof GridSqlTable)
-                    tbls.add((GridSqlTable)el);
-
-                return false;
-            }
-        });
-    }
-
-    /**
-     * @param target Expression to extract the table from.
-     * @return Back end table for this element.
-     */
-    public static GridSqlTable gridTableForElement(GridSqlElement target) {
-        Set<GridSqlTable> tbls = new HashSet<>();
-
-        collectAllGridTablesInTarget(target, tbls);
-
-        if (tbls.size() != 1)
-            throw new IgniteSQLException("Failed to determine target table", IgniteQueryErrorCode.TABLE_NOT_FOUND);
-
-        return tbls.iterator().next();
-    }
-
-    /** 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/03bb5513/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
index 8ffc5fa..3b19e39 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
@@ -36,6 +36,7 @@ import org.apache.ignite.cache.QueryIndexType;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.internal.processors.query.h2.dml.DmlAstUtils;
 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.util.typedef.F;


Mime
View raw message