Skip to content

Commit

Permalink
IGNITE-23353 Improve CREATE TABLE syntax (apache#4599)
Browse files Browse the repository at this point in the history
  • Loading branch information
ygerzhedovich authored Nov 4, 2024
1 parent f1b1b60 commit d09ea51
Show file tree
Hide file tree
Showing 67 changed files with 242 additions and 501 deletions.
2 changes: 1 addition & 1 deletion docs/_docs/developers-guide/java-to-tables.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ CREATE TABLE IF NOT EXISTS kv_pojo_test (
PRIMARY KEY (id, id_str desc)
)
COLOCATE BY (f_name, l_name)
WITH PRIMARY_ZONE='ZONE_TEST';
ZONE ZONE_TEST;
CREATE INDEX ix_test (f_name, l_name desc nulls last);
----
Expand Down
43 changes: 13 additions & 30 deletions docs/_docs/sql-reference/ddl.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ NonTerminal('column_list', {href:'./grammar-reference/#column_list'})
),
Optional(
Sequence(
Terminal('WITH'),
OneOrMore (NonTerminal('parameter', {href:'./grammar-reference/#parameter'}), Terminal(','))
Terminal('ZONE'),
NonTerminal('zone_name')
)
),
Optional(
Sequence(
Terminal('EXPIRE'),
Terminal('AT'),
NonTerminal('expiry_column_name')
Terminal('STORAGE ENGINE'),
NonTerminal('storage_engine_name')
)
)
)
Expand All @@ -67,10 +66,8 @@ Keywords and parameters:
* `table_name` - name of the table. Can be schema-qualified.
* `IF NOT EXISTS` - create the table only if a table with the same name does not exist.
* `COLOCATE BY` - colocation key. The key can be composite. Primary key must include colocation key. Was `affinity_key` in Ignite 2.x.
* `WITH` - accepts additional parameters; currently, accepts only:
** `PRIMARY_ZONE` - sets the link:sql-reference/distribution-zones[Distribution Zone].
* `EXPIRE AT` - allows specifying a column with a point in time when a record should be deleted.
* `expiry_column_name` - name of the column that contains values on which the record expiry is based.
* `ZONE` - sets the link:sql-reference/distribution-zones[Distribution Zone].
* `STORAGE ENGINE` - sets the link:sql-reference/distribution-zones[Distribution Zone].

Examples:

Expand All @@ -97,18 +94,7 @@ CREATE TABLE IF NOT EXISTS Person (
name varchar,
age int,
company varchar
) WITH PRIMARY_ZONE=`MYZONE`
----

Creates a Person table where the records expire at timestamps in the `ttl` column:

[source,sql]
----
CREATE TABLE IF NOT EXISTS Person (
id int PRIMARY KEY,
name varchar,
ttl timestamp
) EXPIRE AT ttl
) ZONE MYZONE
----

Creates a Person table where the default value if the `city_id` column is 1:
Expand Down Expand Up @@ -612,15 +598,14 @@ NonTerminal('column_list', {href:'./grammar-reference/#column_list'})
),
Optional(
Sequence(
Terminal('WITH'),
OneOrMore (NonTerminal('parameter', {href:'./grammar-reference/#parameter'}), Terminal(','))
Terminal('ZONE'),
NonTerminal('zone_name')
)
),
Optional(
Sequence(
Terminal('EXPIRE'),
Terminal('AT'),
NonTerminal('expiry_column_name')
Terminal('STORAGE ENGINE'),
NonTerminal('storage_engine_name')
)
)
)
Expand All @@ -630,7 +615,5 @@ Keywords and parameters:
* `cache_name` - name of the cache. Can be schema-qualified.
* `IF NOT EXISTS` - create the cache only if a cache with the same name does not exist.
* `COLOCATE BY` - colocation key. The key can be composite. Primary key must include colocation key. Was `affinity_key` in Ignite 2.x.
* `WITH` - accepts additional parameters; currently, accepts only:
** `PRIMARY_ZONE` - sets the link:sql-reference/distribution-zones[Distribution Zone]. The selected distribution zone must use `aimem` storage engine.
* `EXPIRE AT` - allows specifying a column with a point in time when a record should be deleted.
* `expiry_column_name` - name of the column that contains values on which the record expiry is based.
* `ZONE` - sets the link:sql-reference/distribution-zones[Distribution Zone]. The selected distribution zone must use `aimem` storage engine.
* `STORAGE ENGINE` - sets the link:sql-reference/distribution-zones[Distribution Zone].
6 changes: 3 additions & 3 deletions docs/_docs/sql-reference/grammar-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -197,21 +197,21 @@ When a parameter is specified, you can provide it as a literal value or as an id

----
CREATE ZONE test_zone WITH STORAGE_PROFILES='default';
CREATE TABLE test_table (id INT PRIMARY KEY, val INT) WITH PRIMARY_ZONE=test_zone;
CREATE TABLE test_table (id INT PRIMARY KEY, val INT) ZONE test_zone;
----

In this case, `test_zone` is the identifier, and is used as an identifier. When used like this, the parameters are not case-sensitive.

----
CREATE ZONE "test_zone" WITH STORAGE_PROFILES='default';
CREATE TABLE test_table (id INT PRIMARY KEY, val INT) WITH PRIMARY_ZONE='test_zone';
CREATE TABLE test_table (id INT PRIMARY KEY, val INT) ZONE "test_zone";
----

In this case, `test_zone` is created as a literal value, and is used as a literal. When used like this, the parameter is case-sensitive.

----
CREATE ZONE test_zone WITH STORAGE_PROFILES='default';
CREATE TABLE test_table (id INT PRIMARY KEY, val INT) WITH PRIMARY_ZONE=`TEST_ZONE`;
CREATE TABLE test_table (id INT PRIMARY KEY, val INT) ZONE TEST_ZONE;
----

In this case, `test_zone` is created as an identifier, and is case-insensitive. As such, when `TEST_ZONE` is used as a literal, it still matches the identifier.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void run() throws SQLException {
+ "FIRST_NAME VARCHAR, "
+ "LAST_NAME VARCHAR, "
+ "BALANCE DOUBLE) "
+ "WITH PRIMARY_ZONE = 'ACCOUNTS_ZONE'"
+ "ZONE ACCOUNTS_ZONE"
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
* <pre>
* CREATE ZONE IF NOT EXISTS zone_test WITH PARTITIONS=1, REPLICAS=3, STORAGE_PROFILES='default';
* CREATE TABLE IF NOT EXISTS table_test (id int, id_str varchar(20), f_name varchar(20) not null default 'a', \
* l_name varchar, str varchar, PRIMARY KEY (id, id_str)) COLOCATE BY (id, id_str) WITH PRIMARY_ZONE='ZONE_TEST';
* l_name varchar, str varchar, PRIMARY KEY (id, id_str)) COLOCATE BY (id, id_str) ZONE ZONE_TEST;
* CREATE INDEX IF NOT EXISTS ix_pojo ON table_test (f_name, l_name desc);
* </pre>
* And here's the equivalent definition using builders:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public boolean ifNotExists() {
/**
* Returns primary zone name.
*
* @return Zone name to use in the {@code WITH PRIMARY_ZONE} option or {@code null} if not specified.
* @return Zone name to use in the {@code ZONE} option or {@code null} if not specified.
*/
public @Nullable String zoneName() {
return zoneName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ class CreateTableImpl extends AbstractCatalogQuery<Name> {

private final List<Constraint> constraints = new ArrayList<>();

private final List<Option> withOptions = new ArrayList<>();

private Colocate colocate;

private Zone zone;

private final List<CreateIndexImpl> indexes = new ArrayList<>();

/**
Expand Down Expand Up @@ -119,7 +119,7 @@ CreateTableImpl colocateBy(List<String> columns) {
CreateTableImpl zone(String zone) {
Objects.requireNonNull(zone, "Zone name must not be null.");

withOptions.add(Option.primaryZone(zone));
this.zone = new Zone(zone.toUpperCase());
return this;
}

Expand Down Expand Up @@ -172,9 +172,8 @@ protected void accept(QueryContext ctx) {
ctx.sql(" ").visit(colocate);
}

if (!withOptions.isEmpty()) {
ctx.sql(" ").sql("WITH ");
ctx.visit(partsList(withOptions));
if (zone != null) {
ctx.sql(" ").visit(zone);
}

ctx.sql(";");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ private Option(String name, Object value) {
this.value = value;
}

public static Option primaryZone(String zone) {
return new Option("PRIMARY_ZONE", zone.toUpperCase());
}

public static Option partitions(Integer partitions) {
return new Option("PARTITIONS", partitions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@
* limitations under the License.
*/

package org.apache.ignite.internal.sql.engine.prepare.ddl;
package org.apache.ignite.internal.catalog.sql;

/**
* Enumerates the options for CREATE TABLE and ALTER TABLE statements.
*/
public enum TableOptionEnum {
/** Primary zone. */
PRIMARY_ZONE,
class Zone extends QueryPart {

private final String zone;

Zone(String zone) {
this.zone = zone;
}

/** Storage profile. */
STORAGE_PROFILE
@Override
protected void accept(QueryContext ctx) {
ctx.sql("ZONE " + zone);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void createFromKeyValueClassesPrimitive() {
+ " DATA_NODES_FILTER='filter';"
+ System.lineSeparator()
+ "CREATE TABLE IF NOT EXISTS PUBLIC.pojo_value_test (id int, f_name varchar, l_name varchar, str varchar,"
+ " PRIMARY KEY (id)) COLOCATE BY (id, id_str) WITH PRIMARY_ZONE='ZONE_TEST';"
+ " PRIMARY KEY (id)) COLOCATE BY (id, id_str) ZONE ZONE_TEST;"
+ System.lineSeparator()
+ "CREATE INDEX IF NOT EXISTS ix_pojo ON PUBLIC.pojo_value_test (f_name, l_name desc);")
);
Expand All @@ -125,7 +125,7 @@ void createFromKeyValueClasses() {
+ " DATA_NODES_FILTER='filter';"
+ System.lineSeparator()
+ "CREATE TABLE IF NOT EXISTS PUBLIC.pojo_value_test (id int, id_str varchar(20), f_name varchar, l_name varchar,"
+ " str varchar, PRIMARY KEY (id, id_str)) COLOCATE BY (id, id_str) WITH PRIMARY_ZONE='ZONE_TEST';"
+ " str varchar, PRIMARY KEY (id, id_str)) COLOCATE BY (id, id_str) ZONE ZONE_TEST;"
+ System.lineSeparator()
+ "CREATE INDEX IF NOT EXISTS ix_pojo ON PUBLIC.pojo_value_test (f_name, l_name desc);")
);
Expand All @@ -144,7 +144,7 @@ void createFromRecordClass() {
+ "CREATE TABLE IF NOT EXISTS PUBLIC.pojo_test"
+ " (id int, id_str varchar(20), f_name varchar(20) not null default 'a',"
+ " l_name varchar, str varchar, PRIMARY KEY (id, id_str))"
+ " COLOCATE BY (id, id_str) WITH PRIMARY_ZONE='ZONE_TEST';"
+ " COLOCATE BY (id, id_str) ZONE ZONE_TEST;"
+ System.lineSeparator()
+ "CREATE INDEX IF NOT EXISTS ix_pojo ON PUBLIC.pojo_test (f_name, l_name desc);")
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ void createFromTableBuilder() {
createTable(table),
is("CREATE TABLE IF NOT EXISTS PUBLIC.builder_test"
+ " (id int, id_str varchar, f_name varchar(20) NOT NULL DEFAULT 'a', PRIMARY KEY (id, id_str))"
+ " COLOCATE BY (id, id_str) WITH PRIMARY_ZONE='ZONE_TEST';"
+ " COLOCATE BY (id, id_str) ZONE ZONE_TEST;"
+ System.lineSeparator()
+ "CREATE INDEX IF NOT EXISTS ix_id_str_f_name ON PUBLIC.builder_test (id_str, f_name);"
+ System.lineSeparator()
Expand Down Expand Up @@ -153,7 +153,7 @@ void createFromKeyValueViewAnnotatedKeyAndValue() {
createTable(tableDefinition),
is("CREATE TABLE PUBLIC.pojo_value_test"
+ " (id int, id_str varchar(20), f_name varchar, l_name varchar, str varchar, PRIMARY KEY (id, id_str))"
+ " COLOCATE BY (id, id_str) WITH PRIMARY_ZONE='ZONE_TEST';")
+ " COLOCATE BY (id, id_str) ZONE ZONE_TEST;")
);
}

Expand All @@ -170,7 +170,7 @@ void createFromRecordView() {
createTable(tableDefinition),
is("CREATE TABLE IF NOT EXISTS PUBLIC.pojo_test (id int, id_str varchar(20),"
+ " f_name varchar(20) not null default 'a', l_name varchar, str varchar,"
+ " PRIMARY KEY (id, id_str)) COLOCATE BY (id, id_str) WITH PRIMARY_ZONE='ZONE_TEST';")
+ " PRIMARY KEY (id, id_str)) COLOCATE BY (id, id_str) ZONE ZONE_TEST;")
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ void withOptions() {
Query query1 = createTable().name("table1").addColumn("col1", INTEGER)
.zone("zone1");
String sql = query1.toString(); // zone param is lowercase
assertThat(sql, is("CREATE TABLE table1 (col1 int) WITH PRIMARY_ZONE='ZONE1';")); // zone result is uppercase
assertThat(sql, is("CREATE TABLE table1 (col1 int) ZONE ZONE1;")); // zone result is uppercase
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,6 @@ void constraintPart() {
assertThat(sql(constraint), is("PRIMARY KEY USING SORTED (a, b)"));
}

@Test
void withOptionPart() {
Option withOption = Option.primaryZone("z");
assertThat(sql(withOption), is("PRIMARY_ZONE='Z'"));

withOption = Option.partitions(1);
assertThat(sql(withOption), is("PARTITIONS=1"));

withOption = Option.replicas(1);
assertThat(sql(withOption), is("REPLICAS=1"));
}

@Test
void queryPartCollection() {
QueryPartCollection<Name> collection = QueryPartCollection.partsList(new Name("a"), new Name("b"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private void createTablesInParallel() {
String tableName = "TEST" + n;

node(0).sql().executeScript(
"CREATE TABLE " + tableName + " (id INT PRIMARY KEY, val VARCHAR) WITH primary_zone='" + ZONE_NAME + "'"
"CREATE TABLE " + tableName + " (id INT PRIMARY KEY, val VARCHAR) ZONE " + ZONE_NAME
);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public abstract class ItResetPartitionsTest extends CliIntegrationTest {
@BeforeAll
public void createTables() {
sql(String.format("CREATE ZONE \"%s\" WITH storage_profiles='%s'", ZONE, DEFAULT_AIPERSIST_PROFILE_NAME));
sql(String.format("CREATE TABLE PUBLIC.\"%s\" (id INT PRIMARY KEY, val INT) WITH PRIMARY_ZONE = '%s'", TABLE_NAME, ZONE));
sql(String.format("CREATE TABLE PUBLIC.\"%s\" (id INT PRIMARY KEY, val INT) ZONE \"%s\"", TABLE_NAME, ZONE));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public abstract class ItRestartPartitionsTest extends CliIntegrationTest {
@BeforeAll
public void createTables() {
sql(String.format("CREATE ZONE \"%s\" WITH storage_profiles='%s'", ZONE, DEFAULT_AIPERSIST_PROFILE_NAME));
sql(String.format("CREATE TABLE PUBLIC.\"%s\" (id INT PRIMARY KEY, val INT) WITH PRIMARY_ZONE = '%s'", TABLE_NAME, ZONE));
sql(String.format("CREATE TABLE PUBLIC.\"%s\" (id INT PRIMARY KEY, val INT) ZONE \"%s\"", TABLE_NAME, ZONE));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public abstract class ItPartitionStatesTest extends CliIntegrationTest {
public static void createTables() {
ZONES_CONTAINING_TABLES.forEach(name -> {
sql(String.format("CREATE ZONE \"%s\" WITH storage_profiles='%s'", name, DEFAULT_AIPERSIST_PROFILE_NAME));
sql(String.format("CREATE TABLE \"%s_table\" (id INT PRIMARY KEY, val INT) WITH PRIMARY_ZONE = '%1$s'", name));
sql(String.format("CREATE TABLE \"%s_table\" (id INT PRIMARY KEY, val INT) ZONE \"%1$s\"", name));
});

sql(String.format("CREATE ZONE \"%s\" WITH storage_profiles='%s'", EMPTY_ZONE, DEFAULT_AIPERSIST_PROFILE_NAME));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,6 @@ void incorrectQueryTest() {
);
}

@Test
@DisplayName("Should display readable error when wrong option is given on CREATE TABLE")
void incorrectEngineOnCreate() {
execute("sql", "create table mytable1(i int, j int, primary key (i)) with notexist='nusuch'", "--jdbc-url", JDBC_URL);

assertAll(
() -> assertExitCodeIs(1),
this::assertOutputIsEmpty,
() -> assertErrOutputContains("Unexpected table option [option=NOTEXIST")
);
}

@Test
@DisplayName("Should display readable error when not SQL expression given")
void notSqlExpression() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public enum IgniteSqlCommand {
CREATE_TABLE("CREATE TABLE",
"CREATE TABLE [IF NOT EXISTS] tableName (tableColumn [, tableColumn]...)\n"
+ "[COLOCATE [BY] (columnName [, columnName]...)]\n"
+ "[WITH paramName=paramValue [,paramName=paramValue]...]\n"
+ "[EXPIRE AT columnName]\n"
+ "[ZONE zoneName]\n"
+ "[STORAGE PROFILE storageProfile]\n"
+ "tableColumn = columnName columnType [[NOT] NULL] [DEFAULT defaultValue] [PRIMARY KEY]"),
create_table("create table", CREATE_TABLE.syntax),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ private void createReplicatedTestTableWithOneRow() {
// Number of replicas == number of nodes and number of partitions == 1. This gives us the majority on primary replica stop.
// After the primary replica is stopped we still be able to select new primary replica selected.
executeSql("CREATE ZONE TEST_ZONE WITH REPLICAS=3, PARTITIONS=1, STORAGE_PROFILES='" + DEFAULT_STORAGE_PROFILE + "'");
executeSql("CREATE TABLE test (k int, v int, CONSTRAINT PK PRIMARY KEY (k)) WITH PRIMARY_ZONE='TEST_ZONE'");
executeSql("CREATE TABLE test (k int, v int, CONSTRAINT PK PRIMARY KEY (k)) ZONE TEST_ZONE");
executeSql("INSERT INTO test(k, v) VALUES (1, 101)");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,8 +465,8 @@ private static String alterZoneSql(int replicas) {

private static String createTableSql() {
return String.format(
"CREATE TABLE %s(%s INT PRIMARY KEY, %s VARCHAR) WITH STORAGE_PROFILE='%s',PRIMARY_ZONE='%s'",
TABLE_NAME, COLUMN_KEY, COLUMN_VAL, DEFAULT_AIPERSIST_PROFILE_NAME, ZONE_NAME
"CREATE TABLE %s(%s INT PRIMARY KEY, %s VARCHAR) ZONE %s STORAGE PROFILE '%s'",
TABLE_NAME, COLUMN_KEY, COLUMN_VAL, ZONE_NAME, DEFAULT_AIPERSIST_PROFILE_NAME
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ private static void createTableAndInsertManyPeople(AtomicInteger nextPersonId) {
// Use hash index for primary key, otherwise if sorted index exists,
// the optimizer might choose it (the primary key index) instead of an existing sorted one.
sql(format(
"CREATE TABLE IF NOT EXISTS {} (id INT, name VARCHAR, salary DOUBLE, PRIMARY KEY USING HASH (id)) WITH PRIMARY_ZONE='{}'",
"CREATE TABLE IF NOT EXISTS {} (id INT, name VARCHAR, salary DOUBLE, PRIMARY KEY USING HASH (id)) ZONE {}",
TABLE_NAME, ZONE_NAME
));

Expand Down
Loading

0 comments on commit d09ea51

Please sign in to comment.