This is an automated email from the ASF dual-hosted git repository.
zstan 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 2e5f3cc39f1 IGNITE-25903 Sql. Support literals in PA metadata builder
(#6406)
2e5f3cc39f1 is described below
commit 2e5f3cc39f1db1adc109ddefe49e4732abf6f26e
Author: Evgeniy Stanilovskiy <[email protected]>
AuthorDate: Thu Aug 14 11:13:28 2025 +0300
IGNITE-25903 Sql. Support literals in PA metadata builder (#6406)
---
.../internal/benchmark/BulkLoadBenchmark.java | 28 +++-
.../runner/app/client/ItThinClientSqlTest.java | 59 +++++++
.../ignite/internal/util/ColocationUtils.java | 33 ++++
.../PartitionAwarenessMetadataExtractor.java | 35 ++++-
.../ignite/internal/sql/engine/util/RexUtils.java | 32 ++++
.../planner/AbstractTpcQueryPlannerTest.java | 4 +-
.../PartitionAwarenessMetadataTest.java | 171 ++++++++++++++-------
7 files changed, 299 insertions(+), 63 deletions(-)
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/benchmark/BulkLoadBenchmark.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/benchmark/BulkLoadBenchmark.java
index b574ad71f1b..a254a58c596 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/benchmark/BulkLoadBenchmark.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/benchmark/BulkLoadBenchmark.java
@@ -21,6 +21,7 @@ import static java.util.stream.Collectors.joining;
import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
import static org.apache.ignite.internal.util.IgniteUtils.closeAll;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import org.apache.ignite.client.IgniteClient;
@@ -87,6 +88,27 @@ public class BulkLoadBenchmark extends
AbstractMultiNodeBenchmark {
state.upload(count, batchSize);
}
+ @Override
+ protected void createTablesOnStartup() {
+ createTable(TABLE_NAME,
+ List.of(
+ "ycsb_key int",
+ "field1 int",
+ "field2 varchar(100)",
+ "field3 varchar(100)",
+ "field4 varchar(100)",
+ "field5 varchar(100)",
+ "field6 varchar(100)",
+ "field7 varchar(100)",
+ "field8 varchar(100)",
+ "field9 varchar(100)",
+ "field10 varchar(100)"
+ ),
+ List.of("ycsb_key", "field1"),
+ List.of()
+ );
+ }
+
/**
* Benchmark's entry point.
*/
@@ -166,7 +188,7 @@ public class BulkLoadBenchmark extends
AbstractMultiNodeBenchmark {
*/
@Setup
public void setUp() {
- for (int i = 1; i < 11; i++) {
+ for (int i = 2; i < 11; i++) {
tuple.set("field" + i, FIELD_VAL);
}
@@ -193,7 +215,7 @@ public class BulkLoadBenchmark extends
AbstractMultiNodeBenchmark {
tx = client.transactions().begin();
}
- kvView.put(tx, Tuple.create().set("ycsb_key", i), tuple);
+ kvView.put(tx, Tuple.create().set("ycsb_key", i).set("field1",
1), tuple);
}
}
}
@@ -202,7 +224,7 @@ public class BulkLoadBenchmark extends
AbstractMultiNodeBenchmark {
String insertQueryTemplate = "insert into {}({}, {}) values(?, {})";
String fieldsQ = IntStream.range(1, 11).mapToObj(i -> "field" +
i).collect(joining(","));
- String valQ = IntStream.range(1, 11).mapToObj(i -> "'" + FIELD_VAL +
"'").collect(joining(","));
+ String valQ = "1, " + IntStream.range(2, 11).mapToObj(i -> "'" +
FIELD_VAL + "'").collect(joining(","));
return format(insertQueryTemplate, TABLE_NAME, "ycsb_key", fieldsQ,
valQ);
}
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSqlTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSqlTest.java
index 51967dccbf8..ca14d6b4a75 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSqlTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSqlTest.java
@@ -30,6 +30,7 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
+import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -48,6 +49,7 @@ import org.apache.ignite.sql.ResultSetMetadata;
import org.apache.ignite.sql.SqlException;
import org.apache.ignite.sql.SqlRow;
import org.apache.ignite.sql.Statement;
+import org.apache.ignite.sql.Statement.StatementBuilder;
import org.apache.ignite.sql.async.AsyncResultSet;
import org.apache.ignite.table.Table;
import org.apache.ignite.table.mapper.Mapper;
@@ -394,6 +396,63 @@ public class ItThinClientSqlTest extends
ItAbstractThinClientTest {
assertEquals(1, res.currentPage().iterator().next().intValue(0));
}
+ /** The purpose of this test is to check clients with different timeZone
settings.
+ * In case when literal is a part of primary key and has a type: TIMESTAMP
WITH LOCAL TIME ZONE - no
+ * partition awareness meta need to be calculated.
+ */
+ @Test
+ void testPartitionAwarenessNotExtractedForTsLiteral() {
+ IgniteClient client = client();
+ IgniteSql sql = client.sql();
+
+ sql.execute(null, "CREATE TABLE my_table (id int, ts TIMESTAMP WITH
LOCAL TIME ZONE, val INT, "
+ + "PRIMARY KEY(id, ts))");
+
+ int count = 100;
+
+ for (int i = 0; i < count; i++) {
+ sql.execute(null, "INSERT INTO my_table VALUES (?, TIMESTAMP WITH
LOCAL TIME ZONE '1970-01-01 00:00:00', ?)", i, i);
+ }
+
+ StatementBuilder builder = sql.statementBuilder();
+
+ String query = "SELECT * FROM my_table WHERE id = ? AND ts = TIMESTAMP
WITH LOCAL TIME ZONE '1970-01-01 00:00:00'";
+
+ builder.query(query);
+ builder.timeZoneId(ZoneId.of("Asia/Nicosia"));
+ Statement stmt1 = builder.build();
+
+ builder = sql.statementBuilder();
+ builder.query(query);
+ builder.timeZoneId(ZoneId.of("UTC"));
+ Statement stmt2 = builder.build();
+
+ Transaction tx = null;
+ for (int i = 0; i < count; i++) {
+ if (i % 5 == 0) {
+ if (tx != null) {
+ tx.commit();
+ }
+
+ tx = client.transactions().begin();
+ }
+
+ sql.execute(tx, stmt1, i);
+ }
+
+ for (int i = 0; i < count; i++) {
+ if (i % 5 == 0) {
+ if (tx != null) {
+ tx.commit();
+ }
+
+ tx = client.transactions().begin();
+ }
+
+ sql.execute(tx, stmt2, i);
+ }
+ }
+
@Test
void testExplicitTransactionKvCase() {
IgniteClient client = client();
diff --git
a/modules/schema/src/main/java/org/apache/ignite/internal/util/ColocationUtils.java
b/modules/schema/src/main/java/org/apache/ignite/internal/util/ColocationUtils.java
index 0ecf6343a5e..a0e8adf546c 100644
---
a/modules/schema/src/main/java/org/apache/ignite/internal/util/ColocationUtils.java
+++
b/modules/schema/src/main/java/org/apache/ignite/internal/util/ColocationUtils.java
@@ -117,4 +117,37 @@ public class ColocationUtils {
throw new IllegalStateException("Unexpected type: " +
type.spec());
}
}
+
+ /** Generates 32-bit hash from the given value with regard to provided
type. */
+ public static int hash(@Nullable Object v, NativeType type) {
+ if (v == null) {
+ return HashCalculator.hashValue(null, 0, 0);
+ }
+
+ switch (type.spec()) {
+ case BOOLEAN:
+ case INT8:
+ case INT16:
+ case INT32:
+ case INT64:
+ case FLOAT:
+ case DOUBLE:
+ case UUID:
+ case STRING:
+ case BYTE_ARRAY:
+ case DATE:
+ return HashCalculator.hashValue(v, 0, 0);
+ case DECIMAL:
+ assert type instanceof DecimalNativeType;
+ return HashCalculator.hashValue(v, ((DecimalNativeType)
type).scale(), 0);
+ case TIME:
+ case DATETIME:
+ case TIMESTAMP:
+ assert type instanceof TemporalNativeType;
+ return HashCalculator.hashValue(v, 0, ((TemporalNativeType)
type).precision());
+
+ default:
+ throw new IllegalStateException("Unexpected type: " +
type.spec());
+ }
+ }
}
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 9495ba411c0..d32a26aaf82 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,15 +17,26 @@
package org.apache.ignite.internal.sql.engine.prepare.partitionawareness;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
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.sql.type.SqlTypeName;
import org.apache.calcite.util.ImmutableIntList;
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.schema.IgniteTable;
+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;
+import org.apache.ignite.internal.sql.engine.util.RexUtils;
+import org.apache.ignite.internal.sql.engine.util.RexUtils.FaultyContext;
+import org.apache.ignite.internal.sql.engine.util.TypeUtils;
+import org.apache.ignite.internal.type.NativeType;
+import org.apache.ignite.internal.util.ColocationUtils;
import org.jetbrains.annotations.Nullable;
/**
@@ -97,7 +108,9 @@ public class PartitionAwarenessMetadataExtractor {
// colocation key index to dynamic param index
int[] indexes = new int[colocationKeys.size()];
- int[] hash = new int[0];
+ IntArrayList hashFields = new IntArrayList(colocationKeys.size() / 2);
+
+ int hashPos = -1;
for (int i = 0; i < colocationKeys.size(); i++) {
int colIdx = colocationKeys.get(i);
@@ -113,11 +126,31 @@ public class PartitionAwarenessMetadataExtractor {
if (expr instanceof RexDynamicParam) {
RexDynamicParam dynamicParam = (RexDynamicParam) expr;
indexes[i] = dynamicParam.getIndex();
+ } else if (expr instanceof RexLiteral) {
+ RexLiteral expr0 = (RexLiteral) expr;
+
+ // depends on supplied zoneId, it can`t be cached
+ if (expr0.getTypeName() ==
SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) {
+ return null;
+ }
+
+ indexes[i] = hashPos--;
+
+ Class<?> internalType = Primitives.wrap((Class<?>)
Commons.typeFactory().getJavaClass(expr0.getType()));
+ Object val = RexUtils.literalValue(FaultyContext.INSTANCE,
expr0, internalType);
+
+ NativeType nativeType =
IgniteTypeFactory.relDataTypeToNative(expr0.getType());
+
+ val = TypeUtils.fromInternal(val, nativeType.spec());
+
+ hashFields.add(ColocationUtils.hash(val, nativeType));
} else {
return null;
}
}
+ int[] hash = hashFields.toArray(new int[0]);
+
return new PartitionAwarenessMetadata(igniteTable.id(), indexes, hash,
directTxMode);
}
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
index 26c7f8202ee..9a3caecaaf4 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
@@ -58,7 +58,9 @@ import java.util.Set;
import java.util.TimeZone;
import org.apache.calcite.DataContext;
import org.apache.calcite.DataContext.Variable;
+import org.apache.calcite.adapter.java.JavaTypeFactory;
import org.apache.calcite.linq4j.Ord;
+import org.apache.calcite.linq4j.QueryProvider;
import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptUtil;
@@ -84,6 +86,7 @@ import org.apache.calcite.rex.RexUnknownAs;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.rex.RexVisitor;
import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -1191,6 +1194,35 @@ public class RexUtils {
return val;
}
+ /** Context which triggers assertion if unexpected method is called. */
+ public static class FaultyContext implements DataContext {
+ public static final FaultyContext INSTANCE = new FaultyContext();
+
+ /** {@inheritDoc} */
+ @Override
+ public SchemaPlus getRootSchema() {
+ throw new AssertionError("should not be called");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public JavaTypeFactory getTypeFactory() {
+ throw new AssertionError("should not be called");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public QueryProvider getQueryProvider() {
+ throw new AssertionError("should not be called");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public @Nullable Object get(String name) {
+ throw new AssertionError("Should not call: [" + name + "] from
current context.");
+ }
+ }
+
private static Object convertNumericLiteral(RelDataType dataType, Number
value, Class<?> type) {
Primitive primitive = Primitive.ofBoxOr(type);
assert primitive != null || type == BigDecimal.class : "Neither
primitive nor BigDecimal: " + type;
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractTpcQueryPlannerTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractTpcQueryPlannerTest.java
index 14db039d7e9..345c36d24c2 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractTpcQueryPlannerTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractTpcQueryPlannerTest.java
@@ -41,7 +41,7 @@ import java.util.regex.Pattern;
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.MultiStepPlan;
+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.TpcScaleFactor;
import org.apache.ignite.internal.sql.engine.util.TpcTable;
@@ -120,7 +120,7 @@ abstract class AbstractTpcQueryPlannerTest extends
AbstractPlannerTest {
int pos = 0;
for (QueryPlan plan : plans) {
- MultiStepPlan plan0 = (MultiStepPlan) plan;
+ ExplainablePlan plan0 = (ExplainablePlan) plan;
String actualPlan = plan0.explain();
if (planUpdater != null) {
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 304b192f1ce..6f7e60928b0 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
@@ -38,6 +38,8 @@ import
org.apache.ignite.internal.sql.engine.framework.TestNode;
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;
+import org.apache.ignite.internal.type.NativeTypes;
+import org.apache.ignite.internal.util.ColocationUtils;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
@@ -121,26 +123,50 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
private static Stream<Arguments> simpleKeyMetadata() {
return Stream.of(
// KV GET
- Arguments.of("SELECT * FROM t WHERE c1=?", dynamicParams(0)),
- Arguments.of("SELECT * FROM t WHERE c2=? and c1=?",
dynamicParams(1)),
- Arguments.of("SELECT * FROM t WHERE c1=1", null),
- Arguments.of("SELECT * FROM t WHERE c1=1+1", null),
+ Arguments.of("SELECT * FROM t WHERE c1=?", meta(0)),
+ Arguments.of("SELECT * FROM t WHERE c2=? and c1=?", meta(1)),
+ Arguments.of("SELECT * FROM t WHERE c1=" + Long.MAX_VALUE,
null),
+ Arguments.of("SELECT * FROM t WHERE c1=1", meta(new int[]{-1},
new int[]{1})),
+ Arguments.of("SELECT * FROM t WHERE c1=1+1", meta(new
int[]{-1}, new int[]{2})),
// the first condition goes into key lookup other into a
post-lookup filter.
- Arguments.of("SELECT * FROM t WHERE c1=? and c1=?",
dynamicParams(0)),
- Arguments.of("SELECT * FROM t WHERE c2=? and c1=? and c1=?",
dynamicParams(1)),
+ Arguments.of("SELECT * FROM t WHERE c1=? and c1=?", meta(0)),
+ Arguments.of("SELECT * FROM t WHERE c2=? and c1=? and c1=?",
meta(1)),
// KV PUT
- Arguments.of("INSERT INTO t VALUES(?, ?)",
dynamicParamsTrackingRequired(0)),
- Arguments.of("INSERT INTO t VALUES(1, ?)", null),
+ 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(c2, c1) VALUES(?, ?)",
dynamicParamsTrackingRequired(1)),
- Arguments.of("INSERT INTO t(c2, c1) VALUES(1, ?)",
dynamicParamsTrackingRequired(0)),
- Arguments.of("INSERT INTO t(c2, c1) VALUES(?, 1)", 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})),
// KV DELETE
- Arguments.of("DELETE FROM t WHERE c1=?",
dynamicParamsTrackingRequired(0)),
- Arguments.of("DELETE FROM t WHERE c1=1", null),
- Arguments.of("DELETE FROM t WHERE c1=1+1", null)
+ 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}))
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("tsKeyMetadata")
+ public void tsCompoundKey(String query, PartitionAwarenessMetadata
expected) {
+ 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);
+ }
+
+ private static Stream<Arguments> tsKeyMetadata() {
+ return Stream.of(
+ // KV GET
+ Arguments.of("SELECT * FROM t WHERE c3=? and c2=?", meta(0,
1)),
+ 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 (c1, c2, c3) VALUES (?, ?,
TIMESTAMP WITH LOCAL TIME ZONE '1970-01-01 00:00:00')", null)
);
}
@@ -158,33 +184,33 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
private static Stream<Arguments> shortKeyMetadata() {
return Stream.of(
// KV GET
- Arguments.of("SELECT * FROM t WHERE c3=? and c2=?",
dynamicParams(0)),
- Arguments.of("SELECT * FROM t WHERE c2=? and c3=?",
dynamicParams(1)),
- Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=?",
dynamicParams(2)),
- Arguments.of("SELECT * FROM t WHERE c3=? and c1=? and c2=?",
dynamicParams(0)),
- Arguments.of("SELECT * FROM t WHERE c3=? and c2=1",
dynamicParams(0)),
- Arguments.of("SELECT * FROM t WHERE c1=1 and c2=? and c3=?",
dynamicParams(1)),
+ Arguments.of("SELECT * FROM t WHERE c3=? and c2=?", meta(0)),
+ Arguments.of("SELECT * FROM t WHERE c2=? and c3=?", meta(1)),
+ Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=?",
meta(2)),
+ Arguments.of("SELECT * FROM t WHERE c3=? and c1=? and c2=?",
meta(0)),
+ 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 c2=? and c3=3", null),
- Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=3",
null),
+ 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 (?, ?, ?)",
dynamicParamsTrackingRequired(2)),
- Arguments.of("INSERT INTO t (c1, c2, c3) VALUES (?, ?, ?)",
dynamicParamsTrackingRequired(2)),
- Arguments.of("INSERT INTO t (c3, c1, c2) VALUES (?, ?, ?)",
dynamicParamsTrackingRequired(0)),
+ 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)),
- Arguments.of("INSERT INTO t (c1, c2, c3) VALUES (?, ?, 3)",
null),
- Arguments.of("INSERT INTO t (c1, c3, c2) VALUES (?, 3, ?)",
null),
- Arguments.of("INSERT INTO t (c3, c1, c2) VALUES (3, ?, ?)",
null),
+ Arguments.of("INSERT INTO t (c1, c2, c3) VALUES (?, ?, 3)",
metaTrackingRequired(new int[]{-1}, new int[]{3})),
+ Arguments.of("INSERT INTO t (c1, c3, c2) VALUES (?, 3, ?)",
metaTrackingRequired(new int[]{-1}, new int[]{3})),
+ Arguments.of("INSERT INTO t (c3, c1, c2) VALUES (3, ?, ?)",
metaTrackingRequired(new int[]{-1}, new int[]{3})),
// KV DELETE
- Arguments.of("SELECT * FROM t WHERE c3=? and c2=?",
dynamicParams(0)),
- Arguments.of("SELECT * FROM t WHERE c2=? and c3=?",
dynamicParams(1)),
- Arguments.of("SELECT * FROM t WHERE c3=? and c2=1",
dynamicParams(0)),
+ 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("SELECT * FROM t WHERE c3=3", null),
- Arguments.of("SELECT * FROM t WHERE c2=? and c3=3", null)
+ 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}))
);
}
@@ -202,41 +228,66 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
private static Stream<Arguments> compoundKeyMetadata() {
return Stream.of(
// KV GET
- Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=?",
dynamicParams(2, 0, 1)),
- Arguments.of("SELECT * FROM t WHERE c3=? and c1=? and c2=?",
dynamicParams(0, 1, 2)),
- Arguments.of("SELECT * FROM t WHERE c3=? and c2=? and c1=?",
dynamicParams(0, 2, 1)),
- Arguments.of("SELECT * FROM t WHERE c4=? and c1=? and c2=? and
1=? and c3=?", dynamicParams(4, 1, 2)),
+ Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=?",
meta(2, 0, 1)),
+ Arguments.of("SELECT * FROM t WHERE c3=? and c1=? and c2=?",
meta(0, 1, 2)),
+ Arguments.of("SELECT * FROM t WHERE c3=? and c2=? and c1=?",
meta(0, 2, 1)),
+
+ Arguments.of("SELECT * FROM t WHERE c3=1 and c1=? and c2=?",
meta(new int[]{-1, 0, 1}, new int[]{1})),
+ Arguments.of("SELECT * FROM t WHERE c3=? and c1=1 and c2=?",
meta(new int[]{0, -1, 1}, new int[]{1})),
+ Arguments.of("SELECT * FROM t WHERE c3=? and c1=? and c2=1",
meta(new int[]{0, 1, -1}, new int[]{1})),
+
+ Arguments.of("SELECT * FROM t WHERE c3=1 and c1=1 and c2=?",
meta(new int[]{-1, -2, 0}, new int[]{1, 1})),
+ Arguments.of("SELECT * FROM t WHERE c3=1 and c1=1 and c2=1",
meta(new int[]{-1, -2, -3}, new int[]{1, 1, 1})),
+
+ Arguments.of("SELECT * FROM t WHERE c4=? and c1=? and c2=? and
1=? and c3=?", meta(4, 1, 2)),
// duplicate condition goes to a post lookup filter.
- Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=? and
c2=?", dynamicParams(2, 0, 1)),
+ Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=? and
c2=?", meta(2, 0, 1)),
- Arguments.of("SELECT * FROM t WHERE c1=1 and c2=? and c3=?",
null),
- Arguments.of("SELECT * FROM t WHERE c1=? and c2=2 and c3=?",
null),
- Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=3",
null),
- Arguments.of("SELECT * FROM t WHERE c1=1 and c2=2 and c3=3",
null),
+ Arguments.of("SELECT * FROM t WHERE c1=1 and c2=? and c3=?",
meta(new int[]{1, -1, 0}, new int[]{1})),
+ Arguments.of("SELECT * FROM t WHERE c1=? and c2=2 and c3=?",
meta(new int[]{1, 0, -1}, new int[]{2})),
+ Arguments.of("SELECT * FROM t WHERE c1=? and c2=? and c3=3",
meta(new int[]{-1, 0, 1}, new int[]{3})),
+ 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})),
// KV PUT
- Arguments.of("INSERT INTO t VALUES (?, ?, ?, ?)",
dynamicParamsTrackingRequired(2, 0, 1)),
- Arguments.of("INSERT INTO t (c3, c2, c4, c1) VALUES (?, ?, ?,
?)", dynamicParamsTrackingRequired(0, 3, 1)),
- Arguments.of("INSERT INTO t (c3, c2, c4, c1) VALUES (?, ?, 1,
?)", dynamicParamsTrackingRequired(0, 2, 1)),
+ 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),
// KV DELETE
- Arguments.of("DELETE FROM t WHERE c1=? and c2=? and c3=?",
dynamicParamsTrackingRequired(2, 0, 1)),
- Arguments.of("DELETE FROM t WHERE c3=? and c1=? and c2=?",
dynamicParamsTrackingRequired(0, 1, 2)),
- Arguments.of("DELETE FROM t WHERE c3=? and c2=? and c1=?",
dynamicParamsTrackingRequired(0, 2, 1)),
-
- Arguments.of("DELETE FROM t WHERE c1=1 and c2=? and c3=?",
null),
- Arguments.of("DELETE FROM t WHERE c1=? and c2=2 and c3=?",
null),
- Arguments.of("DELETE FROM t WHERE c1=? and c2=? and c3=3",
null),
- Arguments.of("DELETE FROM t WHERE c1=1 and c2=2 and c3=3",
null)
+ Arguments.of("DELETE FROM t WHERE c1=? and c2=? and c3=?",
metaTrackingRequired(2, 0, 1)),
+ Arguments.of("DELETE FROM t WHERE c3=? and c1=? and c2=?",
metaTrackingRequired(0, 1, 2)),
+ Arguments.of("DELETE FROM t WHERE c3=? and c2=? and c1=?",
metaTrackingRequired(0, 2, 1)),
+
+ 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}))
);
}
- private static PartitionAwarenessMetadata dynamicParams(int...
dynamicParams) {
- return new PartitionAwarenessMetadata(1, dynamicParams, new int[0],
DirectTxMode.SUPPORTED);
+ private static PartitionAwarenessMetadata meta(int... dynamicParams) {
+ return meta(dynamicParams, new int[0], DirectTxMode.SUPPORTED);
+ }
+
+ private static PartitionAwarenessMetadata meta(int[] dynamicParams, int[]
toHash) {
+ return meta(dynamicParams, toHash, DirectTxMode.SUPPORTED);
+ }
+
+ private static PartitionAwarenessMetadata meta(int[] dynamicParams, int[]
toHash, DirectTxMode mode) {
+ int[] hashes = new int[toHash.length];
+ for (int i = 0; i < toHash.length; ++i) {
+ hashes[i] = ColocationUtils.hash(toHash[i], NativeTypes.INT32);
+ }
+ return new PartitionAwarenessMetadata(1, dynamicParams, hashes, mode);
+ }
+
+ private static PartitionAwarenessMetadata metaTrackingRequired(int[]
dynamicParams, int[] toHash) {
+ return meta(dynamicParams, toHash,
DirectTxMode.SUPPORTED_TRACKING_REQUIRED);
}
- private static PartitionAwarenessMetadata
dynamicParamsTrackingRequired(int... dynamicParams) {
- return new PartitionAwarenessMetadata(1, dynamicParams, new int[0],
DirectTxMode.SUPPORTED_TRACKING_REQUIRED);
+ private static PartitionAwarenessMetadata metaTrackingRequired(int...
dynamicParams) {
+ return meta(dynamicParams, new int[0],
DirectTxMode.SUPPORTED_TRACKING_REQUIRED);
}
private static void expectMetadata(PartitionAwarenessMetadata expected,
@Nullable PartitionAwarenessMetadata actual) {
@@ -258,6 +309,12 @@ public class PartitionAwarenessMetadataTest extends
BaseIgniteAbstractTest {
Arrays.stream(actual.indexes()).boxed().collect(Collectors.toList()),
"indexes"
);
+
+ assertEquals(
+
Arrays.stream(expected.hash()).boxed().collect(Collectors.toList()),
+
Arrays.stream(actual.hash()).boxed().collect(Collectors.toList()),
+ "hashes"
+ );
}
}
}