This is an automated email from the ASF dual-hosted git repository.
jooger pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new d250e635e35 IGNITE-25560 Sql. Partition awareness cover extension
(#6418)
d250e635e35 is described below
commit d250e635e35b9bc5196c52a210c472f2c54b3206
Author: Max Zhuravkov <[email protected]>
AuthorDate: Wed Aug 20 09:38:09 2025 +0300
IGNITE-25560 Sql. Partition awareness cover extension (#6418)
---
.../sql/engine/prepare/PrepareServiceImpl.java | 81 +++++++---
.../sql/engine/prepare/RelWithSources.java | 67 +++++++++
.../PartitionAwarenessMetadata.java | 3 +-
.../PartitionAwarenessMetadataExtractor.java | 163 ++++++++++++++++++---
.../ignite/internal/sql/engine/util/Cloner.java | 42 ++++--
.../sql/engine/exec/mapping/MappingTestRunner.java | 20 ++-
.../planner/PartitionPruningMetadataTest.java | 6 +-
.../sql/engine/planner/PartitionPruningTest.java | 22 +++
.../PartitionAwarenessMetadataTest.java | 148 +++++++++++++++----
9 files changed, 462 insertions(+), 90 deletions(-)
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java
index 395973ad106..0f24814d15d 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java
@@ -26,7 +26,6 @@ import static
org.apache.ignite.internal.sql.engine.util.Commons.fastQueryOptimi
import static
org.apache.ignite.internal.thread.ThreadOperation.NOTHING_ALLOWED;
import static org.apache.ignite.lang.ErrorGroups.Sql.EXECUTION_CANCELLED_ERR;
-import it.unimi.dsi.fastutil.ints.IntObjectPair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -453,14 +452,27 @@ public class PrepareServiceImpl implements PrepareService
{
IgniteKeyValueGet kvGet = (IgniteKeyValueGet) optimizedRel;
return new KeyValueGetPlan(
- nextPlanId(), catalogVersion, kvGet,
resultSetMetadata,
- parameterMetadata, relWithMetadata.paMetadata,
relWithMetadata.ppMetadata
+ nextPlanId(),
+ catalogVersion,
+ kvGet,
+ resultSetMetadata,
+ parameterMetadata,
+ relWithMetadata.paMetadata,
+ relWithMetadata.ppMetadata
);
}
var plan = new MultiStepPlan(
- nextPlanId(), SqlQueryType.QUERY, optimizedRel,
resultSetMetadata, parameterMetadata, catalogVersion,
- relWithMetadata.numTables, fastPlan,
relWithMetadata.paMetadata, relWithMetadata.ppMetadata
+ nextPlanId(),
+ SqlQueryType.QUERY,
+ optimizedRel,
+ resultSetMetadata,
+ parameterMetadata,
+ catalogVersion,
+ relWithMetadata.numSources,
+ fastPlan,
+ relWithMetadata.paMetadata,
+ relWithMetadata.ppMetadata
);
logPlan(parsedResult.originalQuery(), plan);
@@ -523,13 +535,25 @@ public class PrepareServiceImpl implements PrepareService
{
ExplainablePlan plan;
if (optimizedRel instanceof IgniteKeyValueModify) {
plan = new KeyValueModifyPlan(
- nextPlanId(), ctx.catalogVersion(), (IgniteKeyValueModify)
optimizedRel, DML_METADATA,
- parameterMetadata, null, null
+ nextPlanId(),
+ ctx.catalogVersion(),
+ (IgniteKeyValueModify) optimizedRel,
+ DML_METADATA,
+ parameterMetadata,
+ relWithMetadata.paMetadata,
+ relWithMetadata.ppMetadata
);
} else {
plan = new MultiStepPlan(
- nextPlanId(), SqlQueryType.DML, optimizedRel,
DML_METADATA, parameterMetadata, ctx.catalogVersion(),
- relWithMetadata.numTables, null,
relWithMetadata.paMetadata, relWithMetadata.ppMetadata
+ nextPlanId(),
+ SqlQueryType.DML,
+ optimizedRel, DML_METADATA,
+ parameterMetadata,
+ ctx.catalogVersion(),
+ relWithMetadata.numSources,
+ null,
+ relWithMetadata.paMetadata,
+ relWithMetadata.ppMetadata
);
}
@@ -584,13 +608,26 @@ public class PrepareServiceImpl implements PrepareService
{
IgniteKeyValueModify kvModify = (IgniteKeyValueModify)
optimizedRel;
plan = new KeyValueModifyPlan(
- nextPlanId(), catalogVersion, kvModify,
DML_METADATA,
- parameterMetadata, relWithMetadata.paMetadata,
relWithMetadata.ppMetadata
+ nextPlanId(),
+ catalogVersion,
+ kvModify,
+ DML_METADATA,
+ parameterMetadata,
+ relWithMetadata.paMetadata,
+ relWithMetadata.ppMetadata
);
} else {
plan = new MultiStepPlan(
- nextPlanId(), SqlQueryType.DML, optimizedRel,
DML_METADATA, parameterMetadata, catalogVersion,
- relWithMetadata.numTables, null,
relWithMetadata.paMetadata, relWithMetadata.ppMetadata
+ nextPlanId(),
+ SqlQueryType.DML,
+ optimizedRel,
+ DML_METADATA,
+ parameterMetadata,
+ catalogVersion,
+ relWithMetadata.numSources,
+ null,
+ relWithMetadata.paMetadata,
+ relWithMetadata.ppMetadata
);
}
@@ -757,16 +794,16 @@ public class PrepareServiceImpl implements PrepareService
{
// cluster keeps a lot of cached stuff that won't be used anymore.
// In order let GC collect that, let's reattach tree to an empty
cluster
// before storing tree in plan cache
- IntObjectPair<IgniteRel> pair =
Cloner.cloneAndAssignSourceId(igniteRel, Commons.emptyCluster());
- int numTables = pair.firstInt();
- IgniteRel rel = pair.right();
-
- PartitionAwarenessMetadata partitionAwarenessMetadata =
- PartitionAwarenessMetadataExtractor.getMetadata(rel);
+ RelWithSources reWithSources =
Cloner.cloneAndAssignSourceId(igniteRel, Commons.emptyCluster());
+ int numTables = reWithSources.sources().size();
+ IgniteRel rel = reWithSources.root();
PartitionPruningMetadata partitionPruningMetadata = new
PartitionPruningMetadataExtractor()
.go(rel);
+ PartitionAwarenessMetadata partitionAwarenessMetadata =
+ PartitionAwarenessMetadataExtractor.getMetadata(reWithSources,
partitionPruningMetadata);
+
return new RelWithMetadata(rel, numTables, partitionAwarenessMetadata,
partitionPruningMetadata);
}
@@ -861,16 +898,16 @@ public class PrepareServiceImpl implements PrepareService
{
final IgniteRel rel;
final @Nullable PartitionAwarenessMetadata paMetadata;
final @Nullable PartitionPruningMetadata ppMetadata;
- final int numTables;
+ final int numSources;
RelWithMetadata(
IgniteRel rel,
- int numTables,
+ int numSources,
@Nullable PartitionAwarenessMetadata paMetadata,
@Nullable PartitionPruningMetadata ppMetadata
) {
this.rel = rel;
- this.numTables = numTables;
+ this.numSources = numSources;
this.paMetadata = paMetadata;
this.ppMetadata = ppMetadata;
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/RelWithSources.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/RelWithSources.java
new file mode 100644
index 00000000000..866b6ef8b4c
--- /dev/null
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/RelWithSources.java
@@ -0,0 +1,67 @@
+/*
+ * 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.sql.engine.prepare;
+
+import it.unimi.dsi.fastutil.ints.IntSet;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
+
+/**
+ * Relation with sources.
+ */
+public final class RelWithSources {
+
+ private final IgniteRel rel;
+
+ private final Long2ObjectMap<IgniteRel> sourceRels;
+
+ private final IntSet modifiedTables;
+
+ /**
+ * Constructor.
+ *
+ * @param rel Relation.
+ * @param sourceRels Source relations.
+ * @param modifiedTables Modified tables.
+ */
+ public RelWithSources(IgniteRel rel, Long2ObjectMap<IgniteRel> sourceRels,
IntSet modifiedTables) {
+ this.rel = rel;
+ this.sourceRels = sourceRels;
+ this.modifiedTables = modifiedTables;
+ }
+
+ /** Plan. */
+ public IgniteRel root() {
+ return rel;
+ }
+
+ /** Returns tables modified by the plan. */
+ public IntSet modifiedTables() {
+ return modifiedTables;
+ }
+
+ /** Returns a source relation by the given id. */
+ public IgniteRel get(long sourceId) {
+ return sourceRels.get(sourceId);
+ }
+
+ /** Returns a map of source relations. */
+ public Long2ObjectMap<IgniteRel> sources() {
+ return sourceRels;
+ }
+}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadata.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadata.java
index 49e836b12bd..bb9c6512105 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadata.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadata.java
@@ -110,7 +110,8 @@ public final class PartitionAwarenessMetadata {
public String toString() {
return S.toString(PartitionAwarenessMetadata.class, this,
"indexes", Arrays.toString(indexes),
- "hash", Arrays.toString(hash)
+ "hash", Arrays.toString(hash),
+ "directTxMode", directTxMode
);
}
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadataExtractor.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadataExtractor.java
index 899f9110518..a0de72232fd 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadataExtractor.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadataExtractor.java
@@ -17,19 +17,27 @@
package org.apache.ignite.internal.sql.engine.prepare.partitionawareness;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import java.util.List;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.rex.RexDynamicParam;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.ImmutableIntList;
+import org.apache.ignite.internal.sql.engine.prepare.RelWithSources;
+import
org.apache.ignite.internal.sql.engine.prepare.pruning.PartitionPruningColumns;
+import
org.apache.ignite.internal.sql.engine.prepare.pruning.PartitionPruningMetadata;
import org.apache.ignite.internal.sql.engine.rel.IgniteKeyValueGet;
import org.apache.ignite.internal.sql.engine.rel.IgniteKeyValueModify;
import
org.apache.ignite.internal.sql.engine.rel.IgniteKeyValueModify.Operation;
import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
+import org.apache.ignite.internal.sql.engine.rel.IgniteTableFunctionScan;
import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
+import org.apache.ignite.internal.sql.engine.sql.fun.IgniteSqlOperatorTable;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.Primitives;
@@ -67,15 +75,22 @@ public class PartitionAwarenessMetadataExtractor {
/**
* Extracts partition awareness metadata from the given plan.
*
- * @param rel Plan.
+ * @param relationWithSources Relation with sources.
+ * @param partitionPruningMetadata Partition-pruning metadata.
* @return Metadata.
*/
- @Nullable
- public static PartitionAwarenessMetadata getMetadata(IgniteRel rel) {
+ public static @Nullable PartitionAwarenessMetadata getMetadata(
+ RelWithSources relationWithSources,
+ @Nullable PartitionPruningMetadata partitionPruningMetadata
+ ) {
+ IgniteRel rel = relationWithSources.root();
+
if (rel instanceof IgniteKeyValueGet) {
return getMetadata((IgniteKeyValueGet) rel);
} else if (rel instanceof IgniteKeyValueModify) {
return getMetadata((IgniteKeyValueModify) rel);
+ } else if (partitionPruningMetadata != null) {
+ return tryConvertPartitionPruningMetadata(relationWithSources,
partitionPruningMetadata);
} else {
return null;
}
@@ -128,8 +143,6 @@ public class PartitionAwarenessMetadataExtractor {
int[] indexes = new int[colocationKeys.size()];
IntArrayList hashFields = new IntArrayList(colocationKeys.size() / 2);
- int hashPos = -1;
-
for (int i = 0; i < colocationKeys.size(); i++) {
int colIdx = colocationKeys.get(i);
RexNode expr;
@@ -141,34 +154,140 @@ public class PartitionAwarenessMetadataExtractor {
expr = expressions.get(keyIdx);
}
- if (expr instanceof RexDynamicParam) {
- RexDynamicParam dynamicParam = (RexDynamicParam) expr;
- indexes[i] = dynamicParam.getIndex();
- } else if (expr instanceof RexLiteral) {
- RexLiteral expr0 = (RexLiteral) expr;
+ boolean added = addToMetadata(expr, indexes, i, hashFields);
+ if (!added) {
+ return null;
+ }
+ }
+
+ int[] hash = hashFields.toIntArray();
+
+ return new PartitionAwarenessMetadata(igniteTable.id(), indexes, hash,
directTxMode);
+ }
+
+ private static @Nullable PartitionAwarenessMetadata
tryConvertPartitionPruningMetadata(
+ RelWithSources relationWithSources,
+ PartitionPruningMetadata metadata
+ ) {
+ // Partition awareness metadata is created once per source table,
+ // so we do not consider plan that have more then 1 source.
+ if (metadata.data().size() != 1) {
+ return null;
+ }
- // depends on supplied zoneId, it can`t be cached
- if (expr0.getTypeName() ==
SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) {
- return null;
- }
+ Long2ObjectMap.Entry<PartitionPruningColumns> entry = metadata.data()
+ .long2ObjectEntrySet()
+ .iterator().next();
- indexes[i] = hashPos--;
+ long sourceId = entry.getLongKey();
+ IgniteRel sourceRel = relationWithSources.get(sourceId);
+ assert sourceRel != null;
- Class<?> internalType = Primitives.wrap((Class<?>)
Commons.typeFactory().getJavaClass(expr0.getType()));
- Object val = RexUtils.literalValue(FaultyContext.INSTANCE,
expr0, internalType);
+ RelOptTable optTable = sourceRel.getTable();
+ assert optTable != null;
+
+ IgniteTable igniteTable = optTable.unwrap(IgniteTable.class);
+ assert igniteTable != null;
- NativeType nativeType =
IgniteTypeFactory.relDataTypeToNative(expr0.getType());
+ // Partition pruning (PP) metadata includes information to identify
all possible partitions.
+ // However, partition awareness restricts execution to a single
partition,
+ // so we should reject PP metadata that has more than one set of
columns.
+ //
+ // Ignore PP with correlated variables as well, because some queries
+ // can access additional partitions.
+ PartitionPruningColumns columns = entry.getValue();
+ if (columns.columns().size() != 1 ||
columns.containCorrelatedVariables()) {
+ return null;
+ }
- val = TypeUtils.fromInternal(val, nativeType.spec());
+ boolean dml =
relationWithSources.modifiedTables().contains(igniteTable.id());
+ long numSources = numberOfModifyAndSourceRels(relationWithSources);
- hashFields.add(ColocationUtils.hash(val, nativeType));
- } else {
+ // Accept queries that have exactly one source rel.
+ if (!dml && numSources != 1) {
+ return null;
+ }
+
+ // Accept DMLs that have a ModifyNode and a single source rel.
+ if (dml && numSources != 2) {
+ return null;
+ }
+
+ // Choose appropriate tx mode.
+ DirectTxMode directTxMode = dml ? DirectTxMode.NOT_SUPPORTED :
DirectTxMode.SUPPORTED;
+
+ ImmutableIntList colocationKeys = igniteTable.distribution().getKeys();
+ int[] indexes = new int[colocationKeys.size()];
+ IntArrayList hashFields = new IntArrayList(colocationKeys.size());
+ Int2ObjectMap<RexNode> cols = columns.columns().get(0);
+
+ for (Int2ObjectMap.Entry<RexNode> colEntry :
cols.int2ObjectEntrySet()) {
+ RexNode colExpr = colEntry.getValue();
+ int colIdx = colEntry.getIntKey();
+ int i = colocationKeys.indexOf(colIdx);
+ assert i >= 0 : "Invalid colocation column index: " +
cols.keySet();
+
+ boolean added = addToMetadata(colExpr, indexes, i, hashFields);
+ if (!added) {
return null;
}
}
- int[] hash = hashFields.toArray(new int[0]);
+ int[] hash = hashFields.toIntArray();
return new PartitionAwarenessMetadata(igniteTable.id(), indexes, hash,
directTxMode);
}
+
+ private static long numberOfModifyAndSourceRels(RelWithSources
relationWithSources) {
+ Long2ObjectMap<IgniteRel> sources = relationWithSources.sources();
+ // When counting the number of source relations ignore safe table
functions as they these function
+ // produce the same result and do not affect / are not affected by
data distribution.
+ return sources.values().stream()
+ .filter(r -> {
+ if (!(r instanceof IgniteTableFunctionScan)) {
+ return true;
+ } else {
+ // Only allow to use the SYSTEM_RANGE table function,
+ // since that function always produces the same results
+ // and does not require any external dependencies to
run.
+ IgniteTableFunctionScan scan =
(IgniteTableFunctionScan) r;
+ return !RexUtil.isCallTo(scan.getCall(),
IgniteSqlOperatorTable.SYSTEM_RANGE);
+ }
+ })
+ .count();
+ }
+
+ private static boolean addToMetadata(RexNode colExpr, int[] indexes, int
i, IntArrayList hashFields) {
+ if (colExpr instanceof RexDynamicParam) {
+ RexDynamicParam dynamicParam = (RexDynamicParam) colExpr;
+ indexes[i] = dynamicParam.getIndex();
+
+ return true;
+ } else if (colExpr instanceof RexLiteral) {
+ RexLiteral literal = (RexLiteral) colExpr;
+
+ // depends on supplied zoneId, it can`t be cached
+ if (literal.getTypeName() ==
SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) {
+ return false;
+ }
+
+ int hashValue = computeHash(literal);
+ hashFields.add(hashValue);
+ indexes[i] = -hashFields.size();
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static int computeHash(RexLiteral literal) {
+ Class<?> internalType = Primitives.wrap((Class<?>)
Commons.typeFactory().getJavaClass(literal.getType()));
+ Object val = RexUtils.literalValue(FaultyContext.INSTANCE, literal,
internalType);
+
+ NativeType nativeType =
IgniteTypeFactory.relDataTypeToNative(literal.getType());
+ Object internalVal = TypeUtils.fromInternal(val, nativeType.spec());
+
+ return ColocationUtils.hash(internalVal, nativeType);
+ }
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Cloner.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Cloner.java
index 80245a23908..6468d623440 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Cloner.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Cloner.java
@@ -17,18 +17,24 @@
package org.apache.ignite.internal.sql.engine.util;
-import it.unimi.dsi.fastutil.ints.IntObjectImmutablePair;
-import it.unimi.dsi.fastutil.ints.IntObjectPair;
+import it.unimi.dsi.fastutil.ints.IntArraySet;
+import it.unimi.dsi.fastutil.ints.IntSet;
+import it.unimi.dsi.fastutil.ints.IntSets;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.ArrayList;
import java.util.List;
import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptTable;
import org.apache.ignite.internal.sql.engine.prepare.IgniteRelShuttle;
+import org.apache.ignite.internal.sql.engine.prepare.RelWithSources;
import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
+import org.apache.ignite.internal.sql.engine.rel.IgniteTableModify;
import org.apache.ignite.internal.sql.engine.rel.SourceAwareIgniteRel;
+import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
/**
- * Utility class to clone relational tree and optionally replace assigned
{@link RelOptCluster cluster}
- * to another one.
+ * Utility class to clone relational tree and optionally replace assigned
{@link RelOptCluster cluster} to another one.
*/
public class Cloner {
private final RelOptCluster cluster;
@@ -61,19 +67,22 @@ public class Cloner {
* @param cluster Cluster.
* @return The number of source relations in the given plan and the plan
itself.
*/
- public static IntObjectPair<IgniteRel> cloneAndAssignSourceId(IgniteRel
root, RelOptCluster cluster) {
+ public static RelWithSources cloneAndAssignSourceId(IgniteRel root,
RelOptCluster cluster) {
CloneAndAssignIds assigner = new CloneAndAssignIds(cluster);
IgniteRel result = assigner.visit(root);
- int numSources = assigner.sourceIndex;
- return new IntObjectImmutablePair<>(numSources, result);
+ return new RelWithSources(result, assigner.sources,
assigner.modifiedTables);
}
private static class CloneAndAssignIds extends IgniteRelShuttle {
private final RelOptCluster cluster;
- private int sourceIndex;
+ private long sourceIndex;
+
+ private final Long2ObjectMap<IgniteRel> sources = new
Long2ObjectOpenHashMap<>();
+
+ private IntSet modifiedTables = IntSets.emptySet();
private CloneAndAssignIds(RelOptCluster cluster) {
this.cluster = cluster;
@@ -85,14 +94,29 @@ public class Cloner {
// Take into account only actual source relations.
SourceAwareIgniteRel src = (SourceAwareIgniteRel) rel;
- int sourceId = sourceIndex++;
+ long sourceId = sourceIndex++;
IgniteRel relWithSourceId = src.clone(sourceId);
+ if (rel instanceof IgniteTableModify) {
+ RelOptTable relOptTable = rel.getTable();
+ assert relOptTable != null;
+
+ IgniteTable table = relOptTable.unwrap(IgniteTable.class);
+ assert table != null;
+
+ if (modifiedTables.isEmpty()) {
+ modifiedTables = new IntArraySet(1);
+ }
+ modifiedTables.add(table.id());
+ }
+
for (int i = 0; i < rel.getInputs().size(); i++) {
IgniteRel childNode = visit((IgniteRel) rel.getInput(i));
relWithSourceId.replaceInput(i, childNode);
}
+ sources.put(sourceId, rel);
+
return relWithSourceId;
} else {
List<IgniteRel> newChildren = new
ArrayList<>(rel.getInputs().size());
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/mapping/MappingTestRunner.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/mapping/MappingTestRunner.java
index dbbd8ef964f..680dfa0d178 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/mapping/MappingTestRunner.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/mapping/MappingTestRunner.java
@@ -21,7 +21,6 @@ import static
org.apache.ignite.internal.lang.IgniteStringFormatter.format;
import static org.apache.ignite.internal.testframework.IgniteTestUtils.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import it.unimi.dsi.fastutil.ints.IntObjectPair;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
@@ -47,6 +46,7 @@ import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.prepare.MultiStepPlan;
import org.apache.ignite.internal.sql.engine.prepare.ParameterMetadata;
import org.apache.ignite.internal.sql.engine.prepare.PlanId;
+import org.apache.ignite.internal.sql.engine.prepare.RelWithSources;
import org.apache.ignite.internal.sql.engine.prepare.pruning.PartitionPruner;
import
org.apache.ignite.internal.sql.engine.prepare.pruning.PartitionPrunerImpl;
import
org.apache.ignite.internal.sql.engine.prepare.pruning.PartitionPruningMetadata;
@@ -179,14 +179,22 @@ final class MappingTestRunner {
ResultSetMetadataImpl resultSetMetadata = new
ResultSetMetadataImpl(Collections.emptyList());
ParameterMetadata parameterMetadata = new
ParameterMetadata(Collections.emptyList());
- IntObjectPair<IgniteRel> pair = Cloner.cloneAndAssignSourceId(rel,
rel.getCluster());
- rel = pair.second();
+ RelWithSources relWithSources = Cloner.cloneAndAssignSourceId(rel,
rel.getCluster());
+ rel = relWithSources.root();
PartitionPruningMetadata partitionPruningMetadata = new
PartitionPruningMetadataExtractor().go(rel);
- MultiStepPlan multiStepPlan = new MultiStepPlan(new
PlanId(UUID.randomUUID(), 1), sqlQueryType, rel,
- resultSetMetadata, parameterMetadata,
schema.catalogVersion(),
- pair.firstInt(), null, null, partitionPruningMetadata
+ MultiStepPlan multiStepPlan = new MultiStepPlan(
+ new PlanId(UUID.randomUUID(), 1),
+ sqlQueryType,
+ rel,
+ resultSetMetadata,
+ parameterMetadata,
+ schema.catalogVersion(),
+ relWithSources.sources().size(),
+ null,
+ null,
+ partitionPruningMetadata
);
String actualText =
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PartitionPruningMetadataTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PartitionPruningMetadataTest.java
index 6afd3c22d2c..d9dd7fbf256 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PartitionPruningMetadataTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PartitionPruningMetadataTest.java
@@ -19,7 +19,6 @@ package org.apache.ignite.internal.sql.engine.planner;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import it.unimi.dsi.fastutil.ints.IntObjectPair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -32,6 +31,7 @@ import org.apache.calcite.sql.SqlExplainFormat;
import org.apache.calcite.sql.SqlExplainLevel;
import org.apache.calcite.sql.SqlKind;
import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.prepare.RelWithSources;
import
org.apache.ignite.internal.sql.engine.prepare.pruning.PartitionPruningColumns;
import
org.apache.ignite.internal.sql.engine.prepare.pruning.PartitionPruningMetadata;
import
org.apache.ignite.internal.sql.engine.prepare.pruning.PartitionPruningMetadataExtractor;
@@ -616,8 +616,8 @@ public class PartitionPruningMetadataTest extends
AbstractPlannerTest {
private void extractMetadataAndCheck(IgniteRel rel, List<String>
columnNames, List<String> expectedMetadata) {
PartitionPruningMetadataExtractor extractor = new
PartitionPruningMetadataExtractor();
- IntObjectPair<IgniteRel> pair = Cloner.cloneAndAssignSourceId(rel,
rel.getCluster());
- PartitionPruningMetadata actual = extractor.go(pair.second());
+ RelWithSources relWithSoucres = Cloner.cloneAndAssignSourceId(rel,
rel.getCluster());
+ PartitionPruningMetadata actual = extractor.go(relWithSoucres.root());
List<String> actualMetadata;
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PartitionPruningTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PartitionPruningTest.java
index 4a55c24c274..48b38305175 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PartitionPruningTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PartitionPruningTest.java
@@ -35,6 +35,7 @@ import
org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Collation;
import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
import org.apache.ignite.internal.type.NativeTypes;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
/**
@@ -209,6 +210,27 @@ public class PartitionPruningTest extends
AbstractPlannerTest {
assertEquals("[[0=2, 1=1], [0=4, 1=3]]",
PartitionPruningColumns.canonicalForm(cols).toString());
}
+ @Test
+ @Disabled("https://issues.apache.org/jira/browse/IGNITE-26203")
+ public void testInsertFromSelect() throws Exception {
+ IgniteTable table = TestBuilders.table()
+ .name("T")
+ .addKeyColumn("C1", NativeTypes.INT32)
+ .addKeyColumn("C2", NativeTypes.INT32)
+ .addColumn("C3", NativeTypes.INT32, true)
+ .distribution(TestBuilders.affinity(List.of(1, 0), 1, 2))
+ .build();
+
+ PartitionPruningMetadata actual = extractMetadata(
+ "INSERT INTO t SELECT * FROM t WHERE c2=1 and c1=2",
+ table
+ );
+
+ PartitionPruningColumns cols = actual.get(1);
+ assertNotNull(cols, "No metadata for source=1");
+ assertEquals("[[0=2, 1=1]]",
PartitionPruningColumns.canonicalForm(cols).toString());
+ }
+
@Test
public void testCorrelatedQuery() throws Exception {
IgniteTable table1 = TestBuilders.table()
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadataTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadataTest.java
index 6f7e60928b0..bb585dabf58 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadataTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/partitionawareness/PartitionAwarenessMetadataTest.java
@@ -35,6 +35,7 @@ import org.apache.ignite.internal.sql.SqlCommon;
import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
import org.apache.ignite.internal.sql.engine.framework.TestCluster;
import org.apache.ignite.internal.sql.engine.framework.TestNode;
+import org.apache.ignite.internal.sql.engine.prepare.ExplainablePlan;
import org.apache.ignite.internal.sql.engine.prepare.QueryPlan;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
@@ -98,11 +99,12 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
"KILL TRANSACTION '1'",
"CREATE TABLE x (a INT, b INT, PRIMARY KEY (a))",
"SELECT * FROM table(system_range(1, 10)) WHERE x = 1",
- "SELECT count(*) FROM t WHERE c1=?",
- "UPDATE t SET c2=1 WHERE c1=?",
+ "SELECT (SELECT MIN(c1) FROM t WHERE c1=k1) FROM t2 WHERE k1=?",
+ "SELECT (SELECT COUNT(*) FROM t2 WHERE k2=c2) FROM t WHERE t.c1=1",
})
public void noMetadata(String query) {
node.initSchema("CREATE TABLE t (c1 INT PRIMARY KEY, c2 INT)");
+ node.initSchema("CREATE TABLE t2 (k1 INT PRIMARY KEY, k2 INT)");
QueryPlan plan = node.prepare(query);
PartitionAwarenessMetadata metadata =
plan.partitionAwarenessMetadata();
@@ -112,12 +114,10 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
@ParameterizedTest
@MethodSource("simpleKeyMetadata")
public void simpleKey(String query, PartitionAwarenessMetadata expected) {
- node.initSchema("CREATE TABLE t (c1 INT PRIMARY KEY, c2 INT)");
+ node.initSchema("CREATE TABLE t (c1 INT PRIMARY KEY, c2 INT, c3 INT)");
QueryPlan plan = node.prepare(query);
- PartitionAwarenessMetadata metadata =
plan.partitionAwarenessMetadata();
-
- expectMetadata(expected, metadata);
+ expectMetadata(plan, expected);
}
private static Stream<Arguments> simpleKeyMetadata() {
@@ -133,9 +133,9 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
Arguments.of("SELECT * FROM t WHERE c2=? and c1=? and c1=?",
meta(1)),
// KV PUT
- Arguments.of("INSERT INTO t VALUES(?, ?)",
metaTrackingRequired(0)),
- Arguments.of("INSERT INTO t VALUES(1, ?)",
metaTrackingRequired(new int[]{-1}, new int[]{1})),
- Arguments.of("INSERT INTO t VALUES(1+1, ?)", null),
+ Arguments.of("INSERT INTO t VALUES(?, ?, 0)",
metaTrackingRequired(0)),
+ Arguments.of("INSERT INTO t VALUES(1, ?, 0)",
metaTrackingRequired(new int[]{-1}, new int[]{1})),
+ Arguments.of("INSERT INTO t VALUES(1+1, ?, 0)", null),
Arguments.of("INSERT INTO t(c2, c1) VALUES(?, ?)",
metaTrackingRequired(1)),
Arguments.of("INSERT INTO t(c2, c1) VALUES(1, ?)",
metaTrackingRequired(0)),
Arguments.of("INSERT INTO t(c2, c1) VALUES(?, 1)",
metaTrackingRequired(new int[]{-1}, new int[]{1})),
@@ -143,7 +143,41 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
// KV DELETE
Arguments.of("DELETE FROM t WHERE c1=?",
metaTrackingRequired(0)),
Arguments.of("DELETE FROM t WHERE c1=1",
metaTrackingRequired(new int[]{-1}, new int[]{1})),
- Arguments.of("DELETE FROM t WHERE c1=1+1",
metaTrackingRequired(new int[]{-1}, new int[]{2}))
+ Arguments.of("DELETE FROM t WHERE c1=1+1",
metaTrackingRequired(new int[]{-1}, new int[]{2})),
+
+ // SELECT
+ Arguments.of("SELECT * FROM t WHERE c1=?", meta(0)),
+ Arguments.of("SELECT * FROM t WHERE c1=? AND c2=?", meta(0)),
+ Arguments.of("SELECT c1, c2 FROM t WHERE c1=? UNION SELECT 1,
x FROM SYSTEM_RANGE(1, 100)", meta(0)),
+ Arguments.of("SELECT c1, c2 FROM t JOIN (SELECT x FROM
SYSTEM_RANGE(1, 100)) r ON r.x=c2 WHERE c1 = ? ", meta(0)),
+ Arguments.of("SELECT c1, c2 FROM t JOIN (SELECT x FROM
SYSTEM_RANGE(1, 100)) r ON r.x=c2 WHERE c1 = 1 ",
+ meta(new int[]{-1}, new int[]{1})),
+
+ // Can refer multiple partitions - skip
+ Arguments.of("SELECT * FROM t WHERE c1=1 or c1=2", null),
+ Arguments.of("SELECT * FROM t WHERE c1 IN (?, 2)", null),
+ Arguments.of("SELECT * FROM t WHERE c1=? AND c2 IN (SELECT *
FROM SYSTEM_RANGE(1, 100))", meta(0)),
+
+ // UPDATE
+ Arguments.of("UPDATE t SET c2=1 WHERE c1=?", meta(new
int[]{0}, new int[0], DirectTxMode.NOT_SUPPORTED)),
+ Arguments.of("UPDATE t SET c2=? WHERE c1=1", meta(new
int[]{-1}, new int[]{1}, DirectTxMode.NOT_SUPPORTED)),
+ Arguments.of("UPDATE t SET c2=? WHERE c1=1 AND c3 IN (SELECT *
FROM SYSTEM_RANGE(1, 100))",
+ meta(new int[]{-1}, new int[]{1},
DirectTxMode.NOT_SUPPORTED)),
+
+ // Can refer multiple partitions - skip
+ Arguments.of("UPDATE t SET c2=1 WHERE c1=1 or c1=2", null),
+ Arguments.of("UPDATE t SET c2=? WHERE c1 IN (?, 2)", null),
+
+ // INSERT
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26203 No
partition pruning metadata for INSERT INTO ... SELECT
+ // Arguments.of("INSERT INTO t SELECT 1 as c1, 2 as c2, x as
c3 FROM SYSTEM_RANGE(1, 100)",
+ // meta(new int[]{-1}, new int[]{1}),
DirectTxMode.NOT_SUPPORTED),
+
+ // DELETE
+ Arguments.of("DELETE FROM t WHERE c1=1 AND c2 IN (SELECT *
FROM SYSTEM_RANGE(1, 100)) ",
+ meta(new int[]{-1}, new int[]{1},
DirectTxMode.NOT_SUPPORTED)),
+ // Can refer multiple partitions - skip
+ Arguments.of("DELETE FROM t WHERE c1=1 or c1=2", null)
);
}
@@ -153,9 +187,7 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
node.initSchema("CREATE TABLE t (c1 INT, c2 INT, c3 TIMESTAMP WITH
LOCAL TIME ZONE, PRIMARY KEY (c3, c2))");
QueryPlan plan = node.prepare(query);
- PartitionAwarenessMetadata metadata =
plan.partitionAwarenessMetadata();
-
- expectMetadata(expected, metadata);
+ expectMetadata(plan, expected);
}
private static Stream<Arguments> tsKeyMetadata() {
@@ -165,7 +197,7 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
Arguments.of("SELECT * FROM t WHERE c2=? and c3 = TIMESTAMP
WITH LOCAL TIME ZONE '1970-01-01 00:00:00'", null),
// KV PUT
- Arguments.of("INSERT INTO t VALUES (?, ?, ?)",
metaTrackingRequired(2, 1)),
+ Arguments.of("INSERT INTO t VALUES (?, ?, ?)",
metaTrackingRequired(2, 1)),
Arguments.of("INSERT INTO t (c1, c2, c3) VALUES (?, ?,
TIMESTAMP WITH LOCAL TIME ZONE '1970-01-01 00:00:00')", null)
);
}
@@ -176,9 +208,7 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
node.initSchema("CREATE TABLE t (c1 INT, c2 INT, c3 INT, PRIMARY KEY
(c3, c2)) COLOCATE BY (c3)");
QueryPlan plan = node.prepare(query);
- PartitionAwarenessMetadata metadata =
plan.partitionAwarenessMetadata();
-
- expectMetadata(expected, metadata);
+ expectMetadata(plan, expected);
}
private static Stream<Arguments> shortKeyMetadata() {
@@ -191,12 +221,12 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
Arguments.of("SELECT * FROM t WHERE c3=? and c2=1", meta(0)),
Arguments.of("SELECT * FROM t WHERE c1=1 and c2=? and c3=?",
meta(1)),
- Arguments.of("SELECT * FROM t WHERE c3=3", null),
+ Arguments.of("SELECT * FROM t WHERE c3=3", meta(new int[]{-1},
new int[]{3})),
Arguments.of("SELECT * FROM t WHERE c2=? and c3=3", meta(new
int[]{-1}, new int[]{3})),
Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=3",
meta(new int[]{-1}, new int[]{3})),
// KV PUT
- Arguments.of("INSERT INTO t VALUES (?, ?, ?)",
metaTrackingRequired(2)),
+ Arguments.of("INSERT INTO t VALUES (?, ?, ?)",
metaTrackingRequired(2)),
Arguments.of("INSERT INTO t (c1, c2, c3) VALUES (?, ?, ?)",
metaTrackingRequired(2)),
Arguments.of("INSERT INTO t (c3, c1, c2) VALUES (?, ?, ?)",
metaTrackingRequired(0)),
@@ -208,9 +238,35 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
Arguments.of("DELETE FROM t WHERE c3=? and c2=?",
metaTrackingRequired(0)),
Arguments.of("DELETE FROM t WHERE c2=? and c3=?",
metaTrackingRequired(1)),
Arguments.of("DELETE FROM t WHERE c3=? and c2=1",
metaTrackingRequired(0)),
-
- Arguments.of("DELETE FROM t WHERE c3=3", null),
- Arguments.of("DELETE FROM t WHERE c2=? and c3=3",
metaTrackingRequired(new int[]{-1}, new int[]{3}))
+ Arguments.of("DELETE FROM t WHERE c2=? and c3=3",
+ meta(new int[]{-1}, new int[]{3},
DirectTxMode.SUPPORTED_TRACKING_REQUIRED)),
+
+ // SELECT
+ Arguments.of("SELECT * FROM t WHERE c3=3 AND c1 IN (SELECT *
FROM SYSTEM_RANGE(1, 100))",
+ meta(new int[]{-1}, new int[]{3})
+ ),
+
+ // UPDATE
+ Arguments.of("UPDATE t SET c1=? WHERE c3=? and c2=?",
+ meta(new int[]{1}, new int[0],
DirectTxMode.NOT_SUPPORTED)
+ ),
+ Arguments.of("UPDATE t SET c1=? WHERE c3=1 and c2=?",
+ meta(new int[]{-1}, new int[]{1},
DirectTxMode.NOT_SUPPORTED)
+ ),
+ Arguments.of("UPDATE t SET c1=? WHERE c3=1 and c2 IN (SELECT *
FROM SYSTEM_RANGE(1, 100))",
+ meta(new int[]{-1}, new int[]{1},
DirectTxMode.NOT_SUPPORTED)
+ ),
+
+ // INSERT
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26203 No
partition pruning metadata for INSERT INTO ... SELECT
+ // Arguments.of("INSERT INTO t SELECT 1 as c1, 2 as c2, 3 as
c3 FROM SYSTEM_RANGE(1, 100)",
+ // meta(new int[]{-1}, new int[]{3},
DirectTxMode.NOT_SUPPORTED)
+ // ),
+
+ // DELETE
+ Arguments.of("DELETE FROM t WHERE c3=3", meta(new int[]{-1},
new int[]{3}, DirectTxMode.NOT_SUPPORTED)),
+ Arguments.of("DELETE FROM t WHERE c3=3 and c2 IN (SELECT *
FROM SYSTEM_RANGE(1, 100))",
+ meta(new int[]{-1}, new int[]{3},
DirectTxMode.NOT_SUPPORTED))
);
}
@@ -220,9 +276,7 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
node.initSchema("CREATE TABLE t (c1 INT, c2 INT, c3 INT, c4 INT,
PRIMARY KEY(c1, c2, c3)) COLOCATE BY (c3, c1, c2)");
QueryPlan plan = node.prepare(query);
- PartitionAwarenessMetadata metadata =
plan.partitionAwarenessMetadata();
-
- expectMetadata(expected, metadata);
+ expectMetadata(plan, expected);
}
private static Stream<Arguments> compoundKeyMetadata() {
@@ -252,7 +306,7 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
Arguments.of("INSERT INTO t VALUES (1, ?, ?, ?)",
metaTrackingRequired(new int[]{1, -1, 0}, new int[]{1})),
Arguments.of("INSERT INTO t (c3, c2, c4, c1) VALUES (?, ?, ?,
?)", metaTrackingRequired(0, 3, 1)),
Arguments.of("INSERT INTO t (c3, c2, c4, c1) VALUES (?, ?, 1,
?)", metaTrackingRequired(0, 2, 1)),
- Arguments.of("INSERT INTO t VALUES (1, 2, 3, 4)", null),
+ Arguments.of("INSERT INTO t VALUES (1, 2, 3, 4)",
metaTrackingRequired(new int[]{-1, -2, -3}, new int[]{3, 1, 2})),
// KV DELETE
Arguments.of("DELETE FROM t WHERE c1=? and c2=? and c3=?",
metaTrackingRequired(2, 0, 1)),
@@ -262,7 +316,34 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
Arguments.of("DELETE FROM t WHERE c1=1 and c2=? and c3=?",
metaTrackingRequired(new int[]{1, -1, 0}, new int[]{1})),
Arguments.of("DELETE FROM t WHERE c1=? and c2=2 and c3=?",
metaTrackingRequired(new int[]{1, 0, -1}, new int[]{2})),
Arguments.of("DELETE FROM t WHERE c1=? and c2=? and c3=3",
metaTrackingRequired(new int[]{-1, 0, 1}, new int[]{3})),
- Arguments.of("DELETE FROM t WHERE c1=1 and c2=2 and c3=3",
metaTrackingRequired(new int[]{-1, -2, -3}, new int[]{3, 1, 2}))
+
+ // SELECT
+ Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=?",
+ meta(new int[]{2, 0, 1}, new int[]{},
DirectTxMode.SUPPORTED)
+ ),
+ Arguments.of("SELECT * FROM t WHERE c1=1 and c2=? and c3=?",
+ meta(new int[]{1, -1, 0}, new int[]{1},
DirectTxMode.SUPPORTED)
+ ),
+ Arguments.of("SELECT * FROM t WHERE c1=1 and c2=2 and c3=?",
+ meta(new int[]{0, -1, -2}, new int[]{1, 2},
DirectTxMode.SUPPORTED)
+ ),
+ Arguments.of("SELECT * FROM t WHERE c1=1 and c2=2 and c3=3",
+ meta(new int[]{-1, -2, -3}, new int[]{3, 1, 2},
DirectTxMode.SUPPORTED)
+ ),
+ // Multiple partitions - skip
+ Arguments.of("SELECT * FROM t WHERE (c1=? and c2=? and c3=?)
OR (c1=1 and c2=2 and c3=3)", null),
+ // Not keys specified - no partition pruning metadata
+ Arguments.of("SELECT * FROM t WHERE c2=? and c3=?", null),
+
+ // INSERT
+ // TODO https://issues.apache.org/jira/browse/IGNITE-26203 No
partition pruning metadata for INSERT INTO ... SELECT
+ // Arguments.of("INSERT INTO t SELECT * FROM t WHERE c1=1 and
c2=2 and c3=3", null)
+
+ // UPDATE
+ Arguments.of("UPDATE t SET c4=? WHERE c1=? and c2=? and c3=?",
+ meta(new int[]{3, 1, 2}, new int[]{},
DirectTxMode.NOT_SUPPORTED)
+ ),
+ Arguments.of("UPDATE t SET c4=? WHERE c2=? and c3=3", null)
);
}
@@ -290,6 +371,19 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
return meta(dynamicParams, new int[0],
DirectTxMode.SUPPORTED_TRACKING_REQUIRED);
}
+ private void expectMetadata(QueryPlan plan, PartitionAwarenessMetadata
expected) {
+ PartitionAwarenessMetadata metadata =
plan.partitionAwarenessMetadata();
+
+ if (plan instanceof ExplainablePlan) {
+ ExplainablePlan explainablePlan = (ExplainablePlan) plan;
+ log.info("Plan:\n{}", explainablePlan.explain());
+ } else {
+ log.info("Plan:{}", plan.getClass().getName());
+ }
+
+ expectMetadata(expected, metadata);
+ }
+
private static void expectMetadata(PartitionAwarenessMetadata expected,
@Nullable PartitionAwarenessMetadata actual) {
if (expected == null) {
assertNull(actual, "Metadata should not be present");