Skip to content

Commit

Permalink
sql: add support for DELETE FROM ... USING to parser
Browse files Browse the repository at this point in the history
Previously, the statement `DELETE FROM .. USING` would
return an unimplemented error. This commit adds
production rules in the parser to handle the `USING`
clause in a `DELETE` statement, however usage will
return an error as support has not been implemented
in `optbuilder`.

Release note: None
  • Loading branch information
faizaanmadhani committed Oct 13, 2022
1 parent 708b242 commit a2b871e
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 89 deletions.
2 changes: 1 addition & 1 deletion docs/generated/sql/bnf/delete_stmt.bnf
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
delete_stmt ::=
( ( 'WITH' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) | 'WITH' 'RECURSIVE' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) ) | ) 'DELETE' 'FROM' ( ( ( 'ONLY' | ) table_name opt_index_flags ( '*' | ) ) | ( ( 'ONLY' | ) table_name opt_index_flags ( '*' | ) ) table_alias_name | ( ( 'ONLY' | ) table_name opt_index_flags ( '*' | ) ) 'AS' table_alias_name ) ( ( 'WHERE' a_expr ) | ) ( sort_clause | ) ( limit_clause | ) ( 'RETURNING' target_list | 'RETURNING' 'NOTHING' | )
( ( 'WITH' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) | 'WITH' 'RECURSIVE' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) ) | ) 'DELETE' 'FROM' ( ( ( 'ONLY' | ) table_name opt_index_flags ( '*' | ) ) | ( ( 'ONLY' | ) table_name opt_index_flags ( '*' | ) ) table_alias_name | ( ( 'ONLY' | ) table_name opt_index_flags ( '*' | ) ) 'AS' table_alias_name ) opt_using_clause ( ( 'WHERE' a_expr ) | ) ( sort_clause | ) ( limit_clause | ) ( 'RETURNING' target_list | 'RETURNING' 'NOTHING' | )
166 changes: 85 additions & 81 deletions docs/generated/sql/bnf/stmt_block.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ create_stmt ::=
| create_external_connection_stmt

delete_stmt ::=
opt_with_clause 'DELETE' 'FROM' table_expr_opt_alias_idx opt_where_clause opt_sort_clause opt_limit_clause returning_clause
opt_with_clause 'DELETE' 'FROM' table_expr_opt_alias_idx opt_using_clause opt_where_clause opt_sort_clause opt_limit_clause returning_clause

drop_stmt ::=
drop_ddl_stmt
Expand Down Expand Up @@ -597,6 +597,10 @@ table_expr_opt_alias_idx ::=
| table_name_opt_idx table_alias_name
| table_name_opt_idx 'AS' table_alias_name

opt_using_clause ::=
'USING' from_list
|

opt_sort_clause ::=
sort_clause
|
Expand Down Expand Up @@ -1769,6 +1773,9 @@ with_clause ::=
table_name_opt_idx ::=
opt_only table_name opt_index_flags opt_descendant

from_list ::=
( table_ref ) ( ( ',' table_ref ) )*

sort_clause ::=
'ORDER' 'BY' sortby_list

Expand Down Expand Up @@ -1969,9 +1976,6 @@ set_clause ::=
single_set_clause
| multiple_set_clause

from_list ::=
( table_ref ) ( ( ',' table_ref ) )*

simple_db_object_name ::=
db_object_name_component

Expand Down Expand Up @@ -2485,6 +2489,16 @@ opt_descendant ::=
'*'
|

table_ref ::=
relation_expr opt_index_flags opt_ordinality opt_alias_clause
| select_with_parens opt_ordinality opt_alias_clause
| 'LATERAL' select_with_parens opt_ordinality opt_alias_clause
| joined_table
| '(' joined_table ')' opt_ordinality alias_clause
| func_table opt_ordinality opt_func_alias_clause
| 'LATERAL' func_table opt_ordinality opt_alias_clause
| '[' row_source_extension_stmt ']' opt_ordinality opt_alias_clause

sortby_list ::=
( sortby ) ( ( ',' sortby ) )*

Expand Down Expand Up @@ -2600,16 +2614,6 @@ single_set_clause ::=
multiple_set_clause ::=
'(' insert_column_list ')' '=' in_expr

table_ref ::=
relation_expr opt_index_flags opt_ordinality opt_alias_clause
| select_with_parens opt_ordinality opt_alias_clause
| 'LATERAL' select_with_parens opt_ordinality opt_alias_clause
| joined_table
| '(' joined_table ')' opt_ordinality alias_clause
| func_table opt_ordinality opt_func_alias_clause
| 'LATERAL' func_table opt_ordinality opt_alias_clause
| '[' row_source_extension_stmt ']' opt_ordinality opt_alias_clause

type_func_name_crdb_extra_keyword ::=
'FAMILY'

Expand Down Expand Up @@ -3058,6 +3062,43 @@ common_table_expr ::=
index_flags_param_list ::=
( index_flags_param ) ( ( ',' index_flags_param ) )*

opt_ordinality ::=
'WITH' 'ORDINALITY'
|

opt_alias_clause ::=
alias_clause
|

joined_table ::=
'(' joined_table ')'
| table_ref 'CROSS' opt_join_hint 'JOIN' table_ref
| table_ref join_type opt_join_hint 'JOIN' table_ref join_qual
| table_ref 'JOIN' table_ref join_qual
| table_ref 'NATURAL' join_type opt_join_hint 'JOIN' table_ref
| table_ref 'NATURAL' 'JOIN' table_ref

alias_clause ::=
'AS' table_alias_name opt_col_def_list_no_types
| table_alias_name opt_col_def_list_no_types

func_table ::=
func_expr_windowless
| 'ROWS' 'FROM' '(' rowsfrom_list ')'

opt_func_alias_clause ::=
func_alias_clause
|

row_source_extension_stmt ::=
delete_stmt
| explain_stmt
| insert_stmt
| select_stmt
| show_stmt
| update_stmt
| upsert_stmt

sortby ::=
a_expr opt_asc_desc opt_nulls_order
| 'PRIMARY' 'KEY' table_name opt_asc_desc
Expand Down Expand Up @@ -3117,43 +3158,6 @@ var_list ::=
schema_wildcard ::=
wildcard_pattern

opt_ordinality ::=
'WITH' 'ORDINALITY'
|

opt_alias_clause ::=
alias_clause
|

joined_table ::=
'(' joined_table ')'
| table_ref 'CROSS' opt_join_hint 'JOIN' table_ref
| table_ref join_type opt_join_hint 'JOIN' table_ref join_qual
| table_ref 'JOIN' table_ref join_qual
| table_ref 'NATURAL' join_type opt_join_hint 'JOIN' table_ref
| table_ref 'NATURAL' 'JOIN' table_ref

alias_clause ::=
'AS' table_alias_name opt_col_def_list_no_types
| table_alias_name opt_col_def_list_no_types

func_table ::=
func_expr_windowless
| 'ROWS' 'FROM' '(' rowsfrom_list ')'

opt_func_alias_clause ::=
func_alias_clause
|

row_source_extension_stmt ::=
delete_stmt
| explain_stmt
| insert_stmt
| select_stmt
| show_stmt
| update_stmt
| upsert_stmt

type_func_name_no_crdb_extra_keyword ::=
'AUTHORIZATION'
| 'COLLATION'
Expand Down Expand Up @@ -3483,6 +3487,30 @@ index_flags_param ::=
| 'FORCE_ZIGZAG'
| 'FORCE_ZIGZAG' '=' index_name

opt_join_hint ::=
'HASH'
| 'MERGE'
| 'LOOKUP'
| 'INVERTED'
|

join_type ::=
'FULL' join_outer
| 'LEFT' join_outer
| 'RIGHT' join_outer
| 'INNER'

join_qual ::=
'USING' '(' name_list ')'
| 'ON' a_expr

rowsfrom_list ::=
( rowsfrom_item ) ( ( ',' rowsfrom_item ) )*

func_alias_clause ::=
'AS' table_alias_name opt_col_def_list
| table_alias_name opt_col_def_list

opt_asc_desc ::=
'ASC'
| 'DESC'
Expand Down Expand Up @@ -3515,30 +3543,6 @@ opt_nowait_or_skip ::=
wildcard_pattern ::=
name '.' '*'

opt_join_hint ::=
'HASH'
| 'MERGE'
| 'LOOKUP'
| 'INVERTED'
|

join_type ::=
'FULL' join_outer
| 'LEFT' join_outer
| 'RIGHT' join_outer
| 'INNER'

join_qual ::=
'USING' '(' name_list ')'
| 'ON' a_expr

rowsfrom_list ::=
( rowsfrom_item ) ( ( ',' rowsfrom_item ) )*

func_alias_clause ::=
'AS' table_alias_name opt_col_def_list
| table_alias_name opt_col_def_list

func_arg ::=
func_arg_class param_name func_arg_type
| param_name func_arg_class func_arg_type
Expand Down Expand Up @@ -3752,12 +3756,6 @@ func_as ::=
col_def_list_no_types ::=
( name ) ( ( ',' name ) )*

group_by_item ::=
a_expr

window_definition ::=
window_name 'AS' window_specification

join_outer ::=
'OUTER'
|
Expand All @@ -3768,6 +3766,12 @@ rowsfrom_item ::=
opt_col_def_list ::=
'(' col_def_list ')'

group_by_item ::=
a_expr

window_definition ::=
window_name 'AS' window_specification

func_arg_class ::=
'IN'

Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/opt/optbuilder/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (b *Builder) buildDelete(del *tree.Delete, inScope *scope) (outScope *scope
// ORDER BY <order-by> LIMIT <limit>
//
// All columns from the delete table will be projected.
mb.buildInputForDelete(inScope, del.Table, del.Where, del.Limit, del.OrderBy)
mb.buildInputForDelete(inScope, del.Table, del.Where, del.Using, del.Limit, del.OrderBy)

// Build the final delete statement, including any returned expressions.
if resultsNeeded(del.Returning) {
Expand Down
12 changes: 11 additions & 1 deletion pkg/sql/opt/optbuilder/mutation_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,12 @@ func (mb *mutationBuilder) buildInputForUpdate(
// All columns from the table to update are added to fetchColList.
// TODO(andyk): Do needed column analysis to project fewer columns if possible.
func (mb *mutationBuilder) buildInputForDelete(
inScope *scope, texpr tree.TableExpr, where *tree.Where, limit *tree.Limit, orderBy tree.OrderBy,
inScope *scope,
texpr tree.TableExpr,
where *tree.Where,
using tree.TableExprs,
limit *tree.Limit,
orderBy tree.OrderBy,
) {
var indexFlags *tree.IndexFlags
if source, ok := texpr.(*tree.AliasedTableExpr); ok && source.IndexFlags != nil {
Expand Down Expand Up @@ -425,6 +430,11 @@ func (mb *mutationBuilder) buildInputForDelete(
mb.b.buildOrderBy(mb.outScope, projectionsScope, orderByScope)
mb.b.constructProjectForScope(mb.outScope, projectionsScope)

// USING
if using != nil {
panic("DELETE USING is unimplemented so should not be used")
}

// LIMIT
if limit != nil {
mb.b.buildLimit(limit, inScope, projectionsScope)
Expand Down
14 changes: 11 additions & 3 deletions pkg/sql/parser/sql.y
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,7 @@ func (u *sqlSymUnion) functionObjs() tree.FuncObjs {
%type <*tree.Limit> select_limit opt_select_limit
%type <tree.TableNames> relation_expr_list
%type <tree.ReturningClause> returning_clause
%type <empty> opt_using_clause
%type <tree.TableExprs> opt_using_clause
%type <tree.RefreshDataOption> opt_clear_data

%type <[]tree.SequenceOption> sequence_option_list opt_sequence_option_list
Expand Down Expand Up @@ -4824,6 +4824,7 @@ opt_changefeed_sink:
// %Category: DML
// %Text: DELETE FROM <tablename> [WHERE <expr>]
// [ORDER BY <exprs...>]
// [USING <exprs...>]
// [LIMIT <expr>]
// [RETURNING <exprs...>]
// %SeeAlso: WEBDOCS/delete.html
Expand All @@ -4833,6 +4834,7 @@ delete_stmt:
$$.val = &tree.Delete{
With: $1.with(),
Table: $4.tblExpr(),
Using: $5.tblExprs(),
Where: tree.NewWhere(tree.AstWhere, $6.expr()),
OrderBy: $7.orderBy(),
Limit: $8.limit(),
Expand All @@ -4842,8 +4844,14 @@ delete_stmt:
| opt_with_clause DELETE error // SHOW HELP: DELETE

opt_using_clause:
USING from_list { return unimplementedWithIssueDetail(sqllex, 40963, "delete using") }
| /* EMPTY */ { }
USING from_list
{
$$.val = $2.tblExprs()
}
| /* EMPTY */
{
$$.val = tree.TableExprs{}
}


// %Help: DISCARD - reset the session to its initial state
Expand Down
50 changes: 50 additions & 0 deletions pkg/sql/parser/testdata/delete
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,53 @@ DELETE FROM a WHERE a = b -- normalized!
DELETE FROM a WHERE ((a) = (b)) -- fully parenthesized
DELETE FROM a WHERE a = b -- literals removed
DELETE FROM _ WHERE _ = _ -- identifiers removed

parse
DELETE FROM a USING b
----
DELETE FROM a USING b
DELETE FROM a USING b -- fully parenthesized
DELETE FROM a USING b -- literals removed
DELETE FROM _ USING _ -- identifiers removed

parse
DELETE FROM a USING b WHERE c = d
----
DELETE FROM a USING b WHERE c = d
DELETE FROM a USING b WHERE ((c) = (d)) -- fully parenthesized
DELETE FROM a USING b WHERE c = d -- literals removed
DELETE FROM _ USING _ WHERE _ = _ -- identifiers removed

parse
DELETE FROM a USING b WHERE c = d AND e = f
----
DELETE FROM a USING b WHERE (c = d) AND (e = f) -- normalized!
DELETE FROM a USING b WHERE ((((c) = (d))) AND (((e) = (f)))) -- fully parenthesized
DELETE FROM a USING b WHERE (c = d) AND (e = f) -- literals removed
DELETE FROM _ USING _ WHERE (_ = _) AND (_ = _) -- identifiers removed

parse
DELETE FROM a USING b, c WHERE d > e AND e < f
----
DELETE FROM a USING b, c WHERE (d > e) AND (e < f) -- normalized!
DELETE FROM a USING b, c WHERE ((((d) > (e))) AND (((e) < (f)))) -- fully parenthesized
DELETE FROM a USING b, c WHERE (d > e) AND (e < f) -- literals removed
DELETE FROM _ USING _, _ WHERE (_ > _) AND (_ < _) -- identifiers removed

parse
DELETE FROM a USING b, c, d AS other WHERE e = f AND g = h OR i = j
----
DELETE FROM a USING b, c, d AS other WHERE ((e = f) AND (g = h)) OR (i = j) -- normalized!
DELETE FROM a USING b, c, d AS other WHERE ((((((e) = (f))) AND (((g) = (h))))) OR (((i) = (j)))) -- fully parenthesized
DELETE FROM a USING b, c, d AS other WHERE ((e = f) AND (g = h)) OR (i = j) -- literals removed
DELETE FROM _ USING _, _, _ AS _ WHERE ((_ = _) AND (_ = _)) OR (_ = _) -- identifiers removed

parse
DELETE FROM a USING b AS one, c AS two, d AS three, e AS four WHERE f != g AND g = h RETURNING e
----
DELETE FROM a USING b AS one, c AS two, d AS three, e AS four WHERE (f != g) AND (g = h) RETURNING e -- normalized!
DELETE FROM a USING b AS one, c AS two, d AS three, e AS four WHERE ((((f) != (g))) AND (((g) = (h)))) RETURNING (e) -- fully parenthesized
DELETE FROM a USING b AS one, c AS two, d AS three, e AS four WHERE (f != g) AND (g = h) RETURNING e -- literals removed
DELETE FROM _ USING _ AS _, _ AS _, _ AS _, _ AS _ WHERE (_ != _) AND (_ = _) RETURNING _ -- identifiers removed


Loading

0 comments on commit a2b871e

Please sign in to comment.