Skip to content

Commit

Permalink
sql: add ON UPDATE syntax
Browse files Browse the repository at this point in the history
Previously, we did not have parsing implemented for ON UPDATE
expressions on columns. This PR adds parsing for ON UPDATE expressions.

Release note: None
  • Loading branch information
pawalt committed Aug 17, 2021
1 parent 65abfcc commit 89d467a
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 6 deletions.
4 changes: 4 additions & 0 deletions docs/generated/sql/bnf/alter_column.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ alter_onetable_stmt ::=
| 'ALTER' 'TABLE' table_name 'ALTER' 'COLUMN' column_name 'DROP' 'DEFAULT'
| 'ALTER' 'TABLE' table_name 'ALTER' column_name 'SET' 'DEFAULT' a_expr
| 'ALTER' 'TABLE' table_name 'ALTER' column_name 'DROP' 'DEFAULT'
| 'ALTER' 'TABLE' table_name 'ALTER' 'COLUMN' column_name alter_column_on_update
| 'ALTER' 'TABLE' table_name 'ALTER' column_name alter_column_on_update
| 'ALTER' 'TABLE' table_name 'ALTER' 'COLUMN' column_name alter_column_visible
| 'ALTER' 'TABLE' table_name 'ALTER' column_name alter_column_visible
| 'ALTER' 'TABLE' table_name 'ALTER' 'COLUMN' column_name 'DROP' 'NOT' 'NULL'
Expand Down Expand Up @@ -31,6 +33,8 @@ alter_onetable_stmt ::=
| 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'COLUMN' column_name 'DROP' 'DEFAULT'
| 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' column_name 'SET' 'DEFAULT' a_expr
| 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' column_name 'DROP' 'DEFAULT'
| 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'COLUMN' column_name alter_column_on_update
| 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' column_name alter_column_on_update
| 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'COLUMN' column_name alter_column_visible
| 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' column_name alter_column_visible
| 'ALTER' 'TABLE' 'IF' 'EXISTS' table_name 'ALTER' 'COLUMN' column_name 'DROP' 'NOT' 'NULL'
Expand Down
4 changes: 2 additions & 2 deletions docs/generated/sql/bnf/alter_table.bnf
Original file line number Diff line number Diff line change
@@ -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_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 ) | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_interleave | '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 ) ) ( ( ',' ( '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_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 ) | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_interleave | '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 ) ) )* )
| '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_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 ) | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_interleave | '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 ) ) ( ( ',' ( '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_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 ) | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_interleave | '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 ) ) )* )
'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 ) | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_interleave | '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 ) ) ( ( ',' ( '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 ) | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_interleave | '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 ) ) )* )
| '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 ) | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_interleave | '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 ) ) ( ( ',' ( '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 ) | 'ALTER' 'PRIMARY' 'KEY' 'USING' 'COLUMNS' '(' index_params ')' opt_hash_sharded opt_interleave | '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 ) ) )* )
2 changes: 2 additions & 0 deletions docs/generated/sql/bnf/col_qualification.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ col_qualification ::=
| 'CONSTRAINT' constraint_name 'PRIMARY' 'KEY' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets
| 'CONSTRAINT' constraint_name 'CHECK' '(' a_expr ')'
| 'CONSTRAINT' constraint_name 'DEFAULT' b_expr
| 'CONSTRAINT' constraint_name 'ON' 'UPDATE' b_expr
| 'CONSTRAINT' constraint_name 'REFERENCES' table_name opt_name_parens key_match reference_actions
| 'CONSTRAINT' constraint_name generated_as '(' a_expr ')' 'STORED'
| 'CONSTRAINT' constraint_name generated_as '(' a_expr ')' 'VIRTUAL'
Expand All @@ -20,6 +21,7 @@ col_qualification ::=
| 'PRIMARY' 'KEY' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' n_buckets
| 'CHECK' '(' a_expr ')'
| 'DEFAULT' b_expr
| 'ON' 'UPDATE' b_expr
| 'REFERENCES' table_name opt_name_parens key_match reference_actions
| generated_as '(' a_expr ')' 'STORED'
| generated_as '(' a_expr ')' 'VIRTUAL'
Expand Down
6 changes: 6 additions & 0 deletions docs/generated/sql/bnf/stmt_block.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -2634,6 +2634,7 @@ alter_table_cmd ::=
| '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'
Expand Down Expand Up @@ -2911,6 +2912,10 @@ alter_column_default ::=
'SET' 'DEFAULT' a_expr
| 'DROP' 'DEFAULT'

alter_column_on_update ::=
'SET' 'ON' 'UPDATE' b_expr
| 'DROP' 'ON' 'UPDATE'

alter_column_visible ::=
'SET' 'VISIBLE'
| 'SET' 'NOT' 'VISIBLE'
Expand Down Expand Up @@ -3034,6 +3039,7 @@ col_qualification_elem ::=
| 'PRIMARY' 'KEY' 'USING' 'HASH' 'WITH' 'BUCKET_COUNT' '=' a_expr
| 'CHECK' '(' a_expr ')'
| 'DEFAULT' b_expr
| 'ON' 'UPDATE' b_expr
| 'REFERENCES' table_name opt_name_parens key_match reference_actions
| generated_as '(' a_expr ')' 'STORED'
| generated_as '(' a_expr ')' 'VIRTUAL'
Expand Down
3 changes: 3 additions & 0 deletions pkg/sql/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,9 @@ func applyColumnMutation(
}
}

case *tree.AlterTableSetOnUpdate:
return errors.Newf("unimplemented")

case *tree.AlterTableSetVisible:
column, err := tableDesc.FindActiveOrNewColumnByName(col.ColName())
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/lexbase/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func init() {
"reset",
"role",
"user",
"on",
} {
reservedOrLookaheadKeywords[s] = struct{}{}
}
Expand Down
16 changes: 15 additions & 1 deletion pkg/sql/parser/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,15 @@ func (l *lexer) Lex(lval *sqlSymType) int {
*lval = l.tokens[l.lastPos]

switch lval.id {
case NOT, WITH, AS, GENERATED, NULLS, RESET, ROLE, USER:
case NOT, WITH, AS, GENERATED, NULLS, RESET, ROLE, USER, ON:
nextID := int32(0)
if l.lastPos+1 < len(l.tokens) {
nextID = l.tokens[l.lastPos+1].id
}
secondID := int32(0)
if l.lastPos+2 < len(l.tokens) {
secondID = l.tokens[l.lastPos+2].id
}

// If you update these cases, update lex.lookaheadKeywords.
switch lval.id {
Expand Down Expand Up @@ -131,6 +135,16 @@ func (l *lexer) Lex(lval *sqlSymType) int {
case ALL:
lval.id = USER_ALL
}
case ON:
switch nextID {
case DELETE:
lval.id = ON_LA
case UPDATE:
switch secondID {
case NO, RESTRICT, CASCADE, SET:
lval.id = ON_LA
}
}
}
}

Expand Down
27 changes: 24 additions & 3 deletions pkg/sql/parser/sql.y
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,8 @@ func (u *sqlSymUnion) setVar() *tree.SetVar {
// 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 GENERATED_BY_DEFAULT RESET_ALL ROLE_ALL USER_ALL
%token NOT_LA NULLS_LA WITH_LA AS_LA GENERATED_ALWAYS GENERATED_BY_DEFAULT RESET_ALL ROLE_ALL
%token USER_ALL ON_LA

%union {
id int32
Expand Down Expand Up @@ -1113,6 +1114,7 @@ func (u *sqlSymUnion) setVar() *tree.SetVar {
%type <tree.SelectStatement> set_operation

%type <tree.Expr> alter_column_default
%type <tree.Expr> alter_column_on_update
%type <tree.Expr> alter_column_visible
%type <tree.Direction> opt_asc_desc
%type <tree.NullsOrder> opt_nulls_order
Expand Down Expand Up @@ -2122,6 +2124,11 @@ alter_table_cmd:
{
$$.val = &tree.AlterTableSetDefault{Column: tree.Name($3), Default: $4.expr()}
}
// ALTER TABLE <name> ALTER [COLUMN] <colname> {ON UPDATE <expr>|DROP ON UPDATE}
| ALTER opt_column column_name alter_column_on_update
{
$$.val = &tree.AlterTableSetOnUpdate{Column: tree.Name($3), Expr: $4.expr()}
}
// ALTER TABLE <name> ALTER [COLUMN] <colname> SET {VISIBLE|NOT VISIBLE}
| ALTER opt_column column_name alter_column_visible
{
Expand Down Expand Up @@ -2286,6 +2293,16 @@ alter_column_default:
$$.val = nil
}

alter_column_on_update:
SET ON UPDATE b_expr
{
$$.val = $4.expr()
}
| DROP ON UPDATE
{
$$.val = nil
}

alter_column_visible:
SET VISIBLE
{
Expand Down Expand Up @@ -6708,6 +6725,10 @@ col_qualification_elem:
{
$$.val = &tree.ColumnDefault{Expr: $2.expr()}
}
| ON UPDATE b_expr
{
$$.val = &tree.ColumnOnUpdate{Expr: $3.expr()}
}
| REFERENCES table_name opt_name_parens key_match reference_actions
{
name := $2.unresolvedObjectName().ToTableName()
Expand Down Expand Up @@ -7088,13 +7109,13 @@ reference_actions:
}

reference_on_update:
ON UPDATE reference_action
ON_LA UPDATE reference_action
{
$$.val = $3.referenceAction()
}

reference_on_delete:
ON DELETE reference_action
ON_LA DELETE reference_action
{
$$.val = $3.referenceAction()
}
Expand Down
40 changes: 40 additions & 0 deletions pkg/sql/parser/testdata/alter_table
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,14 @@ ALTER TABLE a ADD COLUMN b INT8, ADD CONSTRAINT a_idx UNIQUE (a) -- fully parent
ALTER TABLE a ADD COLUMN b INT8, ADD CONSTRAINT a_idx UNIQUE (a) -- literals removed
ALTER TABLE _ ADD COLUMN _ INT8, ADD CONSTRAINT _ UNIQUE (_) -- identifiers removed

parse
ALTER TABLE a ADD COLUMN b INT8 ON UPDATE 1
----
ALTER TABLE a ADD COLUMN b INT8 ON UPDATE 1
ALTER TABLE a ADD COLUMN b INT8 ON UPDATE (1) -- fully parenthesized
ALTER TABLE a ADD COLUMN b INT8 ON UPDATE _ -- literals removed
ALTER TABLE _ ADD COLUMN _ INT8 ON UPDATE 1 -- identifiers removed

parse
EXPLAIN ALTER TABLE a ADD COLUMN b INT8
----
Expand Down Expand Up @@ -489,6 +497,38 @@ ALTER TABLE a ALTER COLUMN b DROP DEFAULT -- fully parenthesized
ALTER TABLE a ALTER COLUMN b DROP DEFAULT -- literals removed
ALTER TABLE _ ALTER COLUMN _ DROP DEFAULT -- identifiers removed

parse
ALTER TABLE a ALTER COLUMN b SET ON UPDATE 42
----
ALTER TABLE a ALTER COLUMN b SET ON UPDATE 42
ALTER TABLE a ALTER COLUMN b SET ON UPDATE (42) -- fully parenthesized
ALTER TABLE a ALTER COLUMN b SET ON UPDATE _ -- literals removed
ALTER TABLE _ ALTER COLUMN _ SET ON UPDATE 42 -- identifiers removed

parse
ALTER TABLE a ALTER COLUMN b SET ON UPDATE NULL
----
ALTER TABLE a ALTER COLUMN b SET ON UPDATE NULL
ALTER TABLE a ALTER COLUMN b SET ON UPDATE (NULL) -- fully parenthesized
ALTER TABLE a ALTER COLUMN b SET ON UPDATE _ -- literals removed
ALTER TABLE _ ALTER COLUMN _ SET ON UPDATE NULL -- identifiers removed

parse
ALTER TABLE a ALTER COLUMN b SET ON UPDATE current_timestamp()
----
ALTER TABLE a ALTER COLUMN b SET ON UPDATE current_timestamp()
ALTER TABLE a ALTER COLUMN b SET ON UPDATE (current_timestamp()) -- fully parenthesized
ALTER TABLE a ALTER COLUMN b SET ON UPDATE current_timestamp() -- literals removed
ALTER TABLE _ ALTER COLUMN _ SET ON UPDATE current_timestamp() -- identifiers removed

parse
ALTER TABLE a ALTER COLUMN b DROP ON UPDATE
----
ALTER TABLE a ALTER COLUMN b DROP ON UPDATE
ALTER TABLE a ALTER COLUMN b DROP ON UPDATE -- fully parenthesized
ALTER TABLE a ALTER COLUMN b DROP ON UPDATE -- literals removed
ALTER TABLE _ ALTER COLUMN _ DROP ON UPDATE -- identifiers removed

parse
ALTER TABLE a ALTER COLUMN b DROP NOT NULL
----
Expand Down
Loading

0 comments on commit 89d467a

Please sign in to comment.