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;