From 350354f1b3bcce71605e210642c1ba77e21b007b Mon Sep 17 00:00:00 2001 From: Chengxiong Ruan Date: Thu, 3 Feb 2022 13:40:59 -0500 Subject: [PATCH] sql: enable storage parameter syntax for primary key This is a prerequisite to support `WITH (bucket_count=...)` syntax for hash sharded index. Release note (sql change): Previously, `WITH (param=value)` syntax is not allowed for primary key. However, that does not align with postgresql. Also, to support `WITH (bucket_count=...)` syntax for hash sharded index, we need to enable it as well. This pr also adds extra validation to prevent existing storage params from being applied to primary keys. Which means, even the syntax is accepted by the parser, none of existing storage param for inverted index is allowed on primary key. We don't actually set those params on top of PKs internally, but we need to tell user which param is supprted or not. Eventually, when we add support for `bucket_count` param, a param white list will be maintained for PKs. --- docs/generated/sql/bnf/alter_primary_key.bnf | 10 ++- docs/generated/sql/bnf/alter_table.bnf | 4 +- .../sql/bnf/alter_table_partition_by.bnf | 4 +- docs/generated/sql/bnf/col_qualification.bnf | 10 ++- .../sql/bnf/create_as_col_qual_list.bnf | 2 +- .../sql/bnf/create_as_constraint_def.bnf | 2 +- docs/generated/sql/bnf/create_index_stmt.bnf | 4 +- docs/generated/sql/bnf/index_def.bnf | 24 +++---- docs/generated/sql/bnf/stmt_block.bnf | 20 +++--- docs/generated/sql/bnf/table_constraint.bnf | 10 ++- pkg/sql/alter_primary_key.go | 5 ++ pkg/sql/create_table.go | 46 +++++++++++++ .../testdata/logic_test/alter_primary_key | 14 ++++ .../testdata/logic_test/create_table | 66 +++++++++++++++++++ pkg/sql/paramparse/BUILD.bazel | 1 + pkg/sql/paramparse/validation.go | 31 +++++++++ pkg/sql/parser/sql.y | 55 +++++++++------- pkg/sql/sem/tree/alter_table.go | 7 +- pkg/sql/sem/tree/create.go | 18 +++-- 19 files changed, 248 insertions(+), 85 deletions(-) create mode 100644 pkg/sql/paramparse/validation.go diff --git a/docs/generated/sql/bnf/alter_primary_key.bnf b/docs/generated/sql/bnf/alter_primary_key.bnf index c6415de857e4..756482eb5dc2 100644 --- a/docs/generated/sql/bnf/alter_primary_key.bnf +++ b/docs/generated/sql/bnf/alter_primary_key.bnf @@ -1,7 +1,5 @@ alter_onetable_stmt ::= - 'ALTER' 'TABLE' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets - | 'ALTER' 'TABLE' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' 'USING' 'HASH' - | 'ALTER' 'TABLE' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' - | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets - | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' 'USING' 'HASH' - | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' + 'ALTER' 'TABLE' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_with_storage_parameter_list + | 'ALTER' 'TABLE' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_with_storage_parameter_list + | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_with_storage_parameter_list + | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_with_storage_parameter_list diff --git a/docs/generated/sql/bnf/alter_table.bnf b/docs/generated/sql/bnf/alter_table.bnf index 1da9dbc6ec78..2136d0e6ad34 100644 --- a/docs/generated/sql/bnf/alter_table.bnf +++ b/docs/generated/sql/bnf/alter_table.bnf @@ -1,3 +1,3 @@ alter_onetable_stmt ::= - 'ALTER' 'TABLE' table_name ( ( ( 'RENAME' ( 'COLUMN' | ) column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' ( column_name typename col_qual_list ) | 'ADD' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DEFAULT' a_expr | 'DROP' 'DEFAULT' ) | 'ALTER' ( 'COLUMN' | ) column_name alter_column_on_update | 'ALTER' ( 'COLUMN' | ) column_name alter_column_visible | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'NOT' 'NULL' | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'STORED' | 'ALTER' ( 'COLUMN' | ) column_name 'SET' 'NOT' 'NULL' | 'DROP' ( 'COLUMN' | ) 'IF' 'EXISTS' column_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' ( 'COLUMN' | ) column_name ( 'CASCADE' | 'RESTRICT' | ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DATA' | ) 'TYPE' typename ( 'COLLATE' collation_name | ) ( 'USING' a_expr | ) | 'ADD' ( 'CONSTRAINT' constraint_name constraint_elem | constraint_elem ) | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' 'CONSTRAINT' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | partition_by_table | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) ( ( ',' ( 'RENAME' ( 'COLUMN' | ) column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' ( column_name typename col_qual_list ) | 'ADD' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DEFAULT' a_expr | 'DROP' 'DEFAULT' ) | 'ALTER' ( 'COLUMN' | ) column_name alter_column_on_update | 'ALTER' ( 'COLUMN' | ) column_name alter_column_visible | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'NOT' 'NULL' | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'STORED' | 'ALTER' ( 'COLUMN' | ) column_name 'SET' 'NOT' 'NULL' | 'DROP' ( 'COLUMN' | ) 'IF' 'EXISTS' column_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' ( 'COLUMN' | ) column_name ( 'CASCADE' | 'RESTRICT' | ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DATA' | ) 'TYPE' typename ( 'COLLATE' collation_name | ) ( 'USING' a_expr | ) | 'ADD' ( 'CONSTRAINT' constraint_name constraint_elem | constraint_elem ) | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' 'CONSTRAINT' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | partition_by_table | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) )* ) - | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name ( ( ( 'RENAME' ( 'COLUMN' | ) column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' ( column_name typename col_qual_list ) | 'ADD' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DEFAULT' a_expr | 'DROP' 'DEFAULT' ) | 'ALTER' ( 'COLUMN' | ) column_name alter_column_on_update | 'ALTER' ( 'COLUMN' | ) column_name alter_column_visible | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'NOT' 'NULL' | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'STORED' | 'ALTER' ( 'COLUMN' | ) column_name 'SET' 'NOT' 'NULL' | 'DROP' ( 'COLUMN' | ) 'IF' 'EXISTS' column_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' ( 'COLUMN' | ) column_name ( 'CASCADE' | 'RESTRICT' | ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DATA' | ) 'TYPE' typename ( 'COLLATE' collation_name | ) ( 'USING' a_expr | ) | 'ADD' ( 'CONSTRAINT' constraint_name constraint_elem | constraint_elem ) | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' 'CONSTRAINT' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | partition_by_table | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) ( ( ',' ( 'RENAME' ( 'COLUMN' | ) column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' ( column_name typename col_qual_list ) | 'ADD' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DEFAULT' a_expr | 'DROP' 'DEFAULT' ) | 'ALTER' ( 'COLUMN' | ) column_name alter_column_on_update | 'ALTER' ( 'COLUMN' | ) column_name alter_column_visible | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'NOT' 'NULL' | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'STORED' | 'ALTER' ( 'COLUMN' | ) column_name 'SET' 'NOT' 'NULL' | 'DROP' ( 'COLUMN' | ) 'IF' 'EXISTS' column_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' ( 'COLUMN' | ) column_name ( 'CASCADE' | 'RESTRICT' | ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DATA' | ) 'TYPE' typename ( 'COLLATE' collation_name | ) ( 'USING' a_expr | ) | 'ADD' ( 'CONSTRAINT' constraint_name constraint_elem | constraint_elem ) | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' 'CONSTRAINT' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | partition_by_table | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) )* ) + 'ALTER' 'TABLE' table_name ( ( ( 'RENAME' ( 'COLUMN' | ) column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' ( column_name typename col_qual_list ) | 'ADD' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DEFAULT' a_expr | 'DROP' 'DEFAULT' ) | 'ALTER' ( 'COLUMN' | ) column_name alter_column_on_update | 'ALTER' ( 'COLUMN' | ) column_name alter_column_visible | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'NOT' 'NULL' | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'STORED' | 'ALTER' ( 'COLUMN' | ) column_name 'SET' 'NOT' 'NULL' | 'DROP' ( 'COLUMN' | ) 'IF' 'EXISTS' column_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' ( 'COLUMN' | ) column_name ( 'CASCADE' | 'RESTRICT' | ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DATA' | ) 'TYPE' typename ( 'COLLATE' collation_name | ) ( 'USING' a_expr | ) | 'ADD' ( 'CONSTRAINT' constraint_name constraint_elem | constraint_elem ) | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' 'CONSTRAINT' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | partition_by_table | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) ( ( ',' ( 'RENAME' ( 'COLUMN' | ) column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' ( column_name typename col_qual_list ) | 'ADD' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DEFAULT' a_expr | 'DROP' 'DEFAULT' ) | 'ALTER' ( 'COLUMN' | ) column_name alter_column_on_update | 'ALTER' ( 'COLUMN' | ) column_name alter_column_visible | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'NOT' 'NULL' | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'STORED' | 'ALTER' ( 'COLUMN' | ) column_name 'SET' 'NOT' 'NULL' | 'DROP' ( 'COLUMN' | ) 'IF' 'EXISTS' column_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' ( 'COLUMN' | ) column_name ( 'CASCADE' | 'RESTRICT' | ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DATA' | ) 'TYPE' typename ( 'COLLATE' collation_name | ) ( 'USING' a_expr | ) | 'ADD' ( 'CONSTRAINT' constraint_name constraint_elem | constraint_elem ) | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' 'CONSTRAINT' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | partition_by_table | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) )* ) + | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name ( ( ( 'RENAME' ( 'COLUMN' | ) column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' ( column_name typename col_qual_list ) | 'ADD' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DEFAULT' a_expr | 'DROP' 'DEFAULT' ) | 'ALTER' ( 'COLUMN' | ) column_name alter_column_on_update | 'ALTER' ( 'COLUMN' | ) column_name alter_column_visible | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'NOT' 'NULL' | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'STORED' | 'ALTER' ( 'COLUMN' | ) column_name 'SET' 'NOT' 'NULL' | 'DROP' ( 'COLUMN' | ) 'IF' 'EXISTS' column_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' ( 'COLUMN' | ) column_name ( 'CASCADE' | 'RESTRICT' | ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DATA' | ) 'TYPE' typename ( 'COLLATE' collation_name | ) ( 'USING' a_expr | ) | 'ADD' ( 'CONSTRAINT' constraint_name constraint_elem | constraint_elem ) | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' 'CONSTRAINT' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | partition_by_table | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) ( ( ',' ( 'RENAME' ( 'COLUMN' | ) column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' ( column_name typename col_qual_list ) | 'ADD' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' ( column_name typename col_qual_list ) | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' ( column_name typename col_qual_list ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DEFAULT' a_expr | 'DROP' 'DEFAULT' ) | 'ALTER' ( 'COLUMN' | ) column_name alter_column_on_update | 'ALTER' ( 'COLUMN' | ) column_name alter_column_visible | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'NOT' 'NULL' | 'ALTER' ( 'COLUMN' | ) column_name 'DROP' 'STORED' | 'ALTER' ( 'COLUMN' | ) column_name 'SET' 'NOT' 'NULL' | 'DROP' ( 'COLUMN' | ) 'IF' 'EXISTS' column_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' ( 'COLUMN' | ) column_name ( 'CASCADE' | 'RESTRICT' | ) | 'ALTER' ( 'COLUMN' | ) column_name ( 'SET' 'DATA' | ) 'TYPE' typename ( 'COLLATE' collation_name | ) ( 'USING' a_expr | ) | 'ADD' ( 'CONSTRAINT' constraint_name constraint_elem | constraint_elem ) | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'DROP' 'CONSTRAINT' constraint_name ( 'CASCADE' | 'RESTRICT' | ) | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | partition_by_table | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) )* ) diff --git a/docs/generated/sql/bnf/alter_table_partition_by.bnf b/docs/generated/sql/bnf/alter_table_partition_by.bnf index be4913e668ad..74ba4941407a 100644 --- a/docs/generated/sql/bnf/alter_table_partition_by.bnf +++ b/docs/generated/sql/bnf/alter_table_partition_by.bnf @@ -1,3 +1,3 @@ alter_onetable_stmt ::= - 'ALTER' 'TABLE' table_name 'PARTITION' 'ALL' 'BY' partition_by_inner ( ( ',' ( 'RENAME' opt_column column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' column_def | 'ADD' 'IF' 'NOT' 'EXISTS' column_def | 'ADD' 'COLUMN' column_def | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' column_def | 'ALTER' opt_column column_name alter_column_default | 'ALTER' opt_column column_name alter_column_on_update | 'ALTER' opt_column column_name alter_column_visible | 'ALTER' opt_column column_name 'DROP' 'NOT' 'NULL' | 'ALTER' opt_column column_name 'DROP' 'STORED' | 'ALTER' opt_column column_name 'SET' 'NOT' 'NULL' | 'DROP' opt_column 'IF' 'EXISTS' column_name opt_drop_behavior | 'DROP' opt_column column_name opt_drop_behavior | 'ALTER' opt_column column_name opt_set_data 'TYPE' typename opt_collate opt_alter_column_using | 'ADD' table_constraint opt_validate_behavior | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem opt_validate_behavior | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name opt_drop_behavior | 'DROP' 'CONSTRAINT' constraint_name opt_drop_behavior | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | ( partition_by | 'PARTITION' 'ALL' 'BY' partition_by_inner ) | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) )* - | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'PARTITION' 'ALL' 'BY' partition_by_inner ( ( ',' ( 'RENAME' opt_column column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' column_def | 'ADD' 'IF' 'NOT' 'EXISTS' column_def | 'ADD' 'COLUMN' column_def | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' column_def | 'ALTER' opt_column column_name alter_column_default | 'ALTER' opt_column column_name alter_column_on_update | 'ALTER' opt_column column_name alter_column_visible | 'ALTER' opt_column column_name 'DROP' 'NOT' 'NULL' | 'ALTER' opt_column column_name 'DROP' 'STORED' | 'ALTER' opt_column column_name 'SET' 'NOT' 'NULL' | 'DROP' opt_column 'IF' 'EXISTS' column_name opt_drop_behavior | 'DROP' opt_column column_name opt_drop_behavior | 'ALTER' opt_column column_name opt_set_data 'TYPE' typename opt_collate opt_alter_column_using | 'ADD' table_constraint opt_validate_behavior | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem opt_validate_behavior | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name opt_drop_behavior | 'DROP' 'CONSTRAINT' constraint_name opt_drop_behavior | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | ( partition_by | 'PARTITION' 'ALL' 'BY' partition_by_inner ) | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) )* + 'ALTER' 'TABLE' table_name 'PARTITION' 'ALL' 'BY' partition_by_inner ( ( ',' ( 'RENAME' opt_column column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' column_def | 'ADD' 'IF' 'NOT' 'EXISTS' column_def | 'ADD' 'COLUMN' column_def | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' column_def | 'ALTER' opt_column column_name alter_column_default | 'ALTER' opt_column column_name alter_column_on_update | 'ALTER' opt_column column_name alter_column_visible | 'ALTER' opt_column column_name 'DROP' 'NOT' 'NULL' | 'ALTER' opt_column column_name 'DROP' 'STORED' | 'ALTER' opt_column column_name 'SET' 'NOT' 'NULL' | 'DROP' opt_column 'IF' 'EXISTS' column_name opt_drop_behavior | 'DROP' opt_column column_name opt_drop_behavior | 'ALTER' opt_column column_name opt_set_data 'TYPE' typename opt_collate opt_alter_column_using | 'ADD' table_constraint opt_validate_behavior | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem opt_validate_behavior | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name opt_drop_behavior | 'DROP' 'CONSTRAINT' constraint_name opt_drop_behavior | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | ( partition_by | 'PARTITION' 'ALL' 'BY' partition_by_inner ) | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) )* + | 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'PARTITION' 'ALL' 'BY' partition_by_inner ( ( ',' ( 'RENAME' opt_column column_name 'TO' column_name | 'RENAME' 'CONSTRAINT' column_name 'TO' column_name | 'ADD' column_def | 'ADD' 'IF' 'NOT' 'EXISTS' column_def | 'ADD' 'COLUMN' column_def | 'ADD' 'COLUMN' 'IF' 'NOT' 'EXISTS' column_def | 'ALTER' opt_column column_name alter_column_default | 'ALTER' opt_column column_name alter_column_on_update | 'ALTER' opt_column column_name alter_column_visible | 'ALTER' opt_column column_name 'DROP' 'NOT' 'NULL' | 'ALTER' opt_column column_name 'DROP' 'STORED' | 'ALTER' opt_column column_name 'SET' 'NOT' 'NULL' | 'DROP' opt_column 'IF' 'EXISTS' column_name opt_drop_behavior | 'DROP' opt_column column_name opt_drop_behavior | 'ALTER' opt_column column_name opt_set_data 'TYPE' typename opt_collate opt_alter_column_using | 'ADD' table_constraint opt_validate_behavior | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem opt_validate_behavior | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name opt_drop_behavior | 'DROP' 'CONSTRAINT' constraint_name opt_drop_behavior | 'EXPERIMENTAL_AUDIT' 'SET' audit_mode | ( partition_by | 'PARTITION' 'ALL' 'BY' partition_by_inner ) | 'SET' '(' storage_parameter_list ')' | 'RESET' '(' storage_parameter_key_list ')' ) ) )* diff --git a/docs/generated/sql/bnf/col_qualification.bnf b/docs/generated/sql/bnf/col_qualification.bnf index 5f8bfd3b24c3..0a59587ac3a3 100644 --- a/docs/generated/sql/bnf/col_qualification.bnf +++ b/docs/generated/sql/bnf/col_qualification.bnf @@ -3,9 +3,8 @@ col_qualification ::= | 'CONSTRAINT' constraint_name 'NULL' | 'CONSTRAINT' constraint_name 'NOT' 'VISIBLE' | 'CONSTRAINT' constraint_name 'UNIQUE' - | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' - | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' 'USING' 'HASH' - | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets + | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' opt_with_storage_parameter_list + | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_with_storage_parameter_list | 'CONSTRAINT' constraint_name 'CHECK' '(' a_expr ')' | 'CONSTRAINT' constraint_name 'DEFAULT' b_expr | 'CONSTRAINT' constraint_name 'ON' 'UPDATE' b_expr @@ -20,9 +19,8 @@ col_qualification ::= | 'NULL' | 'NOT' 'VISIBLE' | 'UNIQUE' - | 'PRIMARY' 'KEY' - | 'PRIMARY' 'KEY' 'USING' 'HASH' - | 'PRIMARY' 'KEY' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets + | 'PRIMARY' 'KEY' opt_with_storage_parameter_list + | 'PRIMARY' 'KEY' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_with_storage_parameter_list | 'CHECK' '(' a_expr ')' | 'DEFAULT' b_expr | 'ON' 'UPDATE' b_expr diff --git a/docs/generated/sql/bnf/create_as_col_qual_list.bnf b/docs/generated/sql/bnf/create_as_col_qual_list.bnf index 62cdd9769292..d6a2cad01c2d 100644 --- a/docs/generated/sql/bnf/create_as_col_qual_list.bnf +++ b/docs/generated/sql/bnf/create_as_col_qual_list.bnf @@ -1,2 +1,2 @@ create_as_col_qual_list ::= - ( ( ( ( 'PRIMARY' 'KEY' ) | 'FAMILY' family_name ) ) )* + ( ( ( ( 'PRIMARY' 'KEY' opt_with_storage_parameter_list ) | 'FAMILY' family_name ) ) )* diff --git a/docs/generated/sql/bnf/create_as_constraint_def.bnf b/docs/generated/sql/bnf/create_as_constraint_def.bnf index cc4785c6412a..71c2dd433cab 100644 --- a/docs/generated/sql/bnf/create_as_constraint_def.bnf +++ b/docs/generated/sql/bnf/create_as_constraint_def.bnf @@ -1,2 +1,2 @@ create_as_constraint_def ::= - 'PRIMARY' 'KEY' '(' create_as_params ')' + 'PRIMARY' 'KEY' '(' create_as_params ')' opt_with_storage_parameter_list diff --git a/docs/generated/sql/bnf/create_index_stmt.bnf b/docs/generated/sql/bnf/create_index_stmt.bnf index a985126efae3..c8f3d2b8299f 100644 --- a/docs/generated/sql/bnf/create_index_stmt.bnf +++ b/docs/generated/sql/bnf/create_index_stmt.bnf @@ -1,5 +1,5 @@ create_index_stmt ::= - 'CREATE' ( 'UNIQUE' | ) 'INDEX' ( 'CONCURRENTLY' | ) opt_index_name 'ON' table_name ( 'USING' name | ) '(' ( ( ( func_expr_windowless index_elem_options | '(' a_expr ')' index_elem_options | name index_elem_options ) ) ( ( ',' ( func_expr_windowless index_elem_options | '(' a_expr ')' index_elem_options | name index_elem_options ) ) )* ) ')' ( 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets | 'USING' 'HASH' | ) ( ( 'COVERING' | 'STORING' | 'INCLUDE' ) '(' name_list ')' | ) opt_partition_by_index ( 'WITH' '(' ( ( storage_parameter ) ( ( ',' storage_parameter ) )* ) ')' ) opt_where_clause - | 'CREATE' ( 'UNIQUE' | ) 'INDEX' ( 'CONCURRENTLY' | ) 'IF' 'NOT' 'EXISTS' index_name 'ON' table_name ( 'USING' name | ) '(' ( ( ( func_expr_windowless index_elem_options | '(' a_expr ')' index_elem_options | name index_elem_options ) ) ( ( ',' ( func_expr_windowless index_elem_options | '(' a_expr ')' index_elem_options | name index_elem_options ) ) )* ) ')' ( 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets | 'USING' 'HASH' | ) ( ( 'COVERING' | 'STORING' | 'INCLUDE' ) '(' name_list ')' | ) opt_partition_by_index ( 'WITH' '(' ( ( storage_parameter ) ( ( ',' storage_parameter ) )* ) ')' ) opt_where_clause + 'CREATE' ( 'UNIQUE' | ) 'INDEX' ( 'CONCURRENTLY' | ) opt_index_name 'ON' table_name ( 'USING' name | ) '(' ( ( ( func_expr_windowless index_elem_options | '(' a_expr ')' index_elem_options | name index_elem_options ) ) ( ( ',' ( func_expr_windowless index_elem_options | '(' a_expr ')' index_elem_options | name index_elem_options ) ) )* ) ')' ( 'USING' 'HASH' opt_hash_sharded_bucket_count | ) ( ( 'COVERING' | 'STORING' | 'INCLUDE' ) '(' name_list ')' | ) opt_partition_by_index ( 'WITH' '(' ( ( storage_parameter ) ( ( ',' storage_parameter ) )* ) ')' ) opt_where_clause + | 'CREATE' ( 'UNIQUE' | ) 'INDEX' ( 'CONCURRENTLY' | ) 'IF' 'NOT' 'EXISTS' index_name 'ON' table_name ( 'USING' name | ) '(' ( ( ( func_expr_windowless index_elem_options | '(' a_expr ')' index_elem_options | name index_elem_options ) ) ( ( ',' ( func_expr_windowless index_elem_options | '(' a_expr ')' index_elem_options | name index_elem_options ) ) )* ) ')' ( 'USING' 'HASH' opt_hash_sharded_bucket_count | ) ( ( 'COVERING' | 'STORING' | 'INCLUDE' ) '(' name_list ')' | ) opt_partition_by_index ( 'WITH' '(' ( ( storage_parameter ) ( ( ',' storage_parameter ) )* ) ')' ) opt_where_clause diff --git a/docs/generated/sql/bnf/index_def.bnf b/docs/generated/sql/bnf/index_def.bnf index a3e58ff51795..1297f5ae0eb0 100644 --- a/docs/generated/sql/bnf/index_def.bnf +++ b/docs/generated/sql/bnf/index_def.bnf @@ -1,24 +1,16 @@ index_def ::= - 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets 'COVERING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets 'STORING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'COVERING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'STORING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause + 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_hash_sharded_bucket_count 'COVERING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause + | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_hash_sharded_bucket_count 'STORING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause + | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_hash_sharded_bucket_count 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause + | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_partition_by_index opt_with_storage_parameter_list opt_where_clause | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'COVERING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'STORING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause | 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets 'COVERING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets 'STORING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'COVERING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'STORING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause - | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause + | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_hash_sharded_bucket_count 'COVERING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause + | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_hash_sharded_bucket_count 'STORING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause + | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_hash_sharded_bucket_count 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause + | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_partition_by_index opt_with_storage_parameter_list opt_where_clause | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'COVERING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'STORING' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause | 'UNIQUE' 'INDEX' opt_index_name '(' index_elem ( ( ',' index_elem ) )* ')' 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_with_storage_parameter_list opt_where_clause diff --git a/docs/generated/sql/bnf/stmt_block.bnf b/docs/generated/sql/bnf/stmt_block.bnf index 62adf4a68a13..e3b87be598bc 100644 --- a/docs/generated/sql/bnf/stmt_block.bnf +++ b/docs/generated/sql/bnf/stmt_block.bnf @@ -1979,8 +1979,7 @@ index_params ::= ( index_elem ) ( ( ',' index_elem ) )* opt_hash_sharded ::= - 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' a_expr - | 'USING' 'HASH' + 'USING' 'HASH' opt_hash_sharded_bucket_count | opt_storing ::= @@ -2483,6 +2482,10 @@ index_elem ::= | '(' a_expr ')' index_elem_options | name index_elem_options +opt_hash_sharded_bucket_count ::= + 'WITH' 'BUCKET_COUNT' '=' a_expr + | + storing ::= 'COVERING' | 'STORING' @@ -2683,7 +2686,7 @@ alter_table_cmd ::= | 'ALTER' opt_column column_name opt_set_data 'TYPE' typename opt_collate opt_alter_column_using | 'ADD' table_constraint opt_validate_behavior | 'ADD' 'CONSTRAINT' 'IF' 'NOT' 'EXISTS' constraint_name constraint_elem opt_validate_behavior - | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded + | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list | 'VALIDATE' 'CONSTRAINT' constraint_name | 'DROP' 'CONSTRAINT' 'IF' 'EXISTS' constraint_name opt_drop_behavior | 'DROP' 'CONSTRAINT' constraint_name opt_drop_behavior @@ -2977,7 +2980,7 @@ opt_validate_behavior ::= constraint_elem ::= 'CHECK' '(' a_expr ')' | 'UNIQUE' '(' index_params ')' opt_storing opt_partition_by_index opt_where_clause - | 'PRIMARY' 'KEY' '(' index_params ')' opt_hash_sharded + | 'PRIMARY' 'KEY' '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list | 'FOREIGN' 'KEY' '(' name_list ')' 'REFERENCES' table_name opt_column_list key_match reference_actions audit_mode ::= @@ -3094,7 +3097,7 @@ opt_family_name ::= opt_name create_as_constraint_elem ::= - 'PRIMARY' 'KEY' '(' create_as_params ')' + 'PRIMARY' 'KEY' '(' create_as_params ')' opt_with_storage_parameter_list group_by_item ::= a_expr @@ -3237,7 +3240,7 @@ like_table_option ::= | 'ALL' create_as_col_qualification_elem ::= - 'PRIMARY' 'KEY' + 'PRIMARY' 'KEY' opt_with_storage_parameter_list family_name ::= name @@ -3316,9 +3319,8 @@ col_qualification_elem ::= | 'NULL' | 'NOT' 'VISIBLE' | 'UNIQUE' - | 'PRIMARY' 'KEY' - | 'PRIMARY' 'KEY' 'USING' 'HASH' - | 'PRIMARY' 'KEY' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' a_expr + | 'PRIMARY' 'KEY' opt_with_storage_parameter_list + | 'PRIMARY' 'KEY' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_with_storage_parameter_list | 'CHECK' '(' a_expr ')' | 'DEFAULT' b_expr | 'ON' 'UPDATE' b_expr diff --git a/docs/generated/sql/bnf/table_constraint.bnf b/docs/generated/sql/bnf/table_constraint.bnf index f0c49214caf6..5174d7c68e9d 100644 --- a/docs/generated/sql/bnf/table_constraint.bnf +++ b/docs/generated/sql/bnf/table_constraint.bnf @@ -4,16 +4,14 @@ table_constraint ::= | 'CONSTRAINT' constraint_name 'UNIQUE' '(' index_params ')' 'STORING' '(' name_list ')' opt_partition_by_index opt_where_clause | 'CONSTRAINT' constraint_name 'UNIQUE' '(' index_params ')' 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_where_clause | 'CONSTRAINT' constraint_name 'UNIQUE' '(' index_params ')' opt_partition_by_index opt_where_clause - | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' '(' index_params ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets - | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' '(' index_params ')' 'USING' 'HASH' - | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' '(' index_params ')' + | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' '(' index_params ')' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_with_storage_parameter_list + | 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' '(' index_params ')' opt_with_storage_parameter_list | 'CONSTRAINT' constraint_name 'FOREIGN' 'KEY' '(' name_list ')' 'REFERENCES' table_name opt_column_list key_match reference_actions | 'CHECK' '(' a_expr ')' | 'UNIQUE' '(' index_params ')' 'COVERING' '(' name_list ')' opt_partition_by_index opt_where_clause | 'UNIQUE' '(' index_params ')' 'STORING' '(' name_list ')' opt_partition_by_index opt_where_clause | 'UNIQUE' '(' index_params ')' 'INCLUDE' '(' name_list ')' opt_partition_by_index opt_where_clause | 'UNIQUE' '(' index_params ')' opt_partition_by_index opt_where_clause - | 'PRIMARY' 'KEY' '(' index_params ')' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets - | 'PRIMARY' 'KEY' '(' index_params ')' 'USING' 'HASH' - | 'PRIMARY' 'KEY' '(' index_params ')' + | 'PRIMARY' 'KEY' '(' index_params ')' 'USING' 'HASH' opt_hash_sharded_bucket_count opt_with_storage_parameter_list + | 'PRIMARY' 'KEY' '(' index_params ')' opt_with_storage_parameter_list | 'FOREIGN' 'KEY' '(' name_list ')' 'REFERENCES' table_name opt_column_list key_match reference_actions diff --git a/pkg/sql/alter_primary_key.go b/pkg/sql/alter_primary_key.go index c9390ce4a88f..5a0e99b1282c 100644 --- a/pkg/sql/alter_primary_key.go +++ b/pkg/sql/alter_primary_key.go @@ -19,6 +19,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/catalog/descbuilder" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/tabledesc" + "github.com/cockroachdb/cockroach/pkg/sql/paramparse" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgnotice" @@ -51,6 +52,10 @@ func (p *planner) AlterPrimaryKey( alterPKNode tree.AlterTableAlterPrimaryKey, alterPrimaryKeyLocalitySwap *alterPrimaryKeyLocalitySwap, ) error { + if err := paramparse.ValidateUniqueConstraintParams(alterPKNode.StorageParams, true /* isPK */); err != nil { + return err + } + if alterPrimaryKeyLocalitySwap != nil { if err := p.checkNoRegionChangeUnderway( ctx, diff --git a/pkg/sql/create_table.go b/pkg/sql/create_table.go index d2b635f50b50..e22fc8625c4a 100644 --- a/pkg/sql/create_table.go +++ b/pkg/sql/create_table.go @@ -1143,6 +1143,10 @@ func newTableDescIfAs( privileges *descpb.PrivilegeDescriptor, evalContext *tree.EvalContext, ) (desc *tabledesc.Mutable, err error) { + if err := validateUniqueConstraintParamsForCreateTableAs(p); err != nil { + return nil, err + } + colResIndex := 0 // TableDefs for a CREATE TABLE ... AS AST node comprise of a ColumnTableDef // for each column, and a ConstraintTableDef for any constraints on those @@ -2233,6 +2237,10 @@ func newTableDesc( privileges *descpb.PrivilegeDescriptor, affected map[descpb.ID]*tabledesc.Mutable, ) (ret *tabledesc.Mutable, err error) { + if err := validateUniqueConstraintParamsForCreateTable(n); err != nil { + return nil, err + } + newDefs, err := replaceLikeTableOpts(n, params) if err != nil { return nil, err @@ -2677,3 +2685,41 @@ func setSequenceOwner( return nil } + +// validateUniqueConstraintParamsForCreateTable validate storage params of +// unique constraints passed in through `CREATE TABLE` statement. +func validateUniqueConstraintParamsForCreateTable(n *tree.CreateTable) error { + for _, def := range n.Defs { + switch d := def.(type) { + case *tree.ColumnTableDef: + if err := paramparse.ValidateUniqueConstraintParams(d.PrimaryKey.StorageParams, true /* isPK */); err != nil { + return err + } + case *tree.UniqueConstraintTableDef: + if err := paramparse.ValidateUniqueConstraintParams(d.IndexTableDef.StorageParams, d.PrimaryKey); err != nil { + return err + } + } + } + return nil +} + +// validateUniqueConstraintParamsForCreateTableAs validate storage params of +// unique constraints passed in through `CREATE TABLE...AS...` statement. +func validateUniqueConstraintParamsForCreateTableAs(n *tree.CreateTable) error { + // TODO (issue 75896): enable storage parameters of primary key. + const errMsg = `storage parameters are not supported on primary key for CREATE TABLE...AS... statement` + for _, def := range n.Defs { + switch d := def.(type) { + case *tree.ColumnTableDef: + if len(d.PrimaryKey.StorageParams) > 0 { + return pgerror.New(pgcode.FeatureNotSupported, errMsg) + } + case *tree.UniqueConstraintTableDef: + if d.PrimaryKey && len(d.StorageParams) > 0 { + return pgerror.New(pgcode.FeatureNotSupported, errMsg) + } + } + } + return nil +} diff --git a/pkg/sql/logictest/testdata/logic_test/alter_primary_key b/pkg/sql/logictest/testdata/logic_test/alter_primary_key index ef2bfb7b9445..803b2c6bb275 100644 --- a/pkg/sql/logictest/testdata/logic_test/alter_primary_key +++ b/pkg/sql/logictest/testdata/logic_test/alter_primary_key @@ -1363,3 +1363,17 @@ SELECT * FROM t@t_b_k_key a b k 1 2 3 3 4 7 + +subtest test_storage_params_validation + +statement ok +CREATE TABLE t_bad_param ( + a INT PRIMARY KEY, + b INT NOT NULL +); + +statement error pq: invalid storage param "s2_max_level" on primary key +ALTER TABLE t_bad_param ALTER PRIMARY KEY USING COLUMNS (b) WITH (s2_max_level=20); + +statement error pq: invalid storage param "s2_max_level" on primary key +ALTER TABLE t_bad_param ALTER PRIMARY KEY USING COLUMNS (b) USING HASH WITH (s2_max_level=20); diff --git a/pkg/sql/logictest/testdata/logic_test/create_table b/pkg/sql/logictest/testdata/logic_test/create_table index 63e406aff144..f3abbaf4ac5b 100644 --- a/pkg/sql/logictest/testdata/logic_test/create_table +++ b/pkg/sql/logictest/testdata/logic_test/create_table @@ -718,3 +718,69 @@ table_id name state refobjid statement ok DROP TABLE test_serial; + +subtest test_storage_params_validation + +statement error pq: invalid storage param "s2_max_level" on primary key +CREATE TABLE t_bad_param ( + a INT PRIMARY KEY WITH (s2_max_level=20) +); + +statement error pq: invalid storage param "s2_max_level" on primary key +CREATE TABLE t_bad_param ( + a INT PRIMARY KEY USING HASH WITH (s2_max_level=20) +); + +statement error pq: invalid storage param "s2_max_level" on primary key +CREATE TABLE t_bad_param ( + a INT NOT NULL, + PRIMARY KEY (a) WITH (s2_max_level=20) +); + +statement error pq: invalid storage param "s2_max_level" on primary key +CREATE TABLE t_bad_param ( + a INT NOT NULL, + PRIMARY KEY (a) USING HASH WITH (s2_max_level=20) +); + +statement error pq: invalid storage param "s2_max_level" on primary key +CREATE TABLE t_bad_param ( + a INT NOT NULL, + CONSTRAINT t_bad_param_pkey PRIMARY KEY (a) WITH (s2_max_level=20) +); + +statement error pq: invalid storage param "s2_max_level" on primary key +CREATE TABLE t_bad_param ( + a INT NOT NULL, + CONSTRAINT t_bad_param_pkey PRIMARY KEY (a) USING HASH WITH (s2_max_level=20) +); + +statement error pq: invalid storage param "s2_max_level" on unique index +CREATE TABLE t_bad_param ( + a INT, + UNIQUE INDEX (a) WITH (s2_max_level=20) +); + +statement error pq: invalid storage param "s2_max_level" on unique index +CREATE TABLE t_bad_param ( + a INT, + UNIQUE INDEX (a) USING HASH WITH (s2_max_level=20) +); + +statement ok +CREATE TABLE t_source ( + a INT PRIMARY KEY +); + +statement error pq: storage parameters are not supported on primary key for CREATE TABLE...AS... statement +CREATE TABLE t_bad_param ( + a PRIMARY KEY WITH (s2_max_level=20) +) AS SELECT * FROM t_source; + +statement error pq: storage parameters are not supported on primary key for CREATE TABLE...AS... statement +CREATE TABLE t_bad_param ( + a, + PRIMARY KEY (a) WITH (s2_max_level=20) +) AS SELECT * FROM t_source; + + diff --git a/pkg/sql/paramparse/BUILD.bazel b/pkg/sql/paramparse/BUILD.bazel index 909a600632bb..444c4e17a5d4 100644 --- a/pkg/sql/paramparse/BUILD.bazel +++ b/pkg/sql/paramparse/BUILD.bazel @@ -5,6 +5,7 @@ go_library( srcs = [ "paramobserver.go", "paramparse.go", + "validation.go", ], importpath = "github.com/cockroachdb/cockroach/pkg/sql/paramparse", visibility = ["//visibility:public"], diff --git a/pkg/sql/paramparse/validation.go b/pkg/sql/paramparse/validation.go new file mode 100644 index 000000000000..5f9fff494d20 --- /dev/null +++ b/pkg/sql/paramparse/validation.go @@ -0,0 +1,31 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package paramparse + +import ( + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" + "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" +) + +// ValidateUniqueConstraintParams checks if there is any storage parameters +// invalid as a param for Unique Constraint. +func ValidateUniqueConstraintParams(params tree.StorageParams, isPK bool) error { + // TODO (issue 75243): add `bucket_count` as a valid param. Current dummy + // implementation is just for a proof of concept and make golint happy. + if len(params) == 0 { + return nil + } + if isPK { + return pgerror.Newf(pgcode.InvalidParameterValue, "invalid storage param %q on primary key", params[0].Key) + } + return pgerror.Newf(pgcode.InvalidParameterValue, "invalid storage param %q on unique index", params[0].Key) +} diff --git a/pkg/sql/parser/sql.y b/pkg/sql/parser/sql.y index 7e1ad65960d9..7602461ab836 100644 --- a/pkg/sql/parser/sql.y +++ b/pkg/sql/parser/sql.y @@ -1271,6 +1271,7 @@ func (u *sqlSymUnion) setVar() *tree.SetVar { %type begin_transaction %type transaction_mode_list transaction_mode +%type opt_hash_sharded_bucket_count %type <*tree.ShardedIndexDef> opt_hash_sharded %type opt_storing %type <*tree.ColumnTableDef> column_def @@ -2323,11 +2324,12 @@ alter_table_cmd: } // ALTER TABLE VALIDATE CONSTRAINT ... // ALTER TABLE ALTER PRIMARY KEY USING INDEX -| ALTER PRIMARY KEY USING COLUMNS '(' index_params ')' opt_hash_sharded +| ALTER PRIMARY KEY USING COLUMNS '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list { $$.val = &tree.AlterTableAlterPrimaryKey{ Columns: $7.idxElems(), Sharded: $9.shardedIndexDef(), + StorageParams: $10.storageParams(), } } | VALIDATE CONSTRAINT constraint_name @@ -6988,22 +6990,18 @@ col_qualification_elem: WithoutIndex: $2.bool(), } } -| PRIMARY KEY +| PRIMARY KEY opt_with_storage_parameter_list { - $$.val = tree.PrimaryKeyConstraint{} - } -| PRIMARY KEY USING HASH -{ - $$.val = tree.ShardedPrimaryKeyConstraint{ - Sharded: true, - ShardBuckets: tree.DefaultVal{}, + $$.val = tree.PrimaryKeyConstraint{ + StorageParams: $3.storageParams(), + } } -} -| PRIMARY KEY USING HASH WITH_LA BUCKET_COUNT '=' a_expr +| PRIMARY KEY USING HASH opt_hash_sharded_bucket_count opt_with_storage_parameter_list { $$.val = tree.ShardedPrimaryKeyConstraint{ Sharded: true, - ShardBuckets: $8.expr(), + ShardBuckets: $5.expr(), + StorageParams: $6.storageParams(), } } | CHECK '(' a_expr ')' @@ -7165,12 +7163,13 @@ constraint_elem: }, } } -| PRIMARY KEY '(' index_params ')' opt_hash_sharded +| PRIMARY KEY '(' index_params ')' opt_hash_sharded opt_with_storage_parameter_list { $$.val = &tree.UniqueConstraintTableDef{ IndexTableDef: tree.IndexTableDef{ Columns: $4.idxElems(), Sharded: $6.shardedIndexDef(), + StorageParams: $7.storageParams(), }, PrimaryKey: true, } @@ -7242,11 +7241,12 @@ create_as_constraint_def: } create_as_constraint_elem: - PRIMARY KEY '(' create_as_params ')' + PRIMARY KEY '(' create_as_params ')' opt_with_storage_parameter_list { $$.val = &tree.UniqueConstraintTableDef{ IndexTableDef: tree.IndexTableDef{ Columns: $4.idxElems(), + StorageParams: $6.storageParams(), }, PrimaryKey: true, } @@ -7289,9 +7289,11 @@ create_as_col_qualification: } create_as_col_qualification_elem: - PRIMARY KEY + PRIMARY KEY opt_with_storage_parameter_list { - $$.val = tree.PrimaryKeyConstraint{} + $$.val = tree.PrimaryKeyConstraint{ + StorageParams: $3.storageParams(), + } } opt_deferrable: @@ -7327,17 +7329,10 @@ opt_storing: } opt_hash_sharded: - USING HASH WITH_LA BUCKET_COUNT '=' a_expr + USING HASH opt_hash_sharded_bucket_count { $$.val = &tree.ShardedIndexDef{ - ShardBuckets: $6.expr(), - } - } - | - USING HASH - { - $$.val = &tree.ShardedIndexDef{ - ShardBuckets: tree.DefaultVal{}, + ShardBuckets: $3.expr(), } } | /* EMPTY */ @@ -7345,6 +7340,16 @@ opt_hash_sharded: $$.val = (*tree.ShardedIndexDef)(nil) } +opt_hash_sharded_bucket_count: + WITH_LA BUCKET_COUNT '=' a_expr + { + $$.val = $4.expr() + } + | + { + $$.val = tree.DefaultVal{} + } + opt_column_list: '(' name_list ')' { diff --git a/pkg/sql/sem/tree/alter_table.go b/pkg/sql/sem/tree/alter_table.go index c614d0185c48..705bfb86e45a 100644 --- a/pkg/sql/sem/tree/alter_table.go +++ b/pkg/sql/sem/tree/alter_table.go @@ -259,9 +259,10 @@ func (node *AlterTableAlterColumnType) GetColumn() Name { // AlterTableAlterPrimaryKey represents an ALTER TABLE ALTER PRIMARY KEY command. type AlterTableAlterPrimaryKey struct { - Columns IndexElemList - Sharded *ShardedIndexDef - Name Name + Columns IndexElemList + Sharded *ShardedIndexDef + Name Name + StorageParams StorageParams } // TelemetryCounter implements the AlterTableCmd interface. diff --git a/pkg/sql/sem/tree/create.go b/pkg/sql/sem/tree/create.go index b8026fffcb80..f33331dbbed8 100644 --- a/pkg/sql/sem/tree/create.go +++ b/pkg/sql/sem/tree/create.go @@ -421,9 +421,10 @@ type ColumnTableDef struct { ConstraintName Name } PrimaryKey struct { - IsPrimaryKey bool - Sharded bool - ShardBuckets Expr + IsPrimaryKey bool + Sharded bool + ShardBuckets Expr + StorageParams StorageParams } Unique struct { IsUnique bool @@ -600,12 +601,14 @@ func NewColumnTableDef( d.Nullable.ConstraintName = c.Name case PrimaryKeyConstraint: d.PrimaryKey.IsPrimaryKey = true + d.PrimaryKey.StorageParams = c.Qualification.(PrimaryKeyConstraint).StorageParams d.Unique.ConstraintName = c.Name case ShardedPrimaryKeyConstraint: d.PrimaryKey.IsPrimaryKey = true constraint := c.Qualification.(ShardedPrimaryKeyConstraint) d.PrimaryKey.Sharded = true d.PrimaryKey.ShardBuckets = constraint.ShardBuckets + d.PrimaryKey.StorageParams = constraint.StorageParams d.Unique.ConstraintName = c.Name case UniqueConstraint: d.Unique.IsUnique = true @@ -884,13 +887,16 @@ type NullConstraint struct{} type HiddenConstraint struct{} // PrimaryKeyConstraint represents PRIMARY KEY on a column. -type PrimaryKeyConstraint struct{} +type PrimaryKeyConstraint struct { + StorageParams StorageParams +} // ShardedPrimaryKeyConstraint represents `PRIMARY KEY .. USING HASH..` // on a column. type ShardedPrimaryKeyConstraint struct { - Sharded bool - ShardBuckets Expr + Sharded bool + ShardBuckets Expr + StorageParams StorageParams } // UniqueConstraint represents UNIQUE on a column.