diff --git a/docs/generated/sql/bnf/create_database_stmt.bnf b/docs/generated/sql/bnf/create_database_stmt.bnf index 2b9ca3925b3b..4f30a35b39e6 100644 --- a/docs/generated/sql/bnf/create_database_stmt.bnf +++ b/docs/generated/sql/bnf/create_database_stmt.bnf @@ -1,19 +1,19 @@ create_database_stmt ::= - 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause opt_regions_list opt_survive_clause + 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' '=' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause 'ENCODING' non_reserved_word_or_sconst opt_lc_collate_clause opt_lc_ctype_clause opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' '=' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause 'CONNECTION' 'LIMIT' signed_iconst opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause opt_lc_collate_clause opt_lc_ctype_clause opt_primary_region_clause opt_regions_list opt_survival_goal_clause diff --git a/docs/generated/sql/bnf/stmt_block.bnf b/docs/generated/sql/bnf/stmt_block.bnf index 6e54737a2b46..3f91b5b34697 100644 --- a/docs/generated/sql/bnf/stmt_block.bnf +++ b/docs/generated/sql/bnf/stmt_block.bnf @@ -1241,7 +1241,8 @@ alter_database_stmt ::= | alter_database_to_schema_stmt | alter_database_add_region_stmt | alter_database_drop_region_stmt - | alter_database_survive_stmt + | alter_database_survival_goal_stmt + | alter_database_primary_region_stmt alter_range_stmt ::= alter_zone_range_stmt @@ -1286,8 +1287,8 @@ create_changefeed_stmt ::= 'CREATE' 'CHANGEFEED' 'FOR' changefeed_targets opt_changefeed_sink opt_with_options create_database_stmt ::= - 'CREATE' 'DATABASE' database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause opt_connection_limit opt_regions_list opt_survive_clause - | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause opt_connection_limit opt_regions_list opt_survive_clause + 'CREATE' 'DATABASE' database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause opt_connection_limit opt_primary_region_clause opt_regions_list opt_survival_goal_clause + | 'CREATE' 'DATABASE' 'IF' 'NOT' 'EXISTS' database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause opt_connection_limit opt_primary_region_clause opt_regions_list opt_survival_goal_clause create_index_stmt ::= 'CREATE' opt_unique 'INDEX' opt_concurrently opt_index_name 'ON' table_name opt_index_access_method '(' index_params ')' opt_hash_sharded opt_storing opt_interleave opt_partition_by opt_with_storage_parameter_list opt_where_clause @@ -1673,8 +1674,11 @@ alter_database_add_region_stmt ::= alter_database_drop_region_stmt ::= 'ALTER' 'DATABASE' database_name 'DROP' 'REGION' region_name -alter_database_survive_stmt ::= - 'ALTER' 'DATABASE' database_name survive_clause +alter_database_survival_goal_stmt ::= + 'ALTER' 'DATABASE' database_name survival_goal_clause + +alter_database_primary_region_stmt ::= + 'ALTER' 'DATABASE' database_name primary_region_clause alter_zone_range_stmt ::= 'ALTER' 'RANGE' zone_name set_zone_config @@ -1763,12 +1767,16 @@ opt_connection_limit ::= 'CONNECTION' 'LIMIT' opt_equal signed_iconst | +opt_primary_region_clause ::= + primary_region_clause + | + opt_regions_list ::= region_or_regions opt_equal region_name_list | -opt_survive_clause ::= - survive_clause +opt_survival_goal_clause ::= + survival_goal_clause | opt_unique ::= @@ -2140,10 +2148,13 @@ sequence_option_list ::= region_name ::= name -survive_clause ::= +survival_goal_clause ::= 'SURVIVE' opt_equal 'REGION' 'FAILURE' | 'SURVIVE' opt_equal 'ZONE' 'FAILURE' +primary_region_clause ::= + 'PRIMARY' 'REGION' opt_equal region_name + role_option ::= 'CREATEROLE' | 'NOCREATEROLE' diff --git a/pkg/sql/alter_database.go b/pkg/sql/alter_database.go index 18d5f6571bed..ab144775514d 100644 --- a/pkg/sql/alter_database.go +++ b/pkg/sql/alter_database.go @@ -112,6 +112,13 @@ func (p *planner) AlterDatabaseDropRegion( return nil, unimplemented.New("alter database drop region", "implementation pending") } +// AlterDatabasePrimaryRegion transforms a tree.AlterDatabasePrimaryRegion into a plan node. +func (p *planner) AlterDatabasePrimaryRegion( + ctx context.Context, n *tree.AlterDatabasePrimaryRegion, +) (planNode, error) { + return nil, unimplemented.New("alter database primary region", "implementation pending") +} + // AlterDatabaseSurvivalGoal transforms a tree.AlterDatabaseSurvivalGoal into a plan node. func (p *planner) AlterDatabaseSurvivalGoal( ctx context.Context, n *tree.AlterDatabaseSurvivalGoal, diff --git a/pkg/sql/create_database.go b/pkg/sql/create_database.go index a8df8edeeefa..31ad7dbfbebf 100644 --- a/pkg/sql/create_database.go +++ b/pkg/sql/create_database.go @@ -68,6 +68,10 @@ func (p *planner) CreateDatabase(ctx context.Context, n *tree.CreateDatabase) (p } } + if n.PrimaryRegion != "" { + return nil, unimplemented.New("create database primary region", "implementation pending") + } + if n.ConnectionLimit != -1 { return nil, unimplemented.NewWithIssueDetailf( 54241, diff --git a/pkg/sql/logictest/testdata/logic_test/multiregion b/pkg/sql/logictest/testdata/logic_test/multiregion index aa0aac63d7bc..17573e7db18a 100644 --- a/pkg/sql/logictest/testdata/logic_test/multiregion +++ b/pkg/sql/logictest/testdata/logic_test/multiregion @@ -20,6 +20,9 @@ CREATE DATABASE invalid_region_db REGION "region_no_exists" statement error region "test1" defined multiple times CREATE DATABASE duplicate_region_name_db REGIONS "test1", "test1" +statement error implementation pending +CREATE DATABASE primary_region_db PRIMARY REGION "test" + statement error implementation pending CREATE DATABASE new_db SURVIVE ZONE FAILURE @@ -34,3 +37,6 @@ ALTER DATABASE new_db DROP REGION "us-west-1" statement error implementation pending ALTER TABLE a SET REGIONAL AFFINITY TO NONE + +statement error implementation pending +ALTER DATABASE primary_region_db PRIMARY REGION "test" diff --git a/pkg/sql/opaque.go b/pkg/sql/opaque.go index c7559d17a5c9..800a94fac56a 100644 --- a/pkg/sql/opaque.go +++ b/pkg/sql/opaque.go @@ -55,6 +55,8 @@ func buildOpaque( plan, err = p.AlterDatabaseAddRegion(ctx, n) case *tree.AlterDatabaseDropRegion: plan, err = p.AlterDatabaseDropRegion(ctx, n) + case *tree.AlterDatabasePrimaryRegion: + plan, err = p.AlterDatabasePrimaryRegion(ctx, n) case *tree.AlterDatabaseSurvivalGoal: plan, err = p.AlterDatabaseSurvivalGoal(ctx, n) case *tree.AlterIndex: @@ -198,6 +200,7 @@ func init() { &tree.AlterDatabaseAddRegion{}, &tree.AlterDatabaseDropRegion{}, &tree.AlterDatabaseOwner{}, + &tree.AlterDatabasePrimaryRegion{}, &tree.AlterDatabaseSurvivalGoal{}, &tree.AlterIndex{}, &tree.AlterSchema{}, diff --git a/pkg/sql/parser/parse_test.go b/pkg/sql/parser/parse_test.go index c45a52242f84..a5d25eb33066 100644 --- a/pkg/sql/parser/parse_test.go +++ b/pkg/sql/parser/parse_test.go @@ -74,6 +74,7 @@ func TestParse(t *testing.T) { {`CREATE DATABASE a REGIONS = "us-west-1", "us-west-2"`}, {`CREATE DATABASE a SURVIVE REGION FAILURE`}, {`CREATE DATABASE a SURVIVE ZONE FAILURE`}, + {`CREATE DATABASE a PRIMARY REGION "us-west-1"`}, {`CREATE DATABASE IF NOT EXISTS a`}, {`CREATE DATABASE IF NOT EXISTS a TEMPLATE = 'template0'`}, {`CREATE DATABASE IF NOT EXISTS a TEMPLATE = 'invalid'`}, @@ -87,6 +88,7 @@ func TestParse(t *testing.T) { {`CREATE DATABASE IF NOT EXISTS a REGIONS = "us-west-1", "us-west-2"`}, {`CREATE DATABASE IF NOT EXISTS a SURVIVE REGION FAILURE`}, {`CREATE DATABASE IF NOT EXISTS a SURVIVE ZONE FAILURE`}, + {`CREATE DATABASE IF NOT EXISTS a PRIMARY REGION "us-west-1"`}, {`CREATE SCHEMA IF NOT EXISTS foo`}, {`CREATE SCHEMA foo`}, @@ -1363,6 +1365,7 @@ func TestParse(t *testing.T) { {`ALTER DATABASE a ADD REGION "us-west-1"`}, {`ALTER DATABASE a DROP REGION "us-west-1"`}, {`ALTER DATABASE a SURVIVE REGION FAILURE`}, + {`ALTER DATABASE a PRIMARY REGION "us-west-3"`}, {`EXPLAIN ALTER DATABASE a RENAME TO b`}, {`ALTER DATABASE a OWNER TO foo`}, @@ -1783,6 +1786,10 @@ func TestParse2(t *testing.T) { `CREATE DATABASE a REGION "us-west-1"`, `CREATE DATABASE a REGIONS = "us-west-1"`, }, + { + `CREATE DATABASE a PRIMARY REGION = "us-west-1"`, + `CREATE DATABASE a PRIMARY REGION "us-west-1"`, + }, {`CREATE TABLE a (b INT) WITH (fillfactor=100)`, `CREATE TABLE a (b INT8)`}, {`CREATE TABLE a (b INT, UNIQUE INDEX foo (b))`, diff --git a/pkg/sql/parser/sql.y b/pkg/sql/parser/sql.y index 951b3bf359bc..9e1b03ea51a6 100644 --- a/pkg/sql/parser/sql.y +++ b/pkg/sql/parser/sql.y @@ -756,7 +756,8 @@ func (u *sqlSymUnion) objectNamePrefixList() tree.ObjectNamePrefixList { %type alter_database_to_schema_stmt %type alter_database_add_region_stmt %type alter_database_drop_region_stmt -%type alter_database_survive_stmt +%type alter_database_survival_goal_stmt +%type alter_database_primary_region_stmt %type alter_zone_database_stmt %type alter_database_owner @@ -955,9 +956,9 @@ func (u *sqlSymUnion) objectNamePrefixList() tree.ObjectNamePrefixList { %type opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause %type opt_regions_list -%type region_name +%type region_name primary_region_clause opt_primary_region_clause %type region_name_list -%type survive_clause opt_survive_clause +%type survival_goal_clause opt_survival_goal_clause %type regional_affinity %type opt_connection_limit @@ -1458,6 +1459,7 @@ alter_sequence_options_stmt: // ALTER DATABASE CONVERT TO SCHEMA WITH PARENT // ALTER DATABASE ADD REGIONS // ALTER DATABASE DROP REGIONS +// ALTER DATABASE SET PRIMARY REGION // ALTER DATABASE SURVIVE // %SeeAlso: WEBDOCS/alter-database.html alter_database_stmt: @@ -1467,7 +1469,8 @@ alter_database_stmt: | alter_database_to_schema_stmt | alter_database_add_region_stmt | alter_database_drop_region_stmt -| alter_database_survive_stmt +| alter_database_survival_goal_stmt +| alter_database_primary_region_stmt // ALTER DATABASE has its error help token here because the ALTER DATABASE // prefix is spread over multiple non-terminals. | ALTER DATABASE error // SHOW HELP: ALTER DATABASE @@ -1496,8 +1499,8 @@ alter_database_drop_region_stmt: } } -alter_database_survive_stmt: - ALTER DATABASE database_name survive_clause +alter_database_survival_goal_stmt: + ALTER DATABASE database_name survival_goal_clause { $$.val = &tree.AlterDatabaseSurvivalGoal{ Name: tree.Name($3), @@ -1505,6 +1508,15 @@ alter_database_survive_stmt: } } +alter_database_primary_region_stmt: + ALTER DATABASE database_name primary_region_clause + { + $$.val = &tree.AlterDatabasePrimaryRegion{ + Name: tree.Name($3), + PrimaryRegion: tree.Name($4), + } + } + // %Help: ALTER RANGE - change the parameters of a range // %Category: DDL // %Text: @@ -7544,7 +7556,7 @@ transaction_deferrable_mode: // %Text: CREATE DATABASE [IF NOT EXISTS] // %SeeAlso: WEBDOCS/create-database.html create_database_stmt: - CREATE DATABASE database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause opt_connection_limit opt_regions_list opt_survive_clause + CREATE DATABASE database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause opt_connection_limit opt_primary_region_clause opt_regions_list opt_survival_goal_clause { $$.val = &tree.CreateDatabase{ Name: tree.Name($3), @@ -7553,11 +7565,12 @@ create_database_stmt: Collate: $7, CType: $8, ConnectionLimit: $9.int32(), - Regions: $10.nameList(), - SurvivalGoal: $11.survivalGoal(), + PrimaryRegion: tree.Name($10), + Regions: $11.nameList(), + SurvivalGoal: $12.survivalGoal(), } } -| CREATE DATABASE IF NOT EXISTS database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause opt_connection_limit opt_regions_list opt_survive_clause +| CREATE DATABASE IF NOT EXISTS database_name opt_with opt_template_clause opt_encoding_clause opt_lc_collate_clause opt_lc_ctype_clause opt_connection_limit opt_primary_region_clause opt_regions_list opt_survival_goal_clause { $$.val = &tree.CreateDatabase{ IfNotExists: true, @@ -7567,12 +7580,25 @@ create_database_stmt: Collate: $10, CType: $11, ConnectionLimit: $12.int32(), - Regions: $13.nameList(), - SurvivalGoal: $14.survivalGoal(), + PrimaryRegion: tree.Name($13), + Regions: $14.nameList(), + SurvivalGoal: $15.survivalGoal(), } } | CREATE DATABASE error // SHOW HELP: CREATE DATABASE +opt_primary_region_clause: + primary_region_clause +| /* EMPTY */ + { + $$ = "" + } + +primary_region_clause: + PRIMARY REGION opt_equal region_name { + $$ = $4 + } + opt_regions_list: region_or_regions opt_equal region_name_list { @@ -7587,7 +7613,7 @@ region_or_regions: REGION | REGIONS -survive_clause: +survival_goal_clause: SURVIVE opt_equal REGION FAILURE { $$.val = tree.SurvivalGoalRegionFailure @@ -7597,8 +7623,8 @@ survive_clause: $$.val = tree.SurvivalGoalZoneFailure } -opt_survive_clause: - survive_clause +opt_survival_goal_clause: + survival_goal_clause | /* EMPTY */ { $$.val = tree.SurvivalGoalDefault diff --git a/pkg/sql/sem/tree/alter_database.go b/pkg/sql/sem/tree/alter_database.go index 76417e455da8..ec66682ba79a 100644 --- a/pkg/sql/sem/tree/alter_database.go +++ b/pkg/sql/sem/tree/alter_database.go @@ -60,6 +60,22 @@ func (node *AlterDatabaseDropRegion) Format(ctx *FmtCtx) { ctx.FormatNode(&node.Region) } +// AlterDatabasePrimaryRegion represents a ALTER DATABASE PRIMARY REGION ... statement. +type AlterDatabasePrimaryRegion struct { + Name Name + PrimaryRegion Name +} + +var _ Statement = &AlterDatabasePrimaryRegion{} + +// Format implements the NodeFormatter interface. +func (node *AlterDatabasePrimaryRegion) Format(ctx *FmtCtx) { + ctx.WriteString("ALTER DATABASE ") + ctx.FormatNode(&node.Name) + ctx.WriteString(" PRIMARY REGION ") + node.PrimaryRegion.Format(ctx) +} + // AlterDatabaseSurvivalGoal represents a ALTER DATABASE SURVIVE ... statement. type AlterDatabaseSurvivalGoal struct { Name Name diff --git a/pkg/sql/sem/tree/create.go b/pkg/sql/sem/tree/create.go index c8a1248b1be0..0d57ad86b2a3 100644 --- a/pkg/sql/sem/tree/create.go +++ b/pkg/sql/sem/tree/create.go @@ -44,6 +44,7 @@ type CreateDatabase struct { Collate string CType string ConnectionLimit int32 + PrimaryRegion Name Regions NameList SurvivalGoal SurvivalGoal } @@ -75,6 +76,10 @@ func (node *CreateDatabase) Format(ctx *FmtCtx) { ctx.WriteString(" CONNECTION LIMIT = ") ctx.WriteString(strconv.Itoa(int(node.ConnectionLimit))) } + if node.PrimaryRegion != "" { + ctx.WriteString(" PRIMARY REGION ") + node.PrimaryRegion.Format(ctx) + } if node.Regions != nil { ctx.WriteString(" REGIONS = ") node.Regions.Format(ctx) diff --git a/pkg/sql/sem/tree/stmt.go b/pkg/sql/sem/tree/stmt.go index 168f89b7c061..741979216cfd 100644 --- a/pkg/sql/sem/tree/stmt.go +++ b/pkg/sql/sem/tree/stmt.go @@ -194,6 +194,14 @@ func (*AlterDatabaseDropRegion) StatementTag() string { return "ALTER DATABASE D func (*AlterDatabaseDropRegion) hiddenFromShowQueries() {} +// StatementType implements the Statement interface. +func (*AlterDatabasePrimaryRegion) StatementType() StatementType { return DDL } + +// StatementTag returns a short string identifying the type of statement. +func (*AlterDatabasePrimaryRegion) StatementTag() string { return "ALTER DATABASE PRIMARY REGION" } + +func (*AlterDatabasePrimaryRegion) hiddenFromShowQueries() {} + // StatementType implements the Statement interface. func (*AlterDatabaseSurvivalGoal) StatementType() StatementType { return DDL } @@ -1063,6 +1071,7 @@ func (n *AlterDatabaseOwner) String() string { return AsString(n) } func (n *AlterDatabaseAddRegion) String() string { return AsString(n) } func (n *AlterDatabaseDropRegion) String() string { return AsString(n) } func (n *AlterDatabaseSurvivalGoal) String() string { return AsString(n) } +func (n *AlterDatabasePrimaryRegion) String() string { return AsString(n) } func (n *AlterSchema) String() string { return AsString(n) } func (n *AlterTable) String() string { return AsString(n) } func (n *AlterTableCmds) String() string { return AsString(n) }