blob: c9809e80a3549d8f5d71232a382443c93d0cdc6c [file] [log] [blame]
/*
* 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.schema;
import static org.apache.ignite.internal.catalog.CatalogService.DEFAULT_STORAGE_PROFILE;
import static org.apache.ignite.internal.sql.engine.util.TypeUtils.columnType2NativeType;
import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
import static org.apache.ignite.internal.testframework.IgniteTestUtils.await;
import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelFieldCollation.Direction;
import org.apache.calcite.rel.RelFieldCollation.NullDirection;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.Table;
import org.apache.ignite.internal.catalog.CatalogCommand;
import org.apache.ignite.internal.catalog.CatalogManager;
import org.apache.ignite.internal.catalog.CatalogTestUtils;
import org.apache.ignite.internal.catalog.commands.CatalogUtils;
import org.apache.ignite.internal.catalog.commands.ColumnParams;
import org.apache.ignite.internal.catalog.commands.CreateHashIndexCommand;
import org.apache.ignite.internal.catalog.commands.CreateSortedIndexCommand;
import org.apache.ignite.internal.catalog.commands.CreateSystemViewCommand;
import org.apache.ignite.internal.catalog.commands.CreateTableCommand;
import org.apache.ignite.internal.catalog.commands.CreateTableCommandBuilder;
import org.apache.ignite.internal.catalog.commands.CreateZoneCommand;
import org.apache.ignite.internal.catalog.commands.DefaultValue;
import org.apache.ignite.internal.catalog.commands.MakeIndexAvailableCommand;
import org.apache.ignite.internal.catalog.commands.StartBuildingIndexCommand;
import org.apache.ignite.internal.catalog.commands.StorageProfileParams;
import org.apache.ignite.internal.catalog.commands.TableHashPrimaryKey;
import org.apache.ignite.internal.catalog.commands.TablePrimaryKey;
import org.apache.ignite.internal.catalog.commands.TableSortedPrimaryKey;
import org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation;
import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
import org.apache.ignite.internal.catalog.descriptors.CatalogSchemaDescriptor;
import org.apache.ignite.internal.catalog.descriptors.CatalogSystemViewDescriptor;
import org.apache.ignite.internal.catalog.descriptors.CatalogSystemViewDescriptor.SystemViewType;
import org.apache.ignite.internal.catalog.descriptors.CatalogTableColumnDescriptor;
import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
import org.apache.ignite.internal.catalog.descriptors.CatalogZoneDescriptor;
import org.apache.ignite.internal.hlc.HybridClockImpl;
import org.apache.ignite.internal.lang.IgniteInternalException;
import org.apache.ignite.internal.schema.DefaultValueGenerator;
import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Type;
import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
import org.apache.ignite.internal.sql.engine.util.cache.CaffeineCacheFactory;
import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
import org.apache.ignite.sql.ColumnType;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.junit.jupiter.MockitoExtension;
/** Tests for {@link SqlSchemaManagerImpl}. */
@ExtendWith(MockitoExtension.class)
public class SqlSchemaManagerImplTest extends BaseIgniteAbstractTest {
private static final String PUBLIC_SCHEMA_NAME = "PUBLIC";
private static final String SYSTEM_SCHEMA_NAME = "SYSTEM";
private CatalogManager catalogManager;
private SqlSchemaManagerImpl sqlSchemaManager;
@BeforeEach
void init() {
catalogManager = CatalogTestUtils.createCatalogManagerWithTestUpdateLog("test", new HybridClockImpl());
sqlSchemaManager = new SqlSchemaManagerImpl(catalogManager, CaffeineCacheFactory.INSTANCE, 200);
assertThat(catalogManager.startAsync(), willCompleteSuccessfully());
}
@AfterEach
void cleanup() {
assertThat(catalogManager.stopAsync(), willCompleteSuccessfully());
}
@Test
void exceptionWillBeThrownIfTableNotFoundById() {
await(catalogManager.execute(List.of(
createDummyTable("T1")
)));
int versionAfter = catalogManager.latestCatalogVersion();
// just to fill up cache
sqlSchemaManager.schema(versionAfter);
int nonExistingTableId = Integer.MAX_VALUE;
assertThat(catalogManager.table(nonExistingTableId, versionAfter), nullValue());
assertThrowsWithCause(
() -> sqlSchemaManager.table(versionAfter, nonExistingTableId),
IgniteInternalException.class,
"Table with given id not found"
);
}
@Test
void testMultipleSchemas() {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
createDummyTable("T1"),
createDummySystemView("V1", SystemViewType.NODE)
)));
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
assertNotNull(rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME));
assertNotNull(rootSchema.getSubSchema(SYSTEM_SCHEMA_NAME));
}
/** Basic schema with several tables. */
@Test
public void testBasicSchema() {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
createDummyTable("T1"),
createDummyTable("T2")
)));
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteSchema schema = unwrapSchema(schemaPlus);
assertThat(schema.version(), equalTo(versionAfter));
CatalogSchemaDescriptor schemaDescriptor = catalogManager.schema(PUBLIC_SCHEMA_NAME, versionAfter);
assertThat(schemaDescriptor, notNullValue());
assertThat(schema.getName(), equalTo(schemaDescriptor.name()));
for (CatalogTableDescriptor tableDescriptor : schemaDescriptor.tables()) {
int zoneId = tableDescriptor.zoneId();
CatalogZoneDescriptor zoneDescriptor = catalogManager.zone(zoneId, versionAfter);
assertNotNull(zoneDescriptor, "Zone does not exist: " + zoneId);
Table table = schema.getTable(tableDescriptor.name());
assertThat(table, notNullValue());
IgniteTable igniteTable = assertInstanceOf(IgniteTable.class, table);
assertEquals(zoneDescriptor.partitions(), igniteTable.partitions(),
"Number of partitions is not correct: " + tableDescriptor.name());
assertEquals(CatalogUtils.DEFAULT_PARTITION_COUNT, igniteTable.partitions(),
"Number of partitions is not correct: " + tableDescriptor.name());
}
}
/** Create a table with a zone. */
@Test
public void testTableWithZone() {
int partitions = 10;
await(catalogManager.execute(CreateZoneCommand.builder()
.partitions(partitions)
.zoneName("ABC")
.storageProfilesParams(List.of(StorageProfileParams.builder().storageProfile(DEFAULT_STORAGE_PROFILE).build()))
.build())
);
await(catalogManager.execute(CreateTableCommand.builder()
.schemaName(PUBLIC_SCHEMA_NAME)
.tableName("T")
.columns(List.of(
ColumnParams.builder().name("ID").type(ColumnType.INT32).nullable(false).build(),
ColumnParams.builder().name("VAL").type(ColumnType.INT32).build()
))
.primaryKey(primaryKey("ID"))
.zone("ABC")
.build()));
int version = catalogManager.latestCatalogVersion();
SchemaPlus rootSchema = sqlSchemaManager.schema(version);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteSchema schema = unwrapSchema(schemaPlus);
Table table = schema.getTable("T");
assertNotNull(table);
IgniteTable igniteTable = assertInstanceOf(IgniteTable.class, table);
assertEquals(partitions, igniteTable.partitions());
}
/**
* Table column types.
*/
@ParameterizedTest
@MethodSource("columnTypes")
public void testTableColumns(ColumnType columnType, int precision, int scale) {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
CreateTableCommand.builder()
.schemaName(PUBLIC_SCHEMA_NAME)
.tableName("TEST")
.columns(List.of(
ColumnParams.builder().name("ID").type(ColumnType.INT32).nullable(false).build(),
column("VAL_NULLABLE", columnType, precision, scale, true),
column("VAL_NOT_NULLABLE", columnType, precision, scale, false)
))
.primaryKey(primaryKey("ID"))
.zone("Default")
.build()
)));
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteTable table = getTable(unwrapSchema(schemaPlus), "TEST");
CatalogTableDescriptor tableDescriptor = catalogManager.table(table.id(), versionAfter);
assertThat(tableDescriptor, notNullValue());
TableDescriptor descriptor = table.descriptor();
assertEquals(tableDescriptor.columns().size(), descriptor.columnsCount(), "column count");
for (int i = 0; i < descriptor.columnsCount(); i++) {
CatalogTableColumnDescriptor expectedColumnDescriptor = tableDescriptor.columns().get(i);
ColumnDescriptor actualColumnDescriptor = descriptor.columnDescriptor(i);
checkColumns(actualColumnDescriptor, i, expectedColumnDescriptor);
}
}
private static void checkColumns(
ColumnDescriptor actualColumnDescriptor,
int expectedIndex,
CatalogTableColumnDescriptor expectedColumnDescriptor
) {
assertThat(actualColumnDescriptor.logicalIndex(), equalTo(expectedIndex));
assertThat(actualColumnDescriptor.name(), equalTo(expectedColumnDescriptor.name()));
assertThat(actualColumnDescriptor.nullable(), equalTo(expectedColumnDescriptor.nullable()));
assertThat(
actualColumnDescriptor.physicalType(),
equalTo(columnType2NativeType(
expectedColumnDescriptor.type(),
expectedColumnDescriptor.precision(),
expectedColumnDescriptor.scale(),
expectedColumnDescriptor.length()
))
);
}
/**
* Column default value constraint.
*/
@Test
public void testTableDefaultValue() {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
CreateTableCommand.builder()
.schemaName(PUBLIC_SCHEMA_NAME)
.tableName("TEST")
.columns(List.of(
ColumnParams.builder().name("C1").type(ColumnType.INT32).nullable(false).build(),
ColumnParams.builder().name("C2").type(ColumnType.INT32)
.defaultValue(DefaultValue.constant(null)).build(),
ColumnParams.builder().name("C3").type(ColumnType.INT32)
.defaultValue(DefaultValue.constant(1)).build(),
ColumnParams.builder().name("C4").type(ColumnType.STRING).length(256)
.defaultValue(DefaultValue.functionCall(DefaultValueGenerator.GEN_RANDOM_UUID.name())).build()
))
.primaryKey(primaryKey("C1", "C4"))
.zone("Default")
.build()
)));
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteTable table = getTable(unwrapSchema(schemaPlus), "TEST");
ColumnDescriptor c1 = table.descriptor().columnDescriptor("C1");
assertNull(c1.defaultValue());
assertEquals(DefaultValueStrategy.DEFAULT_NULL, c1.defaultStrategy());
ColumnDescriptor c2 = table.descriptor().columnDescriptor("C2");
assertNull(c2.defaultValue());
assertEquals(DefaultValueStrategy.DEFAULT_NULL, c2.defaultStrategy());
ColumnDescriptor c3 = table.descriptor().columnDescriptor("C3");
assertEquals(1, c3.defaultValue());
assertEquals(DefaultValueStrategy.DEFAULT_CONSTANT, c3.defaultStrategy());
ColumnDescriptor c4 = table.descriptor().columnDescriptor("C4");
assertNotNull(c4.defaultValue());
assertEquals(DefaultValueStrategy.DEFAULT_COMPUTED, c4.defaultStrategy());
}
/**
* Table with primary key but w/o colocation key columns are legal.
*/
@ParameterizedTest
@MethodSource("primaryKeyTypesColumnsC1C3")
public void testTableWithPrimaryKey(TablePrimaryKey primaryKey) {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
CreateTableCommand.builder()
.schemaName(PUBLIC_SCHEMA_NAME)
.tableName("TEST")
.columns(List.of(
ColumnParams.builder().name("C1").type(ColumnType.INT32).nullable(false).build(),
ColumnParams.builder().name("C2").type(ColumnType.INT32)
.defaultValue(DefaultValue.constant(null)).build(),
ColumnParams.builder().name("C3").type(ColumnType.STRING).length(256)
.defaultValue(DefaultValue.functionCall(DefaultValueGenerator.GEN_RANDOM_UUID.name())).build(),
ColumnParams.builder().name("C4").type(ColumnType.INT8).nullable(true).build()
))
.primaryKey(primaryKey)
.zone("Default")
.build()
)));
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteTable table = getTable(unwrapSchema(schemaPlus), "TEST");
assertTrue(table.descriptor().columnDescriptor(0).key());
assertFalse(table.descriptor().columnDescriptor(1).key());
assertTrue(table.descriptor().columnDescriptor(2).key());
assertFalse(table.descriptor().columnDescriptor(3).key());
}
private static Stream<TablePrimaryKey> primaryKeyTypesColumnsC1C3() {
return Stream.of(
TableHashPrimaryKey.builder()
.columns(List.of("C1", "C3"))
.build(),
TableSortedPrimaryKey.builder()
.columns(List.of("C1", "C3"))
.collations(List.of(CatalogColumnCollation.ASC_NULLS_LAST, CatalogColumnCollation.DESC_NULLS_FIRST))
.build()
);
}
/**
* Table distribution.
*/
@Test
public void testTableDistribution() {
Function<CreateTableCommandBuilder, CreateTableCommandBuilder> tableBase = builder -> builder
.schemaName(PUBLIC_SCHEMA_NAME)
.columns(List.of(
ColumnParams.builder().name("C1").type(ColumnType.INT32).build(),
ColumnParams.builder().name("C2").type(ColumnType.INT32).build(),
ColumnParams.builder().name("C3").type(ColumnType.INT32).build(),
ColumnParams.builder().name("C4").type(ColumnType.INT32).build()
))
.primaryKey(primaryKey("C1", "C2", "C3", "C4"))
.zone("Default");
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
tableBase.apply(CreateTableCommand.builder())
.tableName("T1")
.colocationColumns(List.of("C2"))
.build(),
tableBase.apply(CreateTableCommand.builder())
.tableName("T2")
.colocationColumns(List.of("C4", "C2"))
.build(),
tableBase.apply(CreateTableCommand.builder())
.tableName("T3")
.colocationColumns(List.of("C3", "C2", "C1"))
.build()
)));
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
{
IgniteTable table = getTable(unwrapSchema(schemaPlus), "T1");
IgniteDistribution distribution = table.descriptor().distribution();
assertThat(distribution, equalTo(IgniteDistributions.affinity(List.of(1), table.id(), table.id())));
}
{
IgniteTable table = getTable(unwrapSchema(schemaPlus), "T2");
IgniteDistribution distribution = table.descriptor().distribution();
assertThat(distribution, equalTo(IgniteDistributions.affinity(List.of(3, 1), table.id(), table.id())));
}
{
IgniteTable table = getTable(unwrapSchema(schemaPlus), "T3");
IgniteDistribution distribution = table.descriptor().distribution();
assertThat(distribution, equalTo(IgniteDistributions.affinity(List.of(2, 1, 0), table.id(), table.id())));
}
}
@Test
public void testHashIndex() {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
createDummyTable("T1"),
createHashIndex("T1", "VAL1_IDX", "VAL1")
)));
{
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteIndex index = findIndex(unwrapSchema(schemaPlus), "T1", "VAL1_IDX");
assertNull(index, "Index should not be available");
}
makeIndexAvailable("VAL1_IDX");
{
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 2));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteIndex index = findIndex(unwrapSchema(schemaPlus), "T1", "VAL1_IDX");
assertNotNull(index);
assertThat(index.name(), equalTo("VAL1_IDX"));
assertThat(index.type(), equalTo(Type.HASH));
assertThat(index.collation(), equalTo(RelCollations.of(
new RelFieldCollation(1, Direction.CLUSTERED, NullDirection.UNSPECIFIED)
)));
}
}
@Test
public void testSortedIndex() {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
createDummyTable("T1"),
createSortedIndex("T1", "IDX1", List.of("VAL1", "VAL2"),
List.of(CatalogColumnCollation.ASC_NULLS_FIRST, CatalogColumnCollation.ASC_NULLS_LAST)),
createSortedIndex("T1", "IDX2", List.of("VAL1", "VAL2"),
List.of(CatalogColumnCollation.DESC_NULLS_FIRST, CatalogColumnCollation.DESC_NULLS_LAST))
)));
{
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteIndex index1 = findIndex(unwrapSchema(schemaPlus), "T1", "IDX1");
assertNull(index1);
IgniteIndex index2 = findIndex(unwrapSchema(schemaPlus), "T1", "IDX2");
assertNull(index2);
}
makeIndexAvailable("IDX1");
{
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 2));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteIndex index = findIndex(unwrapSchema(schemaPlus), "T1", "IDX1");
assertNotNull(index);
assertThat(index.name(), equalTo("IDX1"));
assertThat(index.type(), equalTo(Type.SORTED));
assertThat(index.collation(), equalTo(RelCollations.of(
new RelFieldCollation(1, Direction.ASCENDING, NullDirection.FIRST),
new RelFieldCollation(2, Direction.ASCENDING, NullDirection.LAST)
)));
}
makeIndexAvailable("IDX2");
{
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 3));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(PUBLIC_SCHEMA_NAME);
assertNotNull(schemaPlus);
IgniteIndex index = findIndex(unwrapSchema(schemaPlus), "T1", "IDX2");
assertNotNull(index);
assertThat(index.name(), equalTo("IDX2"));
assertThat(index.type(), equalTo(Type.SORTED));
assertThat(index.collation(), equalTo(RelCollations.of(
new RelFieldCollation(1, Direction.DESCENDING, NullDirection.FIRST),
new RelFieldCollation(2, Direction.DESCENDING, NullDirection.LAST)
)));
}
}
private void makeIndexAvailable(String name) {
Map<String, CatalogIndexDescriptor> indices = catalogManager.indexes(catalogManager.latestCatalogVersion())
.stream().collect(Collectors.toMap(CatalogIndexDescriptor::name, Function.identity()));
CatalogIndexDescriptor indexDescriptor = indices.get(name);
assertNotNull(indexDescriptor, indices.toString());
CatalogCommand startBuilding = StartBuildingIndexCommand.builder().indexId(indexDescriptor.id()).build();
CatalogCommand makeAvailable = MakeIndexAvailableCommand.builder().indexId(indexDescriptor.id()).build();
await(catalogManager.execute(List.of(startBuilding, makeAvailable)));
}
@ParameterizedTest
@MethodSource("systemViewDistributions")
public void testBasicView(SystemViewType viewType, IgniteDistribution distribution) {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
createDummySystemView("V1", SystemViewType.NODE),
createDummySystemView("V2", SystemViewType.CLUSTER)
)));
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(SYSTEM_SCHEMA_NAME);
assertNotNull(schemaPlus);
{
IgniteSystemView systemView = getSystemView(unwrapSchema(schemaPlus), "V1");
assertThat(systemView.name(), equalTo("V1"));
assertThat(systemView.distribution(), equalTo(IgniteDistributions.identity(0)));
}
{
IgniteSystemView systemView = getSystemView(unwrapSchema(schemaPlus), "V2");
assertThat(systemView.name(), equalTo("V2"));
assertThat(systemView.distribution(), equalTo(IgniteDistributions.single()));
}
}
@ParameterizedTest
@MethodSource("systemViewColumnTypes")
public void testViewColumns(SystemViewType viewType, ColumnType columnType, int precision, int scale) {
int versionBefore = catalogManager.latestCatalogVersion();
await(catalogManager.execute(List.of(
CreateSystemViewCommand.builder()
.name("V1")
.columns(List.of(
ColumnParams.builder().name("ID").type(ColumnType.INT32).nullable(false).build(),
column("VAL_NULLABLE", columnType, precision, scale, true),
column("VAL_NOT_NULLABLE", columnType, precision, scale, false)
))
.type(SystemViewType.CLUSTER)
.build()
)));
int versionAfter = catalogManager.latestCatalogVersion();
assertThat(versionAfter, equalTo(versionBefore + 1));
SchemaPlus rootSchema = sqlSchemaManager.schema(versionAfter);
assertNotNull(rootSchema);
SchemaPlus schemaPlus = rootSchema.getSubSchema(SYSTEM_SCHEMA_NAME);
assertNotNull(schemaPlus);
CatalogSchemaDescriptor schemaDescriptor = catalogManager.schema(SYSTEM_SCHEMA_NAME, versionAfter);
assertNotNull(schemaDescriptor);
CatalogSystemViewDescriptor viewDescriptor = schemaDescriptor.systemView("V1");
assertNotNull(viewDescriptor);
IgniteSystemView systemView = getSystemView(unwrapSchema(schemaPlus), "V1");
TableDescriptor descriptor = systemView.descriptor();
assertEquals(viewDescriptor.columns().size(), descriptor.columnsCount(), "column count");
for (int i = 0; i < descriptor.columnsCount(); i++) {
CatalogTableColumnDescriptor expectedColumnDescriptor = viewDescriptor.columns().get(i);
ColumnDescriptor actualColumnDescriptor = descriptor.columnDescriptor(i);
checkColumns(actualColumnDescriptor, i, expectedColumnDescriptor);
}
}
private static Stream<Arguments> systemViewColumnTypes() {
List<Arguments> allArgs = new ArrayList<>();
for (SystemViewType type : SystemViewType.values()) {
columnTypes().map(args -> {
Object[] vals = args.get();
Object[] newVals = new Object[vals.length + 1];
newVals[0] = type;
System.arraycopy(vals, 0, newVals, 1, vals.length);
return Arguments.of(newVals);
}).forEach(allArgs::add);
}
return allArgs.stream();
}
private static Stream<Arguments> systemViewDistributions() {
return Stream.of(
Arguments.of(SystemViewType.NODE, IgniteDistributions.identity(0)),
Arguments.of(SystemViewType.CLUSTER, IgniteDistributions.single())
);
}
private static IgniteSystemView getSystemView(IgniteSchema schema, String name) {
Table systemViewTable = schema.getTable(name);
assertNotNull(systemViewTable);
IgniteSystemView systemView = assertInstanceOf(IgniteSystemView.class, systemViewTable);
assertEquals(systemView.name(), name);
return systemView;
}
private static IgniteSchema unwrapSchema(SchemaPlus schemaPlus) {
IgniteSchema igniteSchema = schemaPlus.unwrap(IgniteSchema.class);
assertNotNull(igniteSchema);
return igniteSchema;
}
private static IgniteTable getTable(IgniteSchema schema, String name) {
IgniteTable table = (IgniteTable) schema.getTable(name);
assertNotNull(table);
return table;
}
private static @Nullable IgniteIndex findIndex(IgniteSchema schema, String tableName, String indexName) {
IgniteTable table = (IgniteTable) schema.getTable(tableName);
assertNotNull(table);
return table.indexes().get(indexName);
}
private static Stream<Arguments> columnTypes() {
return Stream.of(
Arguments.of(ColumnType.BOOLEAN, -1, -1),
Arguments.of(ColumnType.INT8, -1, -1),
Arguments.of(ColumnType.INT16, -1, -1),
Arguments.of(ColumnType.INT32, -1, -1),
Arguments.of(ColumnType.INT64, -1, -1),
Arguments.of(ColumnType.FLOAT, -1, -1),
Arguments.of(ColumnType.DOUBLE, -1, -1),
Arguments.of(ColumnType.DECIMAL, 4, 0),
Arguments.of(ColumnType.DECIMAL, 4, 2),
Arguments.of(ColumnType.NUMBER, 4, -1),
Arguments.of(ColumnType.STRING, 40, -1),
Arguments.of(ColumnType.BYTE_ARRAY, 40, -1),
Arguments.of(ColumnType.DATE, -1, -1),
Arguments.of(ColumnType.TIME, 2, -1),
Arguments.of(ColumnType.DATETIME, 2, -1),
Arguments.of(ColumnType.TIMESTAMP, 2, -1),
Arguments.of(ColumnType.UUID, -1, -1),
Arguments.of(ColumnType.BITMASK, 2, -1)
);
}
private static CatalogCommand createDummyTable(String name) {
return CreateTableCommand.builder()
.schemaName(PUBLIC_SCHEMA_NAME)
.tableName(name)
.columns(List.of(
ColumnParams.builder().name("ID").type(ColumnType.INT32).nullable(false).build(),
ColumnParams.builder().name("VAL1").type(ColumnType.INT32).nullable(false).build(),
ColumnParams.builder().name("VAL2").type(ColumnType.INT32).nullable(false).build()
))
.primaryKey(TableHashPrimaryKey.builder()
.columns(List.of("ID"))
.build())
.zone("Default")
.build();
}
private static CatalogCommand createDummySystemView(String name, SystemViewType type) {
return CreateSystemViewCommand.builder()
.name(name)
.columns(List.of(
ColumnParams.builder().name("NODE").type(ColumnType.STRING).length(256).build(),
ColumnParams.builder().name("C1").type(ColumnType.INT32).nullable(false).build(),
ColumnParams.builder().name("C2").type(ColumnType.INT32).nullable(false).build()
))
.type(type)
.build();
}
private static CatalogCommand createHashIndex(String tableName, String indexName, String... cols) {
return CreateHashIndexCommand.builder()
.schemaName(PUBLIC_SCHEMA_NAME)
.tableName(tableName)
.indexName(indexName)
.unique(false)
.columns(Arrays.asList(cols))
.build();
}
private static CatalogCommand createSortedIndex(String tableName, String indexName,
List<String> cols, List<CatalogColumnCollation> collations) {
return CreateSortedIndexCommand.builder()
.schemaName(PUBLIC_SCHEMA_NAME)
.tableName(tableName)
.indexName(indexName)
.unique(false)
.columns(cols)
.collations(collations)
.build();
}
private static ColumnParams column(String name, ColumnType columnType, int precision, int scale, boolean nullable) {
ColumnParams.Builder builder = ColumnParams.builder()
.name(name)
.type(columnType)
.nullable(nullable);
switch (columnType) {
case INT8:
case INT16:
case INT32:
case INT64:
case FLOAT:
case DOUBLE:
case DATE:
case UUID:
case BOOLEAN:
break;
case NUMBER:
case TIME:
case DATETIME:
case TIMESTAMP:
builder.precision(precision);
break;
case DECIMAL:
builder.precision(precision);
builder.scale(scale);
break;
case STRING:
case BYTE_ARRAY:
case BITMASK:
builder.length(precision);
break;
default:
throw new IllegalArgumentException("Unsupported native type: " + columnType);
}
return builder.build();
}
private static TablePrimaryKey primaryKey(String column, String... columns) {
List<String> pkColumns = new ArrayList<>();
pkColumns.add(column);
pkColumns.addAll(Arrays.asList(columns));
return TableHashPrimaryKey.builder()
.columns(pkColumns)
.build();
}
}