Skip to content

Commit 1dc3ddb

Browse files
authored
IGNITE-24022 Sql. Fix CreateSchemaCommand catalog command validation (#5084)
1 parent c6b1ffc commit 1dc3ddb

File tree

9 files changed

+243
-23
lines changed

9 files changed

+243
-23
lines changed

modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ private CompletableFuture<Void> initCatalog(Catalog emptyCatalog) {
280280
.build(),
281281
// Add schemas
282282
CreateSchemaCommand.builder().name(SqlCommon.DEFAULT_SCHEMA_NAME).build(),
283-
CreateSchemaCommand.builder().name(SYSTEM_SCHEMA_NAME).build()
283+
CreateSchemaCommand.systemSchemaBuilder().name(SYSTEM_SCHEMA_NAME).build()
284284
);
285285

286286
List<UpdateEntry> entries = new BulkUpdateProducer(initCommands).get(new UpdateContext(emptyCatalog));

modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateSchemaCommand.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.List;
2525
import org.apache.ignite.internal.catalog.Catalog;
2626
import org.apache.ignite.internal.catalog.CatalogCommand;
27+
import org.apache.ignite.internal.catalog.CatalogValidationException;
2728
import org.apache.ignite.internal.catalog.SchemaExistsException;
2829
import org.apache.ignite.internal.catalog.UpdateContext;
2930
import org.apache.ignite.internal.catalog.descriptors.CatalogIndexDescriptor;
@@ -43,9 +44,19 @@ public class CreateSchemaCommand implements CatalogCommand {
4344

4445
private final boolean ifNotExists;
4546

46-
private CreateSchemaCommand(String schemaName, boolean ifNotExists) {
47+
private CreateSchemaCommand(String schemaName, boolean ifNotExists, boolean systemSchemaCommand) {
4748
validateIdentifier(schemaName, "Name of the schema");
4849

50+
if (systemSchemaCommand) {
51+
if (!CatalogUtils.isSystemSchema(schemaName)) {
52+
throw new CatalogValidationException(format("Not a system schema, schema: '{}'", schemaName));
53+
}
54+
} else {
55+
if (CatalogUtils.isSystemSchema(schemaName)) {
56+
throw new CatalogValidationException("Reserved system schema with name '{}' can't be created.", schemaName);
57+
}
58+
}
59+
4960
this.schemaName = schemaName;
5061
this.ifNotExists = ifNotExists;
5162
}
@@ -112,7 +123,31 @@ public CreateSchemaCommandBuilder ifNotExists(boolean value) {
112123
/** {@inheritDoc} */
113124
@Override
114125
public CatalogCommand build() {
115-
return new CreateSchemaCommand(name, ifNotExists);
126+
return new CreateSchemaCommand(name, ifNotExists, false);
127+
}
128+
}
129+
130+
/** Returns builder to create a command to create a system schema. */
131+
public static SystemSchemaBuilder systemSchemaBuilder() {
132+
return new SystemSchemaBuilder();
133+
}
134+
135+
/** Implementation of {@link CreateSystemSchemaCommandBuilder}. */
136+
public static class SystemSchemaBuilder implements CreateSystemSchemaCommandBuilder {
137+
138+
private String name;
139+
140+
/** {@inheritDoc} */
141+
@Override
142+
public CreateSystemSchemaCommandBuilder name(String name) {
143+
this.name = name;
144+
return this;
145+
}
146+
147+
/** {@inheritDoc} */
148+
@Override
149+
public CatalogCommand build() {
150+
return new CreateSchemaCommand(name, false, true);
116151
}
117152
}
118153
}

modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateSchemaCommandBuilder.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,10 @@
1717

1818
package org.apache.ignite.internal.catalog.commands;
1919

20-
import org.apache.ignite.internal.catalog.CatalogCommand;
21-
2220
/**
2321
* Builder for a {@link CreateSchemaCommand}.
2422
*/
25-
public interface CreateSchemaCommandBuilder {
26-
27-
/** Sets schema name. Should not be null or blank. */
28-
CreateSchemaCommandBuilder name(String name);
29-
23+
public interface CreateSchemaCommandBuilder extends CreateSystemSchemaCommandBuilder {
3024
/** Sets a flag indicating whether {@code IF NOT EXISTS} option was specified. */
3125
CreateSchemaCommandBuilder ifNotExists(boolean value);
32-
33-
/** Creates new schema command. */
34-
CatalogCommand build();
3526
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.internal.catalog.commands;
19+
20+
import org.apache.ignite.internal.catalog.CatalogCommand;
21+
22+
/**
23+
* Builder for a {@link CreateSchemaCommand} with system schemas usage.
24+
*/
25+
public interface CreateSystemSchemaCommandBuilder {
26+
/** Sets schema name. Should not be null or blank. */
27+
CreateSystemSchemaCommandBuilder name(String name);
28+
29+
/** Creates new schema command. */
30+
CatalogCommand build();
31+
}

modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogSchemaValidationTest.java

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,22 @@
1717

1818
package org.apache.ignite.internal.catalog;
1919

20+
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.SYSTEM_SCHEMAS;
2021
import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
2122
import static org.apache.ignite.internal.testframework.matchers.CompletableFutureExceptionMatcher.willThrowFast;
2223
import static org.hamcrest.MatcherAssert.assertThat;
2324

25+
import java.util.Locale;
26+
import java.util.stream.Stream;
2427
import org.apache.ignite.internal.catalog.commands.CreateSchemaCommand;
28+
import org.apache.ignite.internal.catalog.commands.CreateSchemaCommandBuilder;
2529
import org.apache.ignite.internal.catalog.commands.DropSchemaCommand;
2630
import org.apache.ignite.internal.sql.SqlCommon;
2731
import org.apache.ignite.internal.testframework.IgniteTestUtils;
2832
import org.junit.jupiter.api.Test;
2933
import org.junit.jupiter.params.ParameterizedTest;
30-
import org.junit.jupiter.params.provider.ValueSource;
34+
import org.junit.jupiter.params.provider.Arguments;
35+
import org.junit.jupiter.params.provider.MethodSource;
3136

3237
/** Validation tests for schema related commands. */
3338
public class CatalogSchemaValidationTest extends BaseCatalogManagerTest {
@@ -78,12 +83,21 @@ public void testCreateSchemaWithNullOrEmptyNameIsRejected() {
7883
);
7984
}
8085

86+
@SuppressWarnings("ThrowableNotThrown")
87+
@ParameterizedTest
88+
@MethodSource("reservedSchemaNames")
89+
public void testCreateSystemSchemaIsRejected(String schemaName) {
90+
CreateSchemaCommandBuilder createCmd = CreateSchemaCommand.builder().name(schemaName);
91+
92+
IgniteTestUtils.assertThrows(
93+
CatalogValidationException.class,
94+
() -> manager.execute(createCmd.build()),
95+
format("Reserved system schema with name '{}' can't be created.", schemaName)
96+
);
97+
}
98+
8199
@ParameterizedTest
82-
@ValueSource(strings = {
83-
CatalogService.SYSTEM_SCHEMA_NAME,
84-
CatalogService.INFORMATION_SCHEMA,
85-
CatalogService.DEFINITION_SCHEMA
86-
})
100+
@MethodSource("reservedSchemaNames")
87101
public void testDropSystemSchemaIsForbidden(String schemaName) {
88102
CatalogCommand dropCmd = DropSchemaCommand.builder().name(schemaName).build();
89103

@@ -93,6 +107,23 @@ public void testDropSystemSchemaIsForbidden(String schemaName) {
93107
);
94108
}
95109

110+
private static Stream<Arguments> reservedSchemaNames() {
111+
return SYSTEM_SCHEMAS.stream().map(Arguments::of);
112+
}
113+
114+
@ParameterizedTest
115+
@MethodSource("reservedSchemaNames")
116+
public void testDropNotExistSchemas(String schemaName) {
117+
schemaName = schemaName.toLowerCase(Locale.ROOT);
118+
119+
CatalogCommand dropCmd = DropSchemaCommand.builder().name(schemaName).build();
120+
121+
assertThat(
122+
manager.execute(dropCmd),
123+
willThrowFast(CatalogValidationException.class, format("Schema with name '{}' not found", schemaName))
124+
);
125+
}
126+
96127
@Test
97128
@SuppressWarnings("ThrowableNotThrown")
98129
public void testDropSchemaWithNullOrEmptyNameIsRejected() {

modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateSchemaCommandValidationTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
/**
3030
* Tests to verify validation of {@link CreateSchemaCommand}.
3131
*/
32+
@SuppressWarnings({"ThrowableNotThrown"})
3233
public class CreateSchemaCommandValidationTest extends AbstractCommandValidationTest {
3334

3435
@ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
@@ -56,6 +57,8 @@ void commandFailsWhenSchemaAlreadyExists() {
5657
() -> builder.build().get(new UpdateContext(catalog)),
5758
"Schema with name 'TEST' already exists"
5859
);
60+
61+
builder.ifNotExists(true).build().get(new UpdateContext(catalog));
5962
}
6063

6164
private static Catalog catalogWithSchema(String schemaName) {
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.internal.catalog.commands;
19+
20+
import static org.apache.ignite.internal.catalog.CatalogService.INFORMATION_SCHEMA;
21+
import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
22+
import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrows;
23+
24+
import java.util.Locale;
25+
import org.apache.ignite.internal.catalog.Catalog;
26+
import org.apache.ignite.internal.catalog.CatalogValidationException;
27+
import org.apache.ignite.internal.catalog.UpdateContext;
28+
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.params.ParameterizedTest;
30+
import org.junit.jupiter.params.provider.MethodSource;
31+
32+
/**
33+
* Tests to verify validation of {@link CreateSchemaCommand} for system schemas.
34+
*/
35+
@SuppressWarnings({"ThrowableNotThrown"})
36+
public class CreateSystemSchemaValidationTest extends AbstractCommandValidationTest {
37+
38+
@ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
39+
@MethodSource("nullAndBlankStrings")
40+
void schemaNameMustNotBeNullOrBlank(String name) {
41+
CreateSystemSchemaCommandBuilder builder = CreateSchemaCommand.systemSchemaBuilder().name(name);
42+
43+
assertThrows(
44+
CatalogValidationException.class,
45+
builder::build,
46+
"Name of the schema can't be null or blank"
47+
);
48+
}
49+
50+
@Test
51+
void commandFailsWithNonSystemSchema() {
52+
String schemaName = INFORMATION_SCHEMA.toLowerCase(Locale.ROOT);
53+
54+
Catalog catalog = catalogWithSchema(INFORMATION_SCHEMA);
55+
56+
assertThrows(
57+
CatalogValidationException.class,
58+
() -> CreateSchemaCommand.systemSchemaBuilder().name(schemaName).build().get(new UpdateContext(catalog)),
59+
format("Not a system schema, schema: '{}'", schemaName)
60+
);
61+
}
62+
63+
@Test
64+
void commandFailsWhenSchemaAlreadyExists() {
65+
CreateSystemSchemaCommandBuilder builder = CreateSchemaCommand.systemSchemaBuilder().name(INFORMATION_SCHEMA);
66+
67+
Catalog catalog = catalogWithSchema(INFORMATION_SCHEMA);
68+
69+
assertThrows(
70+
CatalogValidationException.class,
71+
() -> builder.build().get(new UpdateContext(catalog)),
72+
format("Schema with name '{}' already exists", INFORMATION_SCHEMA)
73+
);
74+
}
75+
76+
private static Catalog catalogWithSchema(String schemaName) {
77+
return catalog(CreateSchemaCommand.systemSchemaBuilder().name(schemaName).build());
78+
}
79+
}

modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,6 @@ public void literalAsColumDefault() {
323323
}
324324

325325
@Test
326-
@SuppressWarnings("ThrowableNotThrown")
327326
public void doNotAllowFunctionsInNonPkColumns() {
328327
// SQL Standard 2016 feature E141-07 - Basic integrity constraints. Column defaults
329328
assertThrowsSqlException(
@@ -339,7 +338,7 @@ public void testItIsNotPossibleToCreateTablesInSystemSchema(String schema) {
339338
if (DEFINITION_SCHEMA.equals(schema) || INFORMATION_SCHEMA.equals(schema)) {
340339
IgniteImpl igniteImpl = unwrapIgniteImpl(CLUSTER.aliveNode());
341340

342-
IgniteTestUtils.await(igniteImpl.catalogManager().execute(CreateSchemaCommand.builder().name(schema).build()));
341+
IgniteTestUtils.await(igniteImpl.catalogManager().execute(CreateSchemaCommand.systemSchemaBuilder().name(schema).build()));
343342
}
344343

345344
assertThrowsSqlException(
@@ -348,6 +347,44 @@ public void testItIsNotPossibleToCreateTablesInSystemSchema(String schema) {
348347
() -> sql(format("CREATE TABLE {}.SYS_TABLE (NAME VARCHAR PRIMARY KEY, SIZE BIGINT)", schema.toLowerCase())));
349348
}
350349

350+
@ParameterizedTest
351+
@MethodSource("reservedSchemaNames")
352+
public void testCreateSystemSchemas(String schema) {
353+
assertThrowsSqlException(
354+
STMT_VALIDATION_ERR,
355+
format("Reserved system schema with name '{}' can't be created.", schema),
356+
() -> sql(format("CREATE SCHEMA {}", schema.toLowerCase())));
357+
358+
assertThrowsSqlException(
359+
STMT_VALIDATION_ERR,
360+
format("Reserved system schema with name '{}' can't be created.", schema),
361+
() -> sql(format("CREATE SCHEMA {}", schema)));
362+
363+
assertThrowsSqlException(
364+
STMT_VALIDATION_ERR,
365+
format("Reserved system schema with name '{}' can't be created.", schema),
366+
() -> sql(format("CREATE SCHEMA \"{}\"", schema)));
367+
}
368+
369+
@ParameterizedTest
370+
@MethodSource("reservedSchemaNames")
371+
public void testDropSystemSchemas(String schema) {
372+
assertThrowsSqlException(
373+
STMT_VALIDATION_ERR,
374+
format("System schema can't be dropped [name={}]", schema),
375+
() -> sql(format("DROP SCHEMA {}", schema.toLowerCase())));
376+
377+
assertThrowsSqlException(
378+
STMT_VALIDATION_ERR,
379+
format("System schema can't be dropped [name={}]", schema),
380+
() -> sql(format("DROP SCHEMA {}", schema)));
381+
382+
assertThrowsSqlException(
383+
STMT_VALIDATION_ERR,
384+
format("System schema can't be dropped [name={}]", schema),
385+
() -> sql(format("DROP SCHEMA \"{}\"", schema)));
386+
}
387+
351388
private static Stream<Arguments> reservedSchemaNames() {
352389
return SYSTEM_SCHEMAS.stream().map(Arguments::of);
353390
}

modules/sql-engine/src/integrationTest/sql/group1/identifiers/test_long_identifiers.test

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
# description: SQL feature F391 (Long identifiers)
33
# group: [identifiers]
44

5-
# TODO: IGNITE-19703 Add cases for long identifiers for schema names.
6-
75
statement ok
86
PRAGMA enable_verification
97

@@ -13,6 +11,21 @@ tableName_veryLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1311
statement error: Non-query expression encountered in illegal context.
1412
SELECT 1; tableName_veryLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf129Characters
1513

14+
# Create schema with long identifiers
15+
statement ok
16+
CREATE SCHEMA identifier_veryLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf128Characters;
17+
18+
statement error: Length of identifier
19+
CREATE SCHEMA identifier_veryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf129Characters;
20+
21+
# Create schema and table with long identifiers
22+
statement ok
23+
CREATE TABLE identifier_veryLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf128Characters.tableName_veryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf128Characters (keyColumnName_veryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf128Characters INTEGER, valueColumnName_veryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf128Characters INTEGER, PRIMARY KEY (keyColumnName_veryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf128Characters));
24+
25+
statement ok
26+
DROP SCHEMA identifier_veryLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongIdentifierOf128Characters CASCADE;
27+
28+
1629
# Create table with short identifiers for test simplicity purpose
1730
statement ok
1831
CREATE TABLE t (id INTEGER, val INTEGER, PRIMARY KEY (id))

0 commit comments

Comments
 (0)