diff --git a/docs/generated/sql/bnf/alter_role_stmt.bnf b/docs/generated/sql/bnf/alter_role_stmt.bnf index ba96b0d25bdb..7c93d1071ce0 100644 --- a/docs/generated/sql/bnf/alter_role_stmt.bnf +++ b/docs/generated/sql/bnf/alter_role_stmt.bnf @@ -7,3 +7,9 @@ alter_role_stmt ::= | 'ALTER' 'ROLE' 'IF' 'EXISTS' name | 'ALTER' 'USER' 'IF' 'EXISTS' name opt_with role_options | 'ALTER' 'USER' 'IF' 'EXISTS' name + | 'ALTER' 'ROLE' name opt_in_database set_or_reset_clause + | 'ALTER' 'USER' name opt_in_database set_or_reset_clause + | 'ALTER' 'ROLE' 'IF' 'EXISTS' name opt_in_database set_or_reset_clause + | 'ALTER' 'USER' 'IF' 'EXISTS' name opt_in_database set_or_reset_clause + | 'ALTER' 'ROLE_ALL' 'ALL' opt_in_database set_or_reset_clause + | 'ALTER' 'USER_ALL' 'ALL' opt_in_database set_or_reset_clause diff --git a/docs/generated/sql/bnf/set_rest.bnf b/docs/generated/sql/bnf/set_rest.bnf new file mode 100644 index 000000000000..367eec56581d --- /dev/null +++ b/docs/generated/sql/bnf/set_rest.bnf @@ -0,0 +1,2 @@ +set_rest ::= + generic_set diff --git a/docs/generated/sql/bnf/set_rest_more.bnf b/docs/generated/sql/bnf/set_rest_more.bnf index b94f098c3435..847247b5fbce 100644 --- a/docs/generated/sql/bnf/set_rest_more.bnf +++ b/docs/generated/sql/bnf/set_rest_more.bnf @@ -1,2 +1,2 @@ set_rest_more ::= - generic_set + set_rest diff --git a/docs/generated/sql/bnf/set_var.bnf b/docs/generated/sql/bnf/set_var.bnf index 2e9fa722a940..62d8abe1c2e8 100644 --- a/docs/generated/sql/bnf/set_var.bnf +++ b/docs/generated/sql/bnf/set_var.bnf @@ -1,5 +1,5 @@ preparable_set_stmt ::= - 'SET' ( 'SESSION' | ) var_name '=' var_value ( ( ',' var_value ) )* - | 'SET' ( 'SESSION' | ) var_name 'TO' var_value ( ( ',' var_value ) )* + 'SET' 'SESSION' set_rest + | 'SET' set_rest | set_csetting_stmt | use_stmt diff --git a/docs/generated/sql/bnf/stmt_block.bnf b/docs/generated/sql/bnf/stmt_block.bnf index 14923a6f2f9e..09e1a2585382 100644 --- a/docs/generated/sql/bnf/stmt_block.bnf +++ b/docs/generated/sql/bnf/stmt_block.bnf @@ -384,6 +384,10 @@ alter_ddl_stmt ::= alter_role_stmt ::= 'ALTER' role_or_group_or_user string_or_placeholder opt_role_options | 'ALTER' role_or_group_or_user 'IF' 'EXISTS' string_or_placeholder opt_role_options + | 'ALTER' role_or_group_or_user string_or_placeholder opt_in_database set_or_reset_clause + | 'ALTER' role_or_group_or_user 'IF' 'EXISTS' string_or_placeholder opt_in_database set_or_reset_clause + | 'ALTER' 'ROLE_ALL' 'ALL' opt_in_database set_or_reset_clause + | 'ALTER' 'USER_ALL' 'ALL' opt_in_database set_or_reset_clause opt_backup_targets ::= targets @@ -1324,6 +1328,15 @@ opt_role_options ::= opt_with role_options | +opt_in_database ::= + 'IN' 'DATABASE' database_name + | + +set_or_reset_clause ::= + 'SET' set_rest + | 'RESET_ALL' 'ALL' + | 'RESET' session_var + as_of_clause ::= 'AS' 'OF' 'SYSTEM' 'TIME' a_expr @@ -1536,7 +1549,7 @@ opt_for_locking_clause ::= | set_rest_more ::= - generic_set + set_rest to_or_eq ::= '=' @@ -1805,6 +1818,9 @@ abbreviated_revoke_stmt ::= role_options ::= ( role_option ) ( ( role_option ) )* +set_rest ::= + generic_set + backup_options ::= 'ENCRYPTION_PASSPHRASE' '=' string_or_placeholder | 'REVISION_HISTORY' @@ -2088,9 +2104,6 @@ offset_clause ::= 'OFFSET' a_expr | 'OFFSET' select_fetch_first_value row_or_rows -generic_set ::= - var_name to_or_eq var_list - extra_var_value ::= 'ON' | cockroachdb_extra_reserved_keyword @@ -2304,6 +2317,9 @@ role_option ::= | password_clause | valid_until_clause +generic_set ::= + var_name to_or_eq var_list + d_expr ::= 'ICONST' | 'FCONST' @@ -2513,9 +2529,6 @@ all_or_distinct ::= for_locking_item ::= for_locking_strength opt_locked_rels opt_nowait_or_skip -var_list ::= - ( var_value ) ( ( ',' var_value ) )* - opt_ordinality ::= 'WITH' 'ORDINALITY' | @@ -2655,6 +2668,9 @@ valid_until_clause ::= 'VALID' 'UNTIL' string_or_placeholder | 'VALID' 'UNTIL' 'NULL' +var_list ::= + ( var_value ) ( ( ',' var_value ) )* + typed_literal ::= func_name_no_crdb_extra 'SCONST' | const_typename 'SCONST' diff --git a/pkg/cmd/roachtest/tests/ruby_pg_blocklist.go b/pkg/cmd/roachtest/tests/ruby_pg_blocklist.go index e75e18ec5675..f1c42fd1b21b 100644 --- a/pkg/cmd/roachtest/tests/ruby_pg_blocklist.go +++ b/pkg/cmd/roachtest/tests/ruby_pg_blocklist.go @@ -109,11 +109,10 @@ var rubyPGBlockList21_2 = blocklist{ "PG::Connection type casting with default result type map can type cast #copy_data output with explicit decoder": "unknown", "PG::Connection type casting with default result type map should respect a type mapping for result": "unknown", "PG::Connection type casting with default result type map should work with arbitrary number of params in conjunction with type casting": "unknown", + "PG::Result encapsulates PG_DIAG_SEVERITY_NONLOCALIZED error in a PG::Error object": "unknown", "PG::Result encapsulates database object names for integrity constraint violations": "unknown", "PG::Result encapsulates errors in a PG::Error object": "unknown", - "PG::Result encapsulates PG_DIAG_SEVERITY_NONLOCALIZED error in a PG::Error object": "unknown", "PG::Result raises a proper exception for a nonexistant schema": "unknown", - "PG::TypeMapByClass should expire the cache after changes to the coders": "unknown", "PG::TypeMapByColumn forwards get_copy_data conversions to another TypeMapByColumn as #default_type_map": "unknown", "PG::TypeMapByColumn should gracefully handle not initialized state": "unknown", "PG::TypeMapByColumn will deny copy queries with different column count": "unknown", diff --git a/pkg/sql/lexbase/predicates.go b/pkg/sql/lexbase/predicates.go index 3fa9a720e75c..6a633fa55b55 100644 --- a/pkg/sql/lexbase/predicates.go +++ b/pkg/sql/lexbase/predicates.go @@ -55,6 +55,9 @@ func init() { "similar", "time", "generated", + "reset", + "role", + "user", } { reservedOrLookaheadKeywords[s] = struct{}{} } diff --git a/pkg/sql/opt/exec/execbuilder/testdata/explain b/pkg/sql/opt/exec/execbuilder/testdata/explain index d726498d67c0..0d6e2bafb7b9 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/explain +++ b/pkg/sql/opt/exec/execbuilder/testdata/explain @@ -521,7 +521,7 @@ vectorized: true │ group by: username │ └── • sort - │ order: +role + │ order: +"role" │ └── • hash join (left outer) │ equality: (username) = (member) diff --git a/pkg/sql/parser/lexer.go b/pkg/sql/parser/lexer.go index 7386b6abd15f..e5e528232638 100644 --- a/pkg/sql/parser/lexer.go +++ b/pkg/sql/parser/lexer.go @@ -80,7 +80,7 @@ func (l *lexer) Lex(lval *sqlSymType) int { *lval = l.tokens[l.lastPos] switch lval.id { - case NOT, WITH, AS, GENERATED, NULLS: + case NOT, WITH, AS, GENERATED, NULLS, RESET, ROLE, USER: nextID := int32(0) if l.lastPos+1 < len(l.tokens) { nextID = l.tokens[l.lastPos+1].id @@ -114,6 +114,21 @@ func (l *lexer) Lex(lval *sqlSymType) int { case FIRST, LAST: lval.id = NULLS_LA } + case RESET: + switch nextID { + case ALL: + lval.id = RESET_ALL + } + case ROLE: + switch nextID { + case ALL: + lval.id = ROLE_ALL + } + case USER: + switch nextID { + case ALL: + lval.id = USER_ALL + } } } diff --git a/pkg/sql/parser/sql.y b/pkg/sql/parser/sql.y index b50f6b8656f2..52b8c0b825f7 100644 --- a/pkg/sql/parser/sql.y +++ b/pkg/sql/parser/sql.y @@ -720,6 +720,9 @@ func (u *sqlSymUnion) abbreviatedRevoke() tree.AbbreviatedRevoke { func (u *sqlSymUnion) alterDefaultPrivilegesTargetObject() tree.AlterDefaultPrivilegesTargetObject { return u.val.(tree.AlterDefaultPrivilegesTargetObject) } +func (u *sqlSymUnion) setVar() *tree.SetVar { + return u.val.(*tree.SetVar) +} %} // NB: the %token definitions must come before the %type definitions in this @@ -852,8 +855,10 @@ func (u *sqlSymUnion) alterDefaultPrivilegesTargetObject() tree.AlterDefaultPriv // NOT, at least with respect to their left-hand subexpression. WITH_LA is // needed to make the grammar LALR(1). GENERATED_ALWAYS is needed to support // the Postgres syntax for computed columns along with our family related -// extensions (CREATE FAMILY/CREATE FAMILY family_name). -%token NOT_LA NULLS_LA WITH_LA AS_LA GENERATED_ALWAYS +// extensions (CREATE FAMILY/CREATE FAMILY family_name). RESET_ALL is used +// to differentiate `RESET var` from `RESET ALL`. ROLE_ALL and USER_ALL are +// used in ALTER ROLE statements that affect all roles. +%token NOT_LA NULLS_LA WITH_LA AS_LA GENERATED_ALWAYS RESET_ALL ROLE_ALL USER_ALL %union { id int32 @@ -876,6 +881,7 @@ func (u *sqlSymUnion) alterDefaultPrivilegesTargetObject() tree.AlterDefaultPriv %type alter_range_stmt %type alter_partition_stmt %type alter_role_stmt +%type <*tree.SetVar> set_or_reset_clause %type alter_type_stmt %type alter_schema_stmt %type alter_unsupported_stmt @@ -1024,6 +1030,7 @@ func (u *sqlSymUnion) alterDefaultPrivilegesTargetObject() tree.AlterDefaultPriv %type set_exprs_internal %type generic_set %type set_rest_more +%type set_rest %type set_names %type show_stmt @@ -1134,7 +1141,7 @@ func (u *sqlSymUnion) alterDefaultPrivilegesTargetObject() tree.AlterDefaultPriv %type <*tree.UnresolvedName> func_name func_name_no_crdb_extra %type opt_class opt_collate -%type cursor_name database_name index_name opt_index_name column_name insert_column_item statistics_name window_name +%type cursor_name database_name index_name opt_index_name column_name insert_column_item statistics_name window_name opt_in_database %type family_name opt_family_name table_alias_name constraint_name target_name zone_name partition_name collation_name %type db_object_name_component %type <*tree.UnresolvedObjectName> table_name db_name standalone_index_name sequence_name type_name view_name db_object_name simple_db_object_name complex_db_object_name @@ -4574,7 +4581,7 @@ generic_set: } } -set_rest_more: +set_rest: // Generic SET syntaxes: generic_set // Special SET syntax forms in addition to the generic form. @@ -4586,6 +4593,7 @@ set_rest_more: /* SKIP DOC */ $$.val = &tree.SetVar{Name: "timezone", Values: tree.Exprs{$3.expr()}} } +| var_name FROM CURRENT { return unimplemented(sqllex, "set from current") } // "SET SCHEMA 'value' is an alias for SET search_path TO value. Only // one schema can be specified using this syntax." | SCHEMA var_value @@ -4593,6 +4601,10 @@ set_rest_more: /* SKIP DOC */ $$.val = &tree.SetVar{Name: "search_path", Values: tree.Exprs{$2.expr()}} } + +set_rest_more: +// SET syntaxes supported as a clause of other statements: + set_rest | SESSION AUTHORIZATION DEFAULT { /* SKIP DOC */ @@ -4604,7 +4616,6 @@ set_rest_more: } // See comment for the non-terminal for SET NAMES below. | set_names -| var_name FROM CURRENT { return unimplemented(sqllex, "set from current") } | error // SHOW HELP: SET SESSION // SET NAMES is the SQL standard syntax for SET client_encoding. @@ -7179,7 +7190,10 @@ create_role_stmt: // %Help: ALTER ROLE - alter a role // %Category: Priv -// %Text: ALTER ROLE [WITH] +// %Text: +// ALTER ROLE [WITH] +// ALTER ROLE { name | ALL } [ IN DATABASE database_name ] SET var { TO | = } { value | DEFAULT } +// ALTER ROLE { name | ALL } [ IN DATABASE database_name ] RESET { var | ALL } // %SeeAlso: CREATE ROLE, DROP ROLE, SHOW ROLES alter_role_stmt: ALTER role_or_group_or_user string_or_placeholder opt_role_options @@ -7190,8 +7204,48 @@ alter_role_stmt: { $$.val = &tree.AlterRole{Name: $5.expr(), IfExists: true, KVOptions: $6.kvOptions(), IsRole: $2.bool()} } +| ALTER role_or_group_or_user string_or_placeholder opt_in_database set_or_reset_clause + { + $$.val = &tree.AlterRoleSet{RoleName: $3.expr(), DatabaseName: tree.Name($4), IsRole: $2.bool(), SetOrReset: $5.setVar()} + } +| ALTER role_or_group_or_user IF EXISTS string_or_placeholder opt_in_database set_or_reset_clause + { + $$.val = &tree.AlterRoleSet{RoleName: $5.expr(), IfExists: true, DatabaseName: tree.Name($6), IsRole: $2.bool(), SetOrReset: $7.setVar()} + } +| ALTER ROLE_ALL ALL opt_in_database set_or_reset_clause + { + $$.val = &tree.AlterRoleSet{AllRoles: true, DatabaseName: tree.Name($4), IsRole: true, SetOrReset: $5.setVar()} + } +| ALTER USER_ALL ALL opt_in_database set_or_reset_clause + { + $$.val = &tree.AlterRoleSet{AllRoles: true, DatabaseName: tree.Name($4), IsRole: false, SetOrReset: $5.setVar()} + } | ALTER role_or_group_or_user error // SHOW HELP: ALTER ROLE +opt_in_database: + IN DATABASE database_name + { + $$ = $3 + } +| /* EMPTY */ + { + $$ = "" + } + +set_or_reset_clause: + SET set_rest + { + $$.val = $2.setVar() + } +| RESET_ALL ALL + { + $$.val = &tree.SetVar{ResetAll: true} + } +| RESET session_var + { + $$.val = &tree.SetVar{Name: $2, Values:tree.Exprs{tree.DefaultVal{}}} + } + // "CREATE GROUP is now an alias for CREATE ROLE" // https://www.postgresql.org/docs/10/static/sql-creategroup.html role_or_group_or_user: diff --git a/pkg/sql/parser/testdata/alter_user b/pkg/sql/parser/testdata/alter_user index 494949af6f00..82aef30dc40d 100644 --- a/pkg/sql/parser/testdata/alter_user +++ b/pkg/sql/parser/testdata/alter_user @@ -80,3 +80,224 @@ ALTER ROLE ('foo') WITH NOCREATELOGIN -- fully parenthesized ALTER ROLE _ WITH NOCREATELOGIN -- literals removed ALTER ROLE '_' WITH NOCREATELOGIN -- UNEXPECTED REPARSED AST WITHOUT LITERALS ALTER ROLE 'foo' WITH NOCREATELOGIN -- identifiers removed + +parse +ALTER USER foo SET search_path = 'abc' +---- +ALTER USER 'foo' SET search_path = 'abc' -- normalized! +ALTER USER ('foo') SET search_path = ('abc') -- fully parenthesized +ALTER USER _ SET search_path = _ -- literals removed +ALTER USER '_' SET search_path = _ -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER 'foo' SET search_path = 'abc' -- identifiers removed + +parse +ALTER USER foo SET application_name TO DEFAULT +---- +ALTER USER 'foo' SET application_name = DEFAULT -- normalized! +ALTER USER ('foo') SET application_name = (DEFAULT) -- fully parenthesized +ALTER USER _ SET application_name = DEFAULT -- literals removed +ALTER USER '_' SET application_name = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER 'foo' SET application_name = DEFAULT -- identifiers removed + +parse +ALTER USER foo RESET server_encoding +---- +ALTER USER 'foo' SET server_encoding = DEFAULT -- normalized! +ALTER USER ('foo') SET server_encoding = (DEFAULT) -- fully parenthesized +ALTER USER _ SET server_encoding = DEFAULT -- literals removed +ALTER USER '_' SET server_encoding = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER 'foo' SET server_encoding = DEFAULT -- identifiers removed + +parse +ALTER USER foo RESET ALL +---- +ALTER USER 'foo' RESET ALL -- normalized! +ALTER USER ('foo') RESET ALL -- fully parenthesized +ALTER USER _ RESET ALL -- literals removed +ALTER USER '_' RESET ALL -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER 'foo' RESET ALL -- identifiers removed + +parse +ALTER USER foo IN DATABASE d SET search_path = 'abc' +---- +ALTER USER 'foo' IN DATABASE d SET search_path = 'abc' -- normalized! +ALTER USER ('foo') IN DATABASE d SET search_path = ('abc') -- fully parenthesized +ALTER USER _ IN DATABASE d SET search_path = _ -- literals removed +ALTER USER '_' IN DATABASE d SET search_path = _ -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER 'foo' IN DATABASE _ SET search_path = 'abc' -- identifiers removed + +parse +ALTER USER foo IN DATABASE d SET application_name = DEFAULT +---- +ALTER USER 'foo' IN DATABASE d SET application_name = DEFAULT -- normalized! +ALTER USER ('foo') IN DATABASE d SET application_name = (DEFAULT) -- fully parenthesized +ALTER USER _ IN DATABASE d SET application_name = DEFAULT -- literals removed +ALTER USER '_' IN DATABASE d SET application_name = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER 'foo' IN DATABASE _ SET application_name = DEFAULT -- identifiers removed + +parse +ALTER USER foo IN DATABASE d RESET server_encoding +---- +ALTER USER 'foo' IN DATABASE d SET server_encoding = DEFAULT -- normalized! +ALTER USER ('foo') IN DATABASE d SET server_encoding = (DEFAULT) -- fully parenthesized +ALTER USER _ IN DATABASE d SET server_encoding = DEFAULT -- literals removed +ALTER USER '_' IN DATABASE d SET server_encoding = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER 'foo' IN DATABASE _ SET server_encoding = DEFAULT -- identifiers removed + +parse +ALTER USER foo IN DATABASE d RESET ALL +---- +ALTER USER 'foo' IN DATABASE d RESET ALL -- normalized! +ALTER USER ('foo') IN DATABASE d RESET ALL -- fully parenthesized +ALTER USER _ IN DATABASE d RESET ALL -- literals removed +ALTER USER '_' IN DATABASE d RESET ALL -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER 'foo' IN DATABASE _ RESET ALL -- identifiers removed + +parse +ALTER ROLE foo SET search_path = 'abc' +---- +ALTER ROLE 'foo' SET search_path = 'abc' -- normalized! +ALTER ROLE ('foo') SET search_path = ('abc') -- fully parenthesized +ALTER ROLE _ SET search_path = _ -- literals removed +ALTER ROLE '_' SET search_path = _ -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE 'foo' SET search_path = 'abc' -- identifiers removed + +parse +ALTER ROLE foo SET application_name = DEFAULT +---- +ALTER ROLE 'foo' SET application_name = DEFAULT -- normalized! +ALTER ROLE ('foo') SET application_name = (DEFAULT) -- fully parenthesized +ALTER ROLE _ SET application_name = DEFAULT -- literals removed +ALTER ROLE '_' SET application_name = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE 'foo' SET application_name = DEFAULT -- identifiers removed + +parse +ALTER ROLE foo RESET server_encoding +---- +ALTER ROLE 'foo' SET server_encoding = DEFAULT -- normalized! +ALTER ROLE ('foo') SET server_encoding = (DEFAULT) -- fully parenthesized +ALTER ROLE _ SET server_encoding = DEFAULT -- literals removed +ALTER ROLE '_' SET server_encoding = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE 'foo' SET server_encoding = DEFAULT -- identifiers removed + +parse +ALTER ROLE foo RESET ALL +---- +ALTER ROLE 'foo' RESET ALL -- normalized! +ALTER ROLE ('foo') RESET ALL -- fully parenthesized +ALTER ROLE _ RESET ALL -- literals removed +ALTER ROLE '_' RESET ALL -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE 'foo' RESET ALL -- identifiers removed + +parse +ALTER ROLE foo IN DATABASE d SET search_path = 'abc' +---- +ALTER ROLE 'foo' IN DATABASE d SET search_path = 'abc' -- normalized! +ALTER ROLE ('foo') IN DATABASE d SET search_path = ('abc') -- fully parenthesized +ALTER ROLE _ IN DATABASE d SET search_path = _ -- literals removed +ALTER ROLE '_' IN DATABASE d SET search_path = _ -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE 'foo' IN DATABASE _ SET search_path = 'abc' -- identifiers removed + +parse +ALTER ROLE foo IN DATABASE d SET application_name TO DEFAULT +---- +ALTER ROLE 'foo' IN DATABASE d SET application_name = DEFAULT -- normalized! +ALTER ROLE ('foo') IN DATABASE d SET application_name = (DEFAULT) -- fully parenthesized +ALTER ROLE _ IN DATABASE d SET application_name = DEFAULT -- literals removed +ALTER ROLE '_' IN DATABASE d SET application_name = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE 'foo' IN DATABASE _ SET application_name = DEFAULT -- identifiers removed + +parse +ALTER ROLE foo IN DATABASE d RESET server_encoding +---- +ALTER ROLE 'foo' IN DATABASE d SET server_encoding = DEFAULT -- normalized! +ALTER ROLE ('foo') IN DATABASE d SET server_encoding = (DEFAULT) -- fully parenthesized +ALTER ROLE _ IN DATABASE d SET server_encoding = DEFAULT -- literals removed +ALTER ROLE '_' IN DATABASE d SET server_encoding = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE 'foo' IN DATABASE _ SET server_encoding = DEFAULT -- identifiers removed + +parse +ALTER ROLE foo IN DATABASE d RESET ALL +---- +ALTER ROLE 'foo' IN DATABASE d RESET ALL -- normalized! +ALTER ROLE ('foo') IN DATABASE d RESET ALL -- fully parenthesized +ALTER ROLE _ IN DATABASE d RESET ALL -- literals removed +ALTER ROLE '_' IN DATABASE d RESET ALL -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE 'foo' IN DATABASE _ RESET ALL -- identifiers removed + +parse +ALTER ROLE IF EXISTS foo IN DATABASE d SET search_path = 'abc' +---- +ALTER ROLE IF EXISTS 'foo' IN DATABASE d SET search_path = 'abc' -- normalized! +ALTER ROLE IF EXISTS ('foo') IN DATABASE d SET search_path = ('abc') -- fully parenthesized +ALTER ROLE IF EXISTS _ IN DATABASE d SET search_path = _ -- literals removed +ALTER ROLE IF EXISTS '_' IN DATABASE d SET search_path = _ -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE IF EXISTS 'foo' IN DATABASE _ SET search_path = 'abc' -- identifiers removed + +parse +ALTER USER IF EXISTS foo SET application_name TO DEFAULT +---- +ALTER USER IF EXISTS 'foo' SET application_name = DEFAULT -- normalized! +ALTER USER IF EXISTS ('foo') SET application_name = (DEFAULT) -- fully parenthesized +ALTER USER IF EXISTS _ SET application_name = DEFAULT -- literals removed +ALTER USER IF EXISTS '_' SET application_name = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER IF EXISTS 'foo' SET application_name = DEFAULT -- identifiers removed + +parse +ALTER ROLE IF EXISTS foo IN DATABASE d SET TIME ZONE 'UTC' +---- +ALTER ROLE IF EXISTS 'foo' IN DATABASE d SET timezone = 'UTC' -- normalized! +ALTER ROLE IF EXISTS ('foo') IN DATABASE d SET timezone = ('UTC') -- fully parenthesized +ALTER ROLE IF EXISTS _ IN DATABASE d SET timezone = _ -- literals removed +ALTER ROLE IF EXISTS '_' IN DATABASE d SET timezone = _ -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE IF EXISTS 'foo' IN DATABASE _ SET timezone = 'UTC' -- identifiers removed + +parse +ALTER USER IF EXISTS foo SET SCHEMA DEFAULT +---- +ALTER USER IF EXISTS 'foo' SET search_path = DEFAULT -- normalized! +ALTER USER IF EXISTS ('foo') SET search_path = (DEFAULT) -- fully parenthesized +ALTER USER IF EXISTS _ SET search_path = DEFAULT -- literals removed +ALTER USER IF EXISTS '_' SET search_path = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER USER IF EXISTS 'foo' SET search_path = DEFAULT -- identifiers removed + +parse +ALTER ROLE IF EXISTS foo IN DATABASE d RESET TIME ZONE +---- +ALTER ROLE IF EXISTS 'foo' IN DATABASE d SET timezone = DEFAULT -- normalized! +ALTER ROLE IF EXISTS ('foo') IN DATABASE d SET timezone = (DEFAULT) -- fully parenthesized +ALTER ROLE IF EXISTS _ IN DATABASE d SET timezone = DEFAULT -- literals removed +ALTER ROLE IF EXISTS '_' IN DATABASE d SET timezone = DEFAULT -- UNEXPECTED REPARSED AST WITHOUT LITERALS +ALTER ROLE IF EXISTS 'foo' IN DATABASE _ SET timezone = DEFAULT -- identifiers removed + +parse +ALTER USER ALL SET application_name = 'app' +---- +ALTER USER ALL SET application_name = 'app' +ALTER USER ALL SET application_name = ('app') -- fully parenthesized +ALTER USER ALL SET application_name = _ -- literals removed +ALTER USER ALL SET application_name = 'app' -- identifiers removed + +parse +ALTER USER ALL IN DATABASE d SET application_name = DEFAULT +---- +ALTER USER ALL IN DATABASE d SET application_name = DEFAULT +ALTER USER ALL IN DATABASE d SET application_name = (DEFAULT) -- fully parenthesized +ALTER USER ALL IN DATABASE d SET application_name = DEFAULT -- literals removed +ALTER USER ALL IN DATABASE _ SET application_name = DEFAULT -- identifiers removed + +parse +ALTER ROLE ALL IN DATABASE d SET application_name = 'app' +---- +ALTER ROLE ALL IN DATABASE d SET application_name = 'app' +ALTER ROLE ALL IN DATABASE d SET application_name = ('app') -- fully parenthesized +ALTER ROLE ALL IN DATABASE d SET application_name = _ -- literals removed +ALTER ROLE ALL IN DATABASE _ SET application_name = 'app' -- identifiers removed + +parse +ALTER ROLE ALL RESET ALL +---- +ALTER ROLE ALL RESET ALL +ALTER ROLE ALL RESET ALL -- fully parenthesized +ALTER ROLE ALL RESET ALL -- literals removed +ALTER ROLE ALL RESET ALL -- identifiers removed diff --git a/pkg/sql/parser/testdata/backup_restore b/pkg/sql/parser/testdata/backup_restore index c66e8e970d16..1730f76f275c 100644 --- a/pkg/sql/parser/testdata/backup_restore +++ b/pkg/sql/parser/testdata/backup_restore @@ -28,10 +28,10 @@ BACKUP TO 'bar' -- identifiers removed parse BACKUP role TO 'bar' ---- -BACKUP TABLE role TO 'bar' -- normalized! -BACKUP TABLE (role) TO ('bar') -- fully parenthesized -BACKUP TABLE role TO _ -- literals removed -BACKUP TABLE role TO '_' -- UNEXPECTED REPARSED AST WITHOUT LITERALS +BACKUP TABLE "role" TO 'bar' -- normalized! +BACKUP TABLE ("role") TO ('bar') -- fully parenthesized +BACKUP TABLE "role" TO _ -- literals removed +BACKUP TABLE "role" TO '_' -- UNEXPECTED REPARSED AST WITHOUT LITERALS BACKUP TABLE _ TO 'bar' -- identifiers removed parse diff --git a/pkg/sql/parser/testdata/grant_revoke b/pkg/sql/parser/testdata/grant_revoke index 2cd11e193af6..e18983297aea 100644 --- a/pkg/sql/parser/testdata/grant_revoke +++ b/pkg/sql/parser/testdata/grant_revoke @@ -37,9 +37,9 @@ GRANT SELECT, DELETE, UPDATE ON TABLE _, _._ TO _, _ -- identifiers removed parse GRANT SELECT ON role TO root ---- -GRANT SELECT ON TABLE role TO root -- normalized! -GRANT SELECT ON TABLE (role) TO root -- fully parenthesized -GRANT SELECT ON TABLE role TO root -- literals removed +GRANT SELECT ON TABLE "role" TO root -- normalized! +GRANT SELECT ON TABLE ("role") TO root -- fully parenthesized +GRANT SELECT ON TABLE "role" TO root -- literals removed GRANT SELECT ON TABLE _ TO _ -- identifiers removed parse diff --git a/pkg/sql/parser/testdata/show b/pkg/sql/parser/testdata/show index a55d3da0d262..d8e279e69919 100644 --- a/pkg/sql/parser/testdata/show +++ b/pkg/sql/parser/testdata/show @@ -1253,18 +1253,18 @@ SHOW GRANTS ON TABLE _ -- identifiers removed parse SHOW GRANTS ON "role" ---- -SHOW GRANTS ON TABLE role -- normalized! -SHOW GRANTS ON TABLE (role) -- fully parenthesized -SHOW GRANTS ON TABLE role -- literals removed +SHOW GRANTS ON TABLE "role" -- normalized! +SHOW GRANTS ON TABLE ("role") -- fully parenthesized +SHOW GRANTS ON TABLE "role" -- literals removed SHOW GRANTS ON TABLE _ -- identifiers removed parse SHOW GRANTS ON role, foo ---- -SHOW GRANTS ON TABLE role, foo -- normalized! -SHOW GRANTS ON TABLE (role), (foo) -- fully parenthesized -SHOW GRANTS ON TABLE role, foo -- literals removed +SHOW GRANTS ON TABLE "role", foo -- normalized! +SHOW GRANTS ON TABLE ("role"), (foo) -- fully parenthesized +SHOW GRANTS ON TABLE "role", foo -- literals removed SHOW GRANTS ON TABLE _, _ -- identifiers removed parse @@ -1286,33 +1286,33 @@ SHOW GRANTS ON TABLE _, _._ -- identifiers removed parse SHOW GRANTS ON "role", foo ---- -SHOW GRANTS ON TABLE role, foo -- normalized! -SHOW GRANTS ON TABLE (role), (foo) -- fully parenthesized -SHOW GRANTS ON TABLE role, foo -- literals removed +SHOW GRANTS ON TABLE "role", foo -- normalized! +SHOW GRANTS ON TABLE ("role"), (foo) -- fully parenthesized +SHOW GRANTS ON TABLE "role", foo -- literals removed SHOW GRANTS ON TABLE _, _ -- identifiers removed parse SHOW GRANTS ON "role".foo ---- -SHOW GRANTS ON TABLE role.foo -- normalized! -SHOW GRANTS ON TABLE (role.foo) -- fully parenthesized -SHOW GRANTS ON TABLE role.foo -- literals removed +SHOW GRANTS ON TABLE "role".foo -- normalized! +SHOW GRANTS ON TABLE ("role".foo) -- fully parenthesized +SHOW GRANTS ON TABLE "role".foo -- literals removed SHOW GRANTS ON TABLE _._ -- identifiers removed parse SHOW GRANTS ON role.foo ---- -SHOW GRANTS ON TABLE role.foo -- normalized! -SHOW GRANTS ON TABLE (role.foo) -- fully parenthesized -SHOW GRANTS ON TABLE role.foo -- literals removed +SHOW GRANTS ON TABLE "role".foo -- normalized! +SHOW GRANTS ON TABLE ("role".foo) -- fully parenthesized +SHOW GRANTS ON TABLE "role".foo -- literals removed SHOW GRANTS ON TABLE _._ -- identifiers removed parse SHOW GRANTS ON role.* ---- -SHOW GRANTS ON TABLE role.* -- normalized! -SHOW GRANTS ON TABLE (role.*) -- fully parenthesized -SHOW GRANTS ON TABLE role.* -- literals removed +SHOW GRANTS ON TABLE "role".* -- normalized! +SHOW GRANTS ON TABLE ("role".*) -- fully parenthesized +SHOW GRANTS ON TABLE "role".* -- literals removed SHOW GRANTS ON TABLE _.* -- identifiers removed parse diff --git a/pkg/sql/sem/tree/BUILD.bazel b/pkg/sql/sem/tree/BUILD.bazel index 2888b206ba18..391c31a85168 100644 --- a/pkg/sql/sem/tree/BUILD.bazel +++ b/pkg/sql/sem/tree/BUILD.bazel @@ -14,6 +14,7 @@ go_library( "alter_database.go", "alter_default_privileges.go", "alter_index.go", + "alter_role.go", "alter_schema.go", "alter_sequence.go", "alter_table.go", diff --git a/pkg/sql/sem/tree/alter_role.go b/pkg/sql/sem/tree/alter_role.go new file mode 100644 index 000000000000..e11b0887e910 --- /dev/null +++ b/pkg/sql/sem/tree/alter_role.go @@ -0,0 +1,73 @@ +// Copyright 2021 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 tree + +// AlterRole represents an `ALTER ROLE ... WITH options` statement. +type AlterRole struct { + Name Expr + IfExists bool + IsRole bool + KVOptions KVOptions +} + +// Format implements the NodeFormatter interface. +func (node *AlterRole) Format(ctx *FmtCtx) { + ctx.WriteString("ALTER") + if node.IsRole { + ctx.WriteString(" ROLE ") + } else { + ctx.WriteString(" USER ") + } + if node.IfExists { + ctx.WriteString("IF EXISTS ") + } + ctx.FormatNode(node.Name) + + if len(node.KVOptions) > 0 { + ctx.WriteString(" WITH") + node.KVOptions.formatAsRoleOptions(ctx) + } +} + +// AlterRoleSet represents an `ALTER ROLE ... SET` statement. +type AlterRoleSet struct { + RoleName Expr + IfExists bool + IsRole bool + AllRoles bool + DatabaseName Name + SetOrReset *SetVar +} + +// Format implements the NodeFormatter interface. +func (node *AlterRoleSet) Format(ctx *FmtCtx) { + ctx.WriteString("ALTER") + if node.IsRole { + ctx.WriteString(" ROLE ") + } else { + ctx.WriteString(" USER ") + } + if node.IfExists { + ctx.WriteString("IF EXISTS ") + } + if node.AllRoles { + ctx.WriteString("ALL ") + } else { + ctx.FormatNode(node.RoleName) + ctx.WriteString(" ") + } + if node.DatabaseName != "" { + ctx.WriteString("IN DATABASE ") + ctx.FormatNode(&node.DatabaseName) + ctx.WriteString(" ") + } + ctx.FormatNode(node.SetOrReset) +} diff --git a/pkg/sql/sem/tree/create.go b/pkg/sql/sem/tree/create.go index dc707dc63536..53c3ed1009d8 100644 --- a/pkg/sql/sem/tree/create.go +++ b/pkg/sql/sem/tree/create.go @@ -1771,33 +1771,6 @@ func (node *CreateRole) Format(ctx *FmtCtx) { } } -// AlterRole represents an ALTER ROLE statement. -type AlterRole struct { - Name Expr - IfExists bool - IsRole bool - KVOptions KVOptions -} - -// Format implements the NodeFormatter interface. -func (node *AlterRole) Format(ctx *FmtCtx) { - ctx.WriteString("ALTER") - if node.IsRole { - ctx.WriteString(" ROLE ") - } else { - ctx.WriteString(" USER ") - } - if node.IfExists { - ctx.WriteString("IF EXISTS ") - } - ctx.FormatNode(node.Name) - - if len(node.KVOptions) > 0 { - ctx.WriteString(" WITH") - node.KVOptions.formatAsRoleOptions(ctx) - } -} - // CreateView represents a CREATE VIEW statement. type CreateView struct { Name TableName diff --git a/pkg/sql/sem/tree/set.go b/pkg/sql/sem/tree/set.go index fb4b79caa070..4086abfc7979 100644 --- a/pkg/sql/sem/tree/set.go +++ b/pkg/sql/sem/tree/set.go @@ -21,12 +21,17 @@ package tree // SetVar represents a SET or RESET statement. type SetVar struct { - Name string - Values Exprs + Name string + Values Exprs + ResetAll bool } // Format implements the NodeFormatter interface. func (node *SetVar) Format(ctx *FmtCtx) { + if node.ResetAll { + ctx.WriteString("RESET ALL") + return + } ctx.WriteString("SET ") if node.Name == "" { ctx.WriteString("ROW (") diff --git a/pkg/sql/sem/tree/stmt.go b/pkg/sql/sem/tree/stmt.go index 712cc1c3607b..dac3a29c0dc0 100644 --- a/pkg/sql/sem/tree/stmt.go +++ b/pkg/sql/sem/tree/stmt.go @@ -333,10 +333,19 @@ func (*AlterRole) StatementType() StatementType { return TypeDDL } // StatementTag returns a short string identifying the type of statement. func (*AlterRole) StatementTag() string { return "ALTER ROLE" } -func (*AlterRole) cclOnlyStatement() {} - func (*AlterRole) hiddenFromShowQueries() {} +// StatementReturnType implements the Statement interface. +func (*AlterRoleSet) StatementReturnType() StatementReturnType { return Ack } + +// StatementType implements the Statement interface. +func (*AlterRoleSet) StatementType() StatementType { return TypeDDL } + +// StatementTag returns a short string identifying the type of statement. +func (*AlterRoleSet) StatementTag() string { return "ALTER ROLE" } + +func (*AlterRoleSet) hiddenFromShowQueries() {} + // StatementReturnType implements the Statement interface. func (*Analyze) StatementReturnType() StatementReturnType { return DDL } @@ -1579,6 +1588,7 @@ func (n *AlterTableOwner) String() string { return AsString(n) } func (n *AlterTableSetSchema) String() string { return AsString(n) } func (n *AlterType) String() string { return AsString(n) } func (n *AlterRole) String() string { return AsString(n) } +func (n *AlterRoleSet) String() string { return AsString(n) } func (n *AlterSequence) String() string { return AsString(n) } func (n *Analyze) String() string { return AsString(n) } func (n *Backup) String() string { return AsString(n) }