You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ko...@apache.org on 2025/05/16 14:43:33 UTC
(ignite-3) branch main updated: IGNITE-25352 Sql. Support NULL ORDERING for indexes (#5834)
This is an automated email from the ASF dual-hosted git repository.
korlov 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 c4a8b3e4ce1 IGNITE-25352 Sql. Support NULL ORDERING for indexes (#5834)
c4a8b3e4ce1 is described below
commit c4a8b3e4ce1a94630b4276ddde1439ac6d6ffe81
Author: korlov42 <ko...@apache.org>
AuthorDate: Fri May 16 17:43:27 2025 +0300
IGNITE-25352 Sql. Support NULL ORDERING for indexes (#5834)
---
.../internal/sql/engine/ItSecondaryIndexTest.java | 63 ++++++++++++++++++++--
.../src/main/codegen/includes/parserImpls.ftl | 12 +++++
.../prepare/ddl/DdlSqlToCommandConverter.java | 17 +++++-
.../sql/engine/sql/AbstractParserTest.java | 4 +-
.../internal/sql/engine/sql/SqlDdlParserTest.java | 48 +++++++++++++++--
.../index/StorageSortedIndexDescriptor.java | 23 +++++++-
.../ignite/internal/storage/util/StorageUtils.java | 4 +-
.../storage/engine/AbstractStorageEngineTest.java | 4 +-
.../index/AbstractSortedIndexStorageTest.java | 3 +-
.../storage/rocksdb/ColumnFamilyUtils.java | 14 +++--
.../storage/rocksdb/ColumnFamilyUtilsTest.java | 18 ++++---
.../instance/SharedRocksDbInstanceTest.java | 22 ++++----
.../internal/table/distributed/IndexBaseTest.java | 4 +-
.../table/distributed/SortedIndexLockerTest.java | 2 +-
.../table/distributed/StorageCleanupTest.java | 4 +-
.../distributed/StorageUpdateHandlerTest.java | 4 +-
.../PartitionReplicaListenerIndexLockingTest.java | 2 +-
...itionReplicaListenerSortedIndexLockingTest.java | 2 +-
.../replication/PartitionReplicaListenerTest.java | 2 +-
.../ZonePartitionReplicaListenerTest.java | 2 +-
20 files changed, 204 insertions(+), 50 deletions(-)
diff --git a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
index b321b7f342a..0c1d9c2692b 100644
--- a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
+++ b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
@@ -23,8 +23,10 @@ import static org.apache.ignite.internal.sql.engine.util.QueryChecker.containsIn
import static org.apache.ignite.internal.sql.engine.util.QueryChecker.containsSubPlan;
import static org.apache.ignite.internal.sql.engine.util.QueryChecker.containsTableScan;
import static org.apache.ignite.internal.sql.engine.util.QueryChecker.containsUnion;
+import static org.apache.ignite.internal.sql.engine.util.QueryChecker.matches;
import static org.apache.ignite.internal.sql.engine.util.QueryChecker.matchesOnce;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.not;
import java.time.LocalDate;
@@ -66,6 +68,8 @@ public class ItSecondaryIndexTest extends BaseSqlIntegrationTest {
.app("CREATE TABLE assignments(developer_id INT, project_id INT, primary key(developer_id, project_id));").nl()
.app("CREATE TABLE t1 (id INT PRIMARY KEY, val INT);").nl()
.app("CREATE INDEX t1_idx on t1(val DESC);").nl()
+ .app("CREATE INDEX t1_val_asc_nulls_last_idx on t1(val ASC NULLS LAST);").nl()
+ .app("CREATE INDEX t1_val_asc_nulls_first_idx on t1(val ASC NULLS FIRST);").nl()
.toString();
sqlScript(query);
@@ -791,7 +795,11 @@ public class ItSecondaryIndexTest extends BaseSqlIntegrationTest {
public void testIndexedNullableFieldGreaterThanFilter() {
assertQuery("SELECT * FROM T1 WHERE val > 4")
.disableRules("LogicalTableScanConverterRule")
- .matches(containsIndexScan("PUBLIC", "T1", "T1_IDX"))
+ .matches(anyOf(
+ containsIndexScan("PUBLIC", "T1", "T1_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_LAST_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_FIRST_IDX")
+ ))
.returns(5, 5)
.returns(6, 6)
.check();
@@ -860,7 +868,11 @@ public class ItSecondaryIndexTest extends BaseSqlIntegrationTest {
public void testIndexedNullableFieldLessThanFilter() {
assertQuery("SELECT * FROM T1 WHERE val <= 5")
.disableRules("LogicalTableScanConverterRule")
- .matches(containsIndexScan("PUBLIC", "T1", "T1_IDX"))
+ .matches(anyOf(
+ containsIndexScan("PUBLIC", "T1", "T1_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_LAST_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_FIRST_IDX")
+ ))
.returns(3, 3)
.returns(4, 4)
.returns(5, 5)
@@ -915,7 +927,11 @@ public class ItSecondaryIndexTest extends BaseSqlIntegrationTest {
@Test
public void testNullCondition1() {
assertQuery("SELECT * FROM T1 WHERE val is null")
- .matches(containsIndexScan("PUBLIC", "T1", "T1_IDX"))
+ .matches(anyOf(
+ containsIndexScan("PUBLIC", "T1", "T1_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_LAST_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_FIRST_IDX")
+ ))
.matches(not(containsUnion()))
.returns(1, null)
.returns(2, null)
@@ -927,7 +943,11 @@ public class ItSecondaryIndexTest extends BaseSqlIntegrationTest {
public void testNullCondition2() {
assertQuery("SELECT * FROM T1 WHERE (val <= 5) or (val is null)")
.disableRules("LogicalTableScanConverterRule")
- .matches(containsIndexScan("PUBLIC", "T1", "T1_IDX"))
+ .matches(anyOf(
+ containsIndexScan("PUBLIC", "T1", "T1_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_LAST_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_FIRST_IDX")
+ ))
.matches(not(containsUnion()))
.returns(1, null)
.returns(2, null)
@@ -942,7 +962,11 @@ public class ItSecondaryIndexTest extends BaseSqlIntegrationTest {
public void testNullCondition3() {
assertQuery("SELECT * FROM T1 WHERE (val >= 5) or (val is null)")
.disableRules("LogicalTableScanConverterRule")
- .matches(containsIndexScan("PUBLIC", "T1", "T1_IDX"))
+ .matches(anyOf(
+ containsIndexScan("PUBLIC", "T1", "T1_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_LAST_IDX"),
+ containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_FIRST_IDX")
+ ))
.matches(not(containsUnion()))
.returns(1, null)
.returns(2, null)
@@ -1172,6 +1196,35 @@ public class ItSecondaryIndexTest extends BaseSqlIntegrationTest {
.check();
}
+ @Test
+ void nullsOrderingTest() {
+ assertQuery("SELECT val FROM t1 ORDER BY val ASC NULLS FIRST")
+ .matches(containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_FIRST_IDX"))
+ .matches(not(matches("Sort")))
+ .ordered()
+ .returns(null)
+ .returns(null)
+ .returns(null)
+ .returns(3)
+ .returns(4)
+ .returns(5)
+ .returns(6)
+ .check();
+
+ assertQuery("SELECT val FROM t1 ORDER BY val ASC NULLS LAST")
+ .matches(containsIndexScan("PUBLIC", "T1", "T1_VAL_ASC_NULLS_LAST_IDX"))
+ .matches(not(matches("Sort")))
+ .ordered()
+ .returns(3)
+ .returns(4)
+ .returns(5)
+ .returns(6)
+ .returns(null)
+ .returns(null)
+ .returns(null)
+ .check();
+ }
+
@ParameterizedTest
@CsvSource(value = {
// type, literal
diff --git a/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl b/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
index b89bb20ecb1..533f15f6261 100644
--- a/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
+++ b/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
@@ -197,6 +197,18 @@ SqlNode ColumnNameWithSortDirection() :
col = SqlStdOperatorTable.DESC.createCall(getPos(), col);
}
)?
+
+ (
+ LOOKAHEAD(2)
+ <NULLS> <FIRST> {
+ col = SqlStdOperatorTable.NULLS_FIRST.createCall(getPos(), col);
+ }
+ |
+ <NULLS> <LAST> {
+ col = SqlStdOperatorTable.NULLS_LAST.createCall(getPos(), col);
+ }
+ )?
+
{
return col;
}
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
index eb8de7660c4..430c1ee1d6d 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
@@ -657,6 +657,17 @@ public class DdlSqlToCommandConverter {
) {
for (SqlNode col : columnList.getList()) {
boolean asc = true;
+ Boolean nullsFirst = null;
+
+ if (col.getKind() == SqlKind.NULLS_FIRST) {
+ col = ((SqlCall) col).getOperandList().get(0);
+
+ nullsFirst = true;
+ } else if (col.getKind() == SqlKind.NULLS_LAST) {
+ col = ((SqlCall) col).getOperandList().get(0);
+
+ nullsFirst = false;
+ }
if (col.getKind() == SqlKind.DESCENDING) {
col = ((SqlCall) col).getOperandList().get(0);
@@ -664,10 +675,14 @@ public class DdlSqlToCommandConverter {
asc = false;
}
+ if (nullsFirst == null) {
+ nullsFirst = !asc;
+ }
+
String columnName = ((SqlIdentifier) col).getSimple();
columns.add(columnName);
if (supportCollation) {
- collations.add(CatalogColumnCollation.get(asc, !asc));
+ collations.add(CatalogColumnCollation.get(asc, nullsFirst));
}
}
}
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/AbstractParserTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/AbstractParserTest.java
index 670fd626101..4f58879d726 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/AbstractParserTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/AbstractParserTest.java
@@ -53,12 +53,12 @@ public abstract class AbstractParserTest {
* @param pred Addition check that would be applied to the object.
* @return {@code true} in case the object if instance of the given class and matches the predicat.
*/
- static <T> Matcher<T> ofTypeMatching(String desc, Class<T> cls, Predicate<T> pred) {
+ static <WiderT, SpecificT extends WiderT> Matcher<WiderT> ofTypeMatching(String desc, Class<SpecificT> cls, Predicate<SpecificT> pred) {
return new CustomMatcher<>(desc) {
/** {@inheritDoc} */
@Override
public boolean matches(Object item) {
- return item != null && cls.isAssignableFrom(item.getClass()) && pred.test((T) item);
+ return item != null && cls.isAssignableFrom(item.getClass()) && pred.test((SpecificT) item);
}
};
}
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
index 378020473e7..7ab5fc15f83 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
@@ -46,10 +46,10 @@ import org.apache.calcite.sql.SqlNumericLiteral;
import org.apache.calcite.sql.SqlUnknownLiteral;
import org.apache.calcite.sql.ddl.SqlColumnDeclaration;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.ignite.internal.util.CollectionUtils;
import org.apache.ignite.lang.ErrorGroups.Sql;
import org.hamcrest.CustomMatcher;
import org.hamcrest.Matcher;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
@@ -58,7 +58,6 @@ import org.junit.jupiter.params.provider.ValueSource;
/**
* Test suite to verify parsing of the DDL command.
*/
-@SuppressWarnings("ThrowableNotThrown")
public class SqlDdlParserTest extends AbstractParserTest {
/**
* Very simple case where only table name and a few columns are presented.
@@ -479,6 +478,50 @@ public class SqlDdlParserTest extends AbstractParserTest {
);
}
+ @Test
+ public void createTableWithSortedPkAndParticularNullOrdering() {
+ String query = "create table my_table(id1 int, id2 int, val varchar, "
+ + "primary key using sorted (id1 ASC NULLS FIRST, id2 DESC NULLS LAST))";
+ SqlNode node = parse(query);
+
+ assertThat(node, instanceOf(IgniteSqlCreateTable.class));
+ IgniteSqlCreateTable createTable = (IgniteSqlCreateTable) node;
+
+ assertThat(createTable.name().names, is(List.of("MY_TABLE")));
+ assertThat(createTable.ifNotExists, is(false));
+
+ SqlNode lastItem = CollectionUtils.last(createTable.columnList());
+
+ assertThat(lastItem, instanceOf((IgniteSqlPrimaryKeyConstraint.class)));
+
+ IgniteSqlPrimaryKeyConstraint pkConstraint = (IgniteSqlPrimaryKeyConstraint) lastItem;
+
+ assertThat(
+ pkConstraint.getColumnList().get(0),
+ ofTypeMatching("\"ID1\" NULLS FIRST", SqlBasicCall.class, bc -> bc.isA(Set.of(SqlKind.NULLS_FIRST))
+ && bc.getOperandList().get(0) instanceof SqlIdentifier
+ && ((SqlIdentifier) bc.getOperandList().get(0)).isSimple()
+ && ((SqlIdentifier) bc.getOperandList().get(0)).getSimple().equals("ID1"))
+ );
+
+ assertThat(
+ pkConstraint.getColumnList().get(1),
+ ofTypeMatching("\"ID2\" DESC NULLS LAST", SqlBasicCall.class, bc -> bc.isA(Set.of(SqlKind.NULLS_LAST))
+ && bc.getOperandList().get(0) instanceof SqlBasicCall
+ && (bc.getOperandList().get(0)).isA(Set.of(SqlKind.DESCENDING))
+ && ((SqlBasicCall) bc.getOperandList().get(0)).getOperandList().get(0) instanceof SqlIdentifier
+ && ((SqlIdentifier) ((SqlBasicCall) bc.getOperandList().get(0)).getOperandList().get(0)).isSimple()
+ && ((SqlIdentifier) ((SqlBasicCall) bc.getOperandList().get(0)).getOperandList().get(0)).getSimple().equals("ID2"))
+ );
+
+ expectUnparsed(node, "CREATE TABLE \"MY_TABLE\" "
+ + "(\"ID1\" INTEGER, "
+ + "\"ID2\" INTEGER, "
+ + "\"VAL\" VARCHAR, "
+ + "PRIMARY KEY USING SORTED (\"ID1\" NULLS FIRST, \"ID2\" DESC NULLS LAST))"
+ );
+ }
+
/**
* Parsing of CREATE TABLE with primary key index type HASH.
*/
@@ -730,7 +773,6 @@ public class SqlDdlParserTest extends AbstractParserTest {
expectUnparsed(node, "CREATE INDEX \"MY_INDEX\" ON \"MY_SCHEMA\".\"MY_TABLE\" (\"COL\")");
}
- @Disabled("https://issues.apache.org/jira/browse/IGNITE-21672")
@Test
public void createIndexExplicitNullDirection() {
var query = "create index my_index on my_table (col1 nulls first, col2 nulls last, col3 desc nulls first)";
diff --git a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/StorageSortedIndexDescriptor.java b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/StorageSortedIndexDescriptor.java
index cca8568adfc..7ccfb723b2e 100644
--- a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/StorageSortedIndexDescriptor.java
+++ b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/index/StorageSortedIndexDescriptor.java
@@ -50,6 +50,8 @@ public class StorageSortedIndexDescriptor implements StorageIndexDescriptor {
private final boolean asc;
+ private final boolean nullsFirst;
+
/**
* Creates a Column Descriptor.
*
@@ -57,12 +59,20 @@ public class StorageSortedIndexDescriptor implements StorageIndexDescriptor {
* @param type Type of the column.
* @param nullable Flag indicating that the column may contain {@code null}s.
* @param asc Sort order of the column.
+ * @param nullsFirst Flag denotes whether to put NULL values first or last in the sorted stream.
*/
- public StorageSortedIndexColumnDescriptor(String name, NativeType type, boolean nullable, boolean asc) {
+ public StorageSortedIndexColumnDescriptor(
+ String name,
+ NativeType type,
+ boolean nullable,
+ boolean asc,
+ boolean nullsFirst
+ ) {
this.name = name;
this.type = type;
this.nullable = nullable;
this.asc = asc;
+ this.nullsFirst = nullsFirst;
}
@Override
@@ -89,6 +99,13 @@ public class StorageSortedIndexDescriptor implements StorageIndexDescriptor {
return asc;
}
+ /**
+ * Returns {@code true} if nulls in this column are put first, returns {@code false} otherwise.
+ */
+ public boolean nullsFirst() {
+ return nullsFirst;
+ }
+
@Override
public String toString() {
return S.toString(this);
@@ -179,7 +196,9 @@ public class StorageSortedIndexDescriptor implements StorageIndexDescriptor {
CatalogColumnCollation collation = columnDescriptor.collation();
- return new StorageSortedIndexColumnDescriptor(columnName, getNativeType(column), column.nullable(), collation.asc());
+ return new StorageSortedIndexColumnDescriptor(
+ columnName, getNativeType(column), column.nullable(), collation.asc(), collation.nullsFirst()
+ );
})
.collect(toList());
}
diff --git a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/util/StorageUtils.java b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/util/StorageUtils.java
index e9fdc1fa301..88905cec352 100644
--- a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/util/StorageUtils.java
+++ b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/util/StorageUtils.java
@@ -286,7 +286,7 @@ public class StorageUtils {
List<NativeType> columnTypes = new ArrayList<>(columns.size());
for (StorageSortedIndexColumnDescriptor col : columns) {
- columnCollation.add(CatalogColumnCollation.get(col.asc(), !col.asc()));
+ columnCollation.add(CatalogColumnCollation.get(col.asc(), col.nullsFirst()));
columnTypes.add(col.type());
}
@@ -301,7 +301,7 @@ public class StorageUtils {
List<NativeType> columnTypes = new ArrayList<>(columns.size());
for (StorageSortedIndexColumnDescriptor col : columns) {
- columnCollation.add(CatalogColumnCollation.get(col.asc(), !col.asc()));
+ columnCollation.add(CatalogColumnCollation.get(col.asc(), col.nullsFirst()));
columnTypes.add(col.type());
}
diff --git a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/engine/AbstractStorageEngineTest.java b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/engine/AbstractStorageEngineTest.java
index ed7f6894972..95472e7d82b 100644
--- a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/engine/AbstractStorageEngineTest.java
+++ b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/engine/AbstractStorageEngineTest.java
@@ -164,7 +164,9 @@ public abstract class AbstractStorageEngineTest extends BaseMvStoragesTest {
int numTables = 2;
- var sortedIndexColumnDescriptor = new StorageSortedIndexColumnDescriptor("foo", NativeTypes.INT64, true, true);
+ var sortedIndexColumnDescriptor = new StorageSortedIndexColumnDescriptor(
+ "foo", NativeTypes.INT64, true, true, false
+ );
var hashIndexColumnDescriptor = new StorageHashIndexColumnDescriptor("foo", NativeTypes.INT64, true);
diff --git a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractSortedIndexStorageTest.java b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractSortedIndexStorageTest.java
index 4104d1d0601..b803bc53cf6 100644
--- a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractSortedIndexStorageTest.java
+++ b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractSortedIndexStorageTest.java
@@ -22,6 +22,7 @@ import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toUnmodifiableList;
import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.ASC_NULLS_FIRST;
import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.ASC_NULLS_LAST;
+import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.DESC_NULLS_FIRST;
import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.DESC_NULLS_LAST;
import static org.apache.ignite.internal.catalog.descriptors.CatalogIndexStatus.AVAILABLE;
import static org.apache.ignite.internal.storage.index.SortedIndexStorage.GREATER;
@@ -109,7 +110,7 @@ public abstract class AbstractSortedIndexStorageTest extends AbstractIndexStorag
.map(ColumnParams::name)
.map(columnName -> new CatalogIndexColumnDescriptor(
columnName,
- random.nextBoolean() ? ASC_NULLS_FIRST : DESC_NULLS_LAST
+ random.nextBoolean() ? ASC_NULLS_LAST : DESC_NULLS_FIRST
))
.toArray(CatalogIndexColumnDescriptor[]::new)
);
diff --git a/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/ColumnFamilyUtils.java b/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/ColumnFamilyUtils.java
index 5d8716bc951..140ebbe0ada 100644
--- a/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/ColumnFamilyUtils.java
+++ b/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/ColumnFamilyUtils.java
@@ -67,10 +67,13 @@ public class ColumnFamilyUtils {
);
/** Nullability flag mask for {@link #sortedIndexCfName(List)}. */
- private static final int NULLABILITY_FLAG = 1;
+ private static final int NULLABILITY_FLAG = 0b1;
/** Order flag mask for {@link #sortedIndexCfName(List)}. */
- private static final int ASC_ORDER_FLAG = 2;
+ private static final int ASC_ORDER_FLAG = 0b10;
+
+ /** Flag denoting whether to put NULLs first or last for {@link #sortedIndexCfName(List)}. */
+ private static final int NULLS_FIRST_FLAG = 0b100;
/** Utility enum to describe a type of the column family - meta or partition. */
public enum ColumnFamilyType {
@@ -137,6 +140,10 @@ public class ColumnFamilyUtils {
flags |= ASC_ORDER_FLAG;
}
+ if (column.nullsFirst()) {
+ flags |= NULLS_FIRST_FLAG;
+ }
+
buf.put((byte) flags);
}
@@ -230,8 +237,9 @@ public class ColumnFamilyUtils {
boolean nullable = (nativeTypeFlags & NULLABILITY_FLAG) != 0;
boolean asc = (nativeTypeFlags & ASC_ORDER_FLAG) != 0;
+ boolean nullsFirst = (nativeTypeFlags & NULLS_FIRST_FLAG) != 0;
- columns.add(new StorageSortedIndexColumnDescriptor("<unknown>", nativeType, nullable, asc));
+ columns.add(new StorageSortedIndexColumnDescriptor("<unknown>", nativeType, nullable, asc, nullsFirst));
}
return new RocksDbBinaryTupleComparator(columns);
diff --git a/modules/storage-rocksdb/src/test/java/org/apache/ignite/internal/storage/rocksdb/ColumnFamilyUtilsTest.java b/modules/storage-rocksdb/src/test/java/org/apache/ignite/internal/storage/rocksdb/ColumnFamilyUtilsTest.java
index 5ac3e7ab39c..b34686e303a 100644
--- a/modules/storage-rocksdb/src/test/java/org/apache/ignite/internal/storage/rocksdb/ColumnFamilyUtilsTest.java
+++ b/modules/storage-rocksdb/src/test/java/org/apache/ignite/internal/storage/rocksdb/ColumnFamilyUtilsTest.java
@@ -17,8 +17,10 @@
package org.apache.ignite.internal.storage.rocksdb;
+import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.ASC_NULLS_FIRST;
import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.ASC_NULLS_LAST;
import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.DESC_NULLS_FIRST;
+import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.DESC_NULLS_LAST;
import static org.apache.ignite.internal.storage.rocksdb.ColumnFamilyUtils.comparatorFromCfName;
import static org.apache.ignite.internal.storage.rocksdb.ColumnFamilyUtils.sortedIndexCfName;
import static org.apache.ignite.internal.testframework.IgniteTestUtils.getFieldValue;
@@ -48,7 +50,7 @@ public class ColumnFamilyUtilsTest {
@ParameterizedTest
@VariableSource("ALL_TYPES")
void testSortedIndexCfNameSingleType(NativeType nativeType) {
- var descriptor = new StorageSortedIndexColumnDescriptor("<unused>", nativeType, false, false);
+ var descriptor = new StorageSortedIndexColumnDescriptor("<unused>", nativeType, false, false, false);
assertArrayEquals(name(nativeType.spec().ordinal(), 0), sortedIndexCfName(List.of(descriptor)));
}
@@ -56,21 +58,21 @@ public class ColumnFamilyUtilsTest {
@Test
void testSortedIndexCfNameFlags() {
List<StorageSortedIndexColumnDescriptor> descriptors = List.of(
- new StorageSortedIndexColumnDescriptor("<unused>", NativeTypes.INT64, false, false),
- new StorageSortedIndexColumnDescriptor("<unused>", NativeTypes.INT32, true, false),
- new StorageSortedIndexColumnDescriptor("<unused>", NativeTypes.INT16, false, true),
- new StorageSortedIndexColumnDescriptor("<unused>", NativeTypes.INT8, true, true)
+ new StorageSortedIndexColumnDescriptor("<unused>", NativeTypes.INT64, false, false, false),
+ new StorageSortedIndexColumnDescriptor("<unused>", NativeTypes.INT32, true, false, true),
+ new StorageSortedIndexColumnDescriptor("<unused>", NativeTypes.INT16, false, true, false),
+ new StorageSortedIndexColumnDescriptor("<unused>", NativeTypes.INT8, true, true, true)
);
- assertArrayEquals(name(3, 0, 2, 1, 1, 2, 0, 3), sortedIndexCfName(descriptors));
+ assertArrayEquals(name(3, 0, 2, 5, 1, 2, 0, 7), sortedIndexCfName(descriptors));
}
@Test
void testComparatorFromCfName() {
- RocksDbBinaryTupleComparator comparator = comparatorFromCfName(name(3, 0, 2, 1, 1, 2, 0, 3));
+ RocksDbBinaryTupleComparator comparator = comparatorFromCfName(name(3, 0, 2, 5, 1, 2, 0, 7));
List<NativeType> expectedTypes = List.of(NativeTypes.INT64, NativeTypes.INT32, NativeTypes.INT16, NativeTypes.INT8);
- List<CatalogColumnCollation> expectedCollations = List.of(DESC_NULLS_FIRST, DESC_NULLS_FIRST, ASC_NULLS_LAST, ASC_NULLS_LAST);
+ List<CatalogColumnCollation> expectedCollations = List.of(DESC_NULLS_LAST, DESC_NULLS_FIRST, ASC_NULLS_LAST, ASC_NULLS_FIRST);
// I am sorry, this is for a single test only.
List<NativeType> columnTypes = getFieldValue(comparator, "comparator", "columnTypes");
diff --git a/modules/storage-rocksdb/src/test/java/org/apache/ignite/internal/storage/rocksdb/instance/SharedRocksDbInstanceTest.java b/modules/storage-rocksdb/src/test/java/org/apache/ignite/internal/storage/rocksdb/instance/SharedRocksDbInstanceTest.java
index de59836c551..bb96a12c67a 100644
--- a/modules/storage-rocksdb/src/test/java/org/apache/ignite/internal/storage/rocksdb/instance/SharedRocksDbInstanceTest.java
+++ b/modules/storage-rocksdb/src/test/java/org/apache/ignite/internal/storage/rocksdb/instance/SharedRocksDbInstanceTest.java
@@ -122,19 +122,19 @@ class SharedRocksDbInstanceTest extends IgniteAbstractTest {
@Test
void testSortedIndexCfCaching() {
byte[] fooName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true, false)
));
byte[] barName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("b", NativeTypes.UUID, true, true)
+ new StorageSortedIndexColumnDescriptor("b", NativeTypes.UUID, true, true, false)
));
byte[] bazName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("c", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("c", NativeTypes.INT64, true, true, false)
));
byte[] quuxName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("d", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("d", NativeTypes.INT64, true, true, false)
));
ColumnFamily foo = rocksDb.getOrCreateSortedIndexCf(fooName, 1, 0);
@@ -173,19 +173,19 @@ class SharedRocksDbInstanceTest extends IgniteAbstractTest {
@Test
void testSortedIndexRecovery() throws Exception {
byte[] fooName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true, false)
));
byte[] barName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("b", NativeTypes.UUID, true, true)
+ new StorageSortedIndexColumnDescriptor("b", NativeTypes.UUID, true, true, false)
));
byte[] bazName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("c", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("c", NativeTypes.INT64, true, true, false)
));
byte[] quuxName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("d", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("d", NativeTypes.INT64, true, true, false)
));
ColumnFamily foo = rocksDb.getOrCreateSortedIndexCf(fooName, 1, 0);
@@ -270,7 +270,7 @@ class SharedRocksDbInstanceTest extends IgniteAbstractTest {
@RepeatedTest(10)
void testConcurrentSortedIndexReadAndCreate() {
byte[] fooName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true, false)
));
rocksDb.getOrCreateSortedIndexCf(fooName, 0, 0);
@@ -311,7 +311,7 @@ class SharedRocksDbInstanceTest extends IgniteAbstractTest {
int indexId = 0;
byte[] fooName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true, false)
));
ColumnFamily cf = rocksDb.getOrCreateSortedIndexCf(fooName, indexId, tableId);
@@ -326,7 +326,7 @@ class SharedRocksDbInstanceTest extends IgniteAbstractTest {
int tableId = 0;
byte[] fooName = sortedIndexCfName(List.of(
- new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true)
+ new StorageSortedIndexColumnDescriptor("a", NativeTypes.INT64, true, true, false)
));
rocksDb.getOrCreateSortedIndexCf(fooName, 0, tableId);
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/IndexBaseTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/IndexBaseTest.java
index 63a58386df3..a39fd783996 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/IndexBaseTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/IndexBaseTest.java
@@ -127,8 +127,8 @@ public abstract class IndexBaseTest extends BaseMvStoragesTest {
new StorageSortedIndexDescriptor(
sortedIndexId,
List.of(
- new StorageSortedIndexColumnDescriptor("INTVAL", NativeTypes.INT32, false, true),
- new StorageSortedIndexColumnDescriptor("STRVAL", NativeTypes.STRING, false, true)
+ new StorageSortedIndexColumnDescriptor("INTVAL", NativeTypes.INT32, false, true, false),
+ new StorageSortedIndexColumnDescriptor("STRVAL", NativeTypes.STRING, false, true, false)
),
true
)
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/SortedIndexLockerTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/SortedIndexLockerTest.java
index d702a6c2590..882c1d62f52 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/SortedIndexLockerTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/SortedIndexLockerTest.java
@@ -65,7 +65,7 @@ class SortedIndexLockerTest extends BaseIgniteAbstractTest {
PARTITION_ID,
new StorageSortedIndexDescriptor(
1,
- List.of(new StorageSortedIndexColumnDescriptor("c1", NativeTypes.INT32, false, true)),
+ List.of(new StorageSortedIndexColumnDescriptor("c1", NativeTypes.INT32, false, true, false)),
false
)
);
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/StorageCleanupTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/StorageCleanupTest.java
index 96010ec71eb..84081f647c3 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/StorageCleanupTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/StorageCleanupTest.java
@@ -124,8 +124,8 @@ public class StorageCleanupTest extends BaseMvStoragesTest {
new StorageSortedIndexDescriptor(
sortedIndexId,
List.of(
- new StorageSortedIndexColumnDescriptor("INTVAL", NativeTypes.INT32, false, true),
- new StorageSortedIndexColumnDescriptor("STRVAL", NativeTypes.STRING, false, true)
+ new StorageSortedIndexColumnDescriptor("INTVAL", NativeTypes.INT32, false, true, false),
+ new StorageSortedIndexColumnDescriptor("STRVAL", NativeTypes.STRING, false, true, false)
),
false
)
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/StorageUpdateHandlerTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/StorageUpdateHandlerTest.java
index cd504d6cd7c..dfec8030b12 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/StorageUpdateHandlerTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/StorageUpdateHandlerTest.java
@@ -115,8 +115,8 @@ public class StorageUpdateHandlerTest extends BaseMvStoragesTest {
new StorageSortedIndexDescriptor(
sortedIndexId,
List.of(
- new StorageSortedIndexColumnDescriptor("INTVAL", NativeTypes.INT32, false, true),
- new StorageSortedIndexColumnDescriptor("STRVAL", NativeTypes.STRING, false, true)
+ new StorageSortedIndexColumnDescriptor("INTVAL", NativeTypes.INT32, false, true, false),
+ new StorageSortedIndexColumnDescriptor("STRVAL", NativeTypes.STRING, false, true, false)
),
false
)
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerIndexLockingTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerIndexLockingTest.java
index d40478feea8..0fa58efacbb 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerIndexLockingTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerIndexLockingTest.java
@@ -209,7 +209,7 @@ public class PartitionReplicaListenerIndexLockingTest extends IgniteAbstractTest
new TestSortedIndexStorage(PART_ID,
new StorageSortedIndexDescriptor(
SORTED_INDEX_ID,
- List.of(new StorageSortedIndexColumnDescriptor("val", NativeTypes.INT32, false, true)),
+ List.of(new StorageSortedIndexColumnDescriptor("val", NativeTypes.INT32, false, true, false)),
false
)),
row2SortKeyConverter
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerSortedIndexLockingTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerSortedIndexLockingTest.java
index 2aa1d964876..b6622e7a7bc 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerSortedIndexLockingTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerSortedIndexLockingTest.java
@@ -175,7 +175,7 @@ public class PartitionReplicaListenerSortedIndexLockingTest extends IgniteAbstra
StorageSortedIndexDescriptor pkIndexDescriptor = new StorageSortedIndexDescriptor(
PK_INDEX_ID,
- List.of(new StorageSortedIndexColumnDescriptor("ID", NativeTypes.INT32, false, true)),
+ List.of(new StorageSortedIndexColumnDescriptor("ID", NativeTypes.INT32, false, true, false)),
false
);
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
index ee0d1ea0490..73d18af1f4c 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
@@ -566,7 +566,7 @@ public class PartitionReplicaListenerTest extends IgniteAbstractTest {
PART_ID,
new StorageSortedIndexDescriptor(
sortedIndexId,
- List.of(new StorageSortedIndexColumnDescriptor("intVal", NativeTypes.INT32, false, true)),
+ List.of(new StorageSortedIndexColumnDescriptor("intVal", NativeTypes.INT32, false, true, false)),
false
)
);
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/ZonePartitionReplicaListenerTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/ZonePartitionReplicaListenerTest.java
index cb4d6a8b568..80388d56bb5 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/ZonePartitionReplicaListenerTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/ZonePartitionReplicaListenerTest.java
@@ -456,7 +456,7 @@ public class ZonePartitionReplicaListenerTest extends IgniteAbstractTest {
PART_ID,
new StorageSortedIndexDescriptor(
sortedIndexId,
- List.of(new StorageSortedIndexColumnDescriptor("intVal", NativeTypes.INT32, false, true)),
+ List.of(new StorageSortedIndexColumnDescriptor("intVal", NativeTypes.INT32, false, true, false)),
false
)
);