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`.

Assists: #40963

Release note (sql change): Parser will now parse
statements of the form `DELETE FROM ... USING`.
  • Loading branch information
faizaanmadhani committed Sep 29, 2022
1 parent 6850a6e commit b860d48
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 88 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 @@ -596,6 +596,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 @@ -1763,6 +1767,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 @@ -1963,9 +1970,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 @@ -2479,6 +2483,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 @@ -2594,16 +2608,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 @@ -3052,6 +3056,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 @@ -3111,43 +3152,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 @@ -3477,6 +3481,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 @@ -3509,30 +3537,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 @@ -3746,12 +3750,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 @@ -3762,6 +3760,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
12 changes: 9 additions & 3 deletions pkg/sql/parser/sql.y
Original file line number Diff line number Diff line change
Expand Up @@ -1374,7 +1374,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 @@ -4823,6 +4823,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 @@ -4832,6 +4833,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 @@ -4841,8 +4843,12 @@ 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
26 changes: 26 additions & 0 deletions pkg/sql/parser/testdata/delete
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,29 @@ 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


5 changes: 5 additions & 0 deletions pkg/sql/sem/tree/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Delete struct {
Table TableExpr
Where *Where
OrderBy OrderBy
Using TableExprs
Limit *Limit
Returning ReturningClause
}
Expand All @@ -34,6 +35,10 @@ func (node *Delete) Format(ctx *FmtCtx) {
ctx.FormatNode(node.With)
ctx.WriteString("DELETE FROM ")
ctx.FormatNode(node.Table)
if len(node.Using) > 0 {
ctx.WriteString(" USING ")
ctx.FormatNode(&node.Using)
}
if node.Where != nil {
ctx.WriteByte(' ')
ctx.FormatNode(node.Where)
Expand Down
6 changes: 5 additions & 1 deletion pkg/sql/sem/tree/pretty.go
Original file line number Diff line number Diff line change
Expand Up @@ -1164,7 +1164,11 @@ func (node *Delete) doc(p *PrettyCfg) pretty.Doc {
items := make([]pretty.TableRow, 0, 6)
items = append(items,
node.With.docRow(p),
p.row("DELETE FROM", p.Doc(node.Table)),
p.row("DELETE FROM", p.Doc(node.Table)))
if len(node.Using) > 0 {
items = append(items, p.row("USING", p.Doc(&node.Using)))
}
items = append(items,
node.Where.docRow(p),
node.OrderBy.docRow(p))
items = append(items, node.Limit.docTable(p)...)
Expand Down

0 comments on commit b860d48

Please sign in to comment.