summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/delete_returning.result235
-rw-r--r--mysql-test/t/delete_returning.test189
-rw-r--r--sql/lex.h1
-rw-r--r--sql/sql_class.cc3
-rw-r--r--sql/sql_delete.cc45
-rw-r--r--sql/sql_delete.h7
-rw-r--r--sql/sql_parse.cc11
-rw-r--r--sql/sql_prepare.cc5
-rw-r--r--sql/sql_yacc.yy7
9 files changed, 487 insertions, 16 deletions
diff --git a/mysql-test/r/delete_returning.result b/mysql-test/r/delete_returning.result
new file mode 100644
index 00000000000..7cc551c23ed
--- /dev/null
+++ b/mysql-test/r/delete_returning.result
@@ -0,0 +1,235 @@
+CREATE TABLE t1 (a int, b varchar(32));
+INSERT INTO t1 VALUES
+(7,'ggggggg'), (1,'a'), (3,'ccc'),
+(4,'dddd'), (1,'A'), (2,'BB'), (4,'DDDD'),
+(5,'EEEEE'), (7,'GGGGGGG'), (2,'bb');
+CREATE TABLE t1c SELECT * FROM t1;
+CREATE TABLE t2 (c int);
+INSERT INTO t2 VALUES
+(4), (5), (7), (1);
+CREATE TABLE t2c SELECT * FROM t2;
+CREATE VIEW v1 AS SELECT a, UPPER(b) FROM t1;
+DELETE FROM t1 WHERE a=2 RETURNING * ;
+a b
+2 BB
+2 bb
+SELECT * FROM t1;
+a b
+7 ggggggg
+1 a
+3 ccc
+4 dddd
+1 A
+4 DDDD
+5 EEEEE
+7 GGGGGGG
+INSERT INTO t1 VALUES (2,'BB'), (2,'bb');
+DELETE FROM t1 WHERE a=2 RETURNING b;
+b
+bb
+BB
+SELECT * FROM t1;
+a b
+7 ggggggg
+1 a
+3 ccc
+4 dddd
+1 A
+4 DDDD
+5 EEEEE
+7 GGGGGGG
+DELETE FROM t1 WHERE a=2 RETURNING c;
+ERROR 42S22: Unknown column 'c' in 'field list'
+INSERT INTO t1 VALUES (2,'BB'), (2,'bb');
+DELETE FROM t1 WHERE a=2 RETURNING a, UPPER(b);
+a UPPER(b)
+2 BB
+2 BB
+SELECT * FROM t1;
+a b
+7 ggggggg
+1 a
+3 ccc
+4 dddd
+1 A
+4 DDDD
+5 EEEEE
+7 GGGGGGG
+INSERT INTO t1 VALUES (2,'BB'), (2,'bb');
+DELETE FROM t1 WHERE a=6 RETURNING b;
+b
+SELECT * FROM t1;
+a b
+7 ggggggg
+1 a
+3 ccc
+4 dddd
+1 A
+2 bb
+4 DDDD
+5 EEEEE
+7 GGGGGGG
+2 BB
+DELETE FROM t1 WHERE a=2 RETURNING MAX(b);
+ERROR HY000: Invalid use of group function
+DELETE FROM t1 WHERE a < 5 RETURNING a, (SELECT MIN(c) FROM t2 WHERE c=a+1);
+a (SELECT MIN(c) FROM t2 WHERE c=a+1)
+1 NULL
+3 4
+4 5
+1 NULL
+2 NULL
+4 5
+2 NULL
+SELECT * FROM t1;
+a b
+7 ggggggg
+5 EEEEE
+7 GGGGGGG
+DELETE FROM t1;
+INSERT INTO t1 SELECT * FROM t1c;
+DELETE FROM t2 WHERE c < 5
+RETURNING (SELECT GROUP_CONCAT(b) FROM t1 GROUP BY a HAVING a=c);
+(SELECT GROUP_CONCAT(b) FROM t1 GROUP BY a HAVING a=c)
+dddd,DDDD
+a,A
+SELECT * FROM t2;
+c
+5
+7
+DELETE FROM t2;
+INSERT INTO t2 SELECT * FROM t2c;
+CREATE FUNCTION f(arg INT) RETURNS TEXT
+BEGIN
+RETURN (SELECT GROUP_CONCAT(b) FROM t1 WHERE a=arg);
+END|
+DELETE FROM t2 WHERE c < 5 RETURNING f(c);
+f(c)
+dddd,DDDD
+a,A
+SELECT * FROM t2;
+c
+5
+7
+DELETE FROM t2;
+INSERT INTO t2 SELECT * FROM t2c;
+DROP FUNCTION f;
+DELETE FROM v1 WHERE a < 5 RETURNING * ;
+a UPPER(b)
+1 A
+3 CCC
+4 DDDD
+1 A
+2 BB
+4 DDDD
+2 BB
+SELECT * FROM t1;
+a b
+7 ggggggg
+5 EEEEE
+7 GGGGGGG
+DELETE FROM t1;
+INSERT INTO t1 SELECT * FROM t1c;
+CREATE VIEW v11(a,c) AS SELECT a, COUNT(b) FROM t1 GROUP BY a;
+DELETE FROM v11 WHERE a < 5 RETURNING * ;
+ERROR HY000: The target table v11 of the DELETE is not updatable
+DROP VIEW v11;
+PREPARE stmt FROM
+"DELETE FROM t1 WHERE a=2 ORDER BY b LIMIT 1 RETURNING a, UPPER(b)";
+EXECUTE stmt;
+a UPPER(b)
+2 BB
+SELECT * FROM t1;
+a b
+7 ggggggg
+1 a
+3 ccc
+4 dddd
+1 A
+4 DDDD
+5 EEEEE
+7 GGGGGGG
+2 bb
+EXECUTE stmt;
+a UPPER(b)
+2 BB
+SELECT * FROM t1;
+a b
+7 ggggggg
+1 a
+3 ccc
+4 dddd
+1 A
+4 DDDD
+5 EEEEE
+7 GGGGGGG
+DEALLOCATE PREPARE stmt;
+DELETE FROM t1;
+INSERT INTO t1 SELECT * FROM t1c;
+FLUSH PRIVILEGES;
+CREATE DATABASE mysqltest;
+CREATE TABLE mysqltest.t1 SELECT * FROM t1;
+GRANT DELETE ON mysqltest.* TO mysqltest_1@localhost;
+GRANT SELECT(b) ON mysqltest.t1 TO mysqltest_1@localhost;
+DELETE FROM mysqltest.t1 WHERE a=2 RETURNING b;
+ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'a' in table 't1'
+DELETE FROM mysqltest.t1 RETURNING b;
+b
+ggggggg
+a
+ccc
+dddd
+A
+BB
+DDDD
+EEEEE
+GGGGGGG
+bb
+SELECT * FROM mysqltest.t1;
+a b
+INSERT INTO mysqltest.t1 SELECT * FROM t1;
+GRANT SELECT(a) ON mysqltest.t1 TO mysqltest_1@localhost;
+DELETE FROM mysqltest.t1 WHERE a=2 RETURNING b;
+b
+bb
+BB
+SELECT * FROM mysqltest.t1;
+a b
+7 GGGGGGG
+5 EEEEE
+4 DDDD
+1 A
+4 dddd
+3 ccc
+1 a
+7 ggggggg
+INSERT INTO mysqltest.t1 SELECT * FROM t1;
+CREATE VIEW mysqltest.v1(a) AS SELECT a FROM mysqltest.t1;
+GRANT SELECT, INSERT ON mysqltest.t1 TO mysqltest_1@localhost;
+DELETE FROM mysqltest.v1;
+SELECT * FROM mysqltest.t1;
+a b
+INSERT INTO mysqltest.t1 SELECT * FROM t1;
+DELETE FROM mysqltest.v1 RETURNING a;
+ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'a' in table 'v1'
+GRANT SELECT ON mysqltest.* TO mysqltest_1@localhost;
+DELETE FROM mysqltest.v1 RETURNING a;
+a
+7
+1
+3
+4
+1
+2
+4
+5
+7
+2
+SELECT * FROM mysqltest.t1;
+a b
+INSERT INTO mysqltest.t1 SELECT * FROM t1;
+DROP DATABASE mysqltest;
+DROP USER mysqltest_1@localhost;
+DROP VIEW v1;
+DROP TABLE t1,t2;
+DROP TABLE t1c,t2c;
diff --git a/mysql-test/t/delete_returning.test b/mysql-test/t/delete_returning.test
new file mode 100644
index 00000000000..53c3ee23a75
--- /dev/null
+++ b/mysql-test/t/delete_returning.test
@@ -0,0 +1,189 @@
+#
+# Tests for DELETE FROM <table> ... RETURNING <expr>,...
+#
+
+CREATE TABLE t1 (a int, b varchar(32));
+INSERT INTO t1 VALUES
+ (7,'ggggggg'), (1,'a'), (3,'ccc'),
+ (4,'dddd'), (1,'A'), (2,'BB'), (4,'DDDD'),
+ (5,'EEEEE'), (7,'GGGGGGG'), (2,'bb');
+
+CREATE TABLE t1c SELECT * FROM t1;
+
+CREATE TABLE t2 (c int);
+INSERT INTO t2 VALUES
+ (4), (5), (7), (1);
+
+CREATE TABLE t2c SELECT * FROM t2;
+
+CREATE VIEW v1 AS SELECT a, UPPER(b) FROM t1;
+
+# DELETE FROM <table> ... RETURNING *
+
+DELETE FROM t1 WHERE a=2 RETURNING * ;
+SELECT * FROM t1;
+
+INSERT INTO t1 VALUES (2,'BB'), (2,'bb');
+
+# DELETE FROM <table> ... RETURNING <col>
+
+DELETE FROM t1 WHERE a=2 RETURNING b;
+SELECT * FROM t1;
+
+# DELETE FROM <table> ... RETURNING <not existing col>
+--error ER_BAD_FIELD_ERROR
+DELETE FROM t1 WHERE a=2 RETURNING c;
+
+INSERT INTO t1 VALUES (2,'BB'), (2,'bb');
+
+# DELETE FROM <table> ... RETURNING <col>, <expr>
+
+DELETE FROM t1 WHERE a=2 RETURNING a, UPPER(b);
+SELECT * FROM t1;
+
+INSERT INTO t1 VALUES (2,'BB'), (2,'bb');
+
+# DELETE FROM <table> ... RETURNING <col> with no rows to be deleted
+
+DELETE FROM t1 WHERE a=6 RETURNING b;
+SELECT * FROM t1;
+
+# DELETE FROM <table> ... RETURNING <expr with aggr function>
+
+--error ER_INVALID_GROUP_FUNC_USE
+DELETE FROM t1 WHERE a=2 RETURNING MAX(b);
+
+# DELETE FROM <table> ... RETURNING <expr with subquery>
+
+DELETE FROM t1 WHERE a < 5 RETURNING a, (SELECT MIN(c) FROM t2 WHERE c=a+1);
+SELECT * FROM t1;
+
+DELETE FROM t1;
+INSERT INTO t1 SELECT * FROM t1c;
+
+DELETE FROM t2 WHERE c < 5
+ RETURNING (SELECT GROUP_CONCAT(b) FROM t1 GROUP BY a HAVING a=c);
+SELECT * FROM t2;
+
+DELETE FROM t2;
+INSERT INTO t2 SELECT * FROM t2c;
+
+# DELETE FROM <table> ... RETURNING <expr with function invocation>
+
+DELIMITER |;
+
+CREATE FUNCTION f(arg INT) RETURNS TEXT
+BEGIN
+ RETURN (SELECT GROUP_CONCAT(b) FROM t1 WHERE a=arg);
+END|
+
+DELIMITER ;|
+
+DELETE FROM t2 WHERE c < 5 RETURNING f(c);
+SELECT * FROM t2;
+
+DELETE FROM t2;
+INSERT INTO t2 SELECT * FROM t2c;
+
+DROP FUNCTION f;
+
+# DELETE FROM <view> ... RETURNING <col>, <col>
+
+DELETE FROM v1 WHERE a < 5 RETURNING * ;
+SELECT * FROM t1;
+
+DELETE FROM t1;
+INSERT INTO t1 SELECT * FROM t1c;
+
+# DELETE FROM <view> ... RETURNING <expr>
+
+CREATE VIEW v11(a,c) AS SELECT a, COUNT(b) FROM t1 GROUP BY a;
+-- error ER_NON_UPDATABLE_TABLE
+DELETE FROM v11 WHERE a < 5 RETURNING * ;
+DROP VIEW v11;
+
+# prepared DELETE FROM <table> ... RETURNING <expr>
+
+PREPARE stmt FROM
+"DELETE FROM t1 WHERE a=2 ORDER BY b LIMIT 1 RETURNING a, UPPER(b)";
+EXECUTE stmt;
+SELECT * FROM t1;
+EXECUTE stmt;
+SELECT * FROM t1;
+DEALLOCATE PREPARE stmt;
+
+DELETE FROM t1;
+INSERT INTO t1 SELECT * FROM t1c;
+
+# DELETE FROM <table> ... RETURNING ... with checking privileges
+
+FLUSH PRIVILEGES;
+
+connect (root,localhost,root,,test);
+connection root;
+--disable_warnings
+CREATE DATABASE mysqltest;
+--enable_warnings
+
+CREATE TABLE mysqltest.t1 SELECT * FROM t1;
+GRANT DELETE ON mysqltest.* TO mysqltest_1@localhost;
+
+GRANT SELECT(b) ON mysqltest.t1 TO mysqltest_1@localhost;
+
+connect (user1,localhost,mysqltest_1,,test);
+
+connection user1;
+
+--error ER_COLUMNACCESS_DENIED_ERROR
+DELETE FROM mysqltest.t1 WHERE a=2 RETURNING b;
+
+DELETE FROM mysqltest.t1 RETURNING b;
+
+connection root;
+SELECT * FROM mysqltest.t1;
+INSERT INTO mysqltest.t1 SELECT * FROM t1;
+
+GRANT SELECT(a) ON mysqltest.t1 TO mysqltest_1@localhost;
+
+DELETE FROM mysqltest.t1 WHERE a=2 RETURNING b;
+
+SELECT * FROM mysqltest.t1;
+INSERT INTO mysqltest.t1 SELECT * FROM t1;
+
+connection root;
+CREATE VIEW mysqltest.v1(a) AS SELECT a FROM mysqltest.t1;
+GRANT SELECT, INSERT ON mysqltest.t1 TO mysqltest_1@localhost;
+
+connection user1;
+
+DELETE FROM mysqltest.v1;
+SELECT * FROM mysqltest.t1;
+
+INSERT INTO mysqltest.t1 SELECT * FROM t1;
+
+--error ER_COLUMNACCESS_DENIED_ERROR
+DELETE FROM mysqltest.v1 RETURNING a;
+
+connection root;
+GRANT SELECT ON mysqltest.* TO mysqltest_1@localhost;
+
+connection user1;
+DELETE FROM mysqltest.v1 RETURNING a;
+SELECT * FROM mysqltest.t1;
+
+INSERT INTO mysqltest.t1 SELECT * FROM t1;
+
+connection root;
+--disable_warnings
+DROP DATABASE mysqltest;
+--enable_warnings
+
+disconnect user1;
+DROP USER mysqltest_1@localhost;
+
+# Cleanup
+DROP VIEW v1;
+DROP TABLE t1,t2;
+DROP TABLE t1c,t2c;
+
+
diff --git a/sql/lex.h b/sql/lex.h
index e269c3e4040..a4bbf74e715 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -483,6 +483,7 @@ static SYMBOL symbols[] = {
{ "RESTRICT", SYM(RESTRICT)},
{ "RESUME", SYM(RESUME_SYM)},
{ "RETURN", SYM(RETURN_SYM)},
+ { "RETURNING", SYM(RETURNING_SYM)},
{ "RETURNS", SYM(RETURNS_SYM)},
{ "REVOKE", SYM(REVOKE)},
{ "RIGHT", SYM(RIGHT)},
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 75c422ecbf0..08e8fbe7361 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -2344,7 +2344,8 @@ int select_send::send_data(List<Item> &items)
Protocol *protocol= thd->protocol;
DBUG_ENTER("select_send::send_data");
- if (unit->offset_limit_cnt)
+ /* unit is not set when using 'delete ... returning' */
+ if (unit && unit->offset_limit_cnt)
{ // using limit offset,count
unit->offset_limit_cnt--;
DBUG_RETURN(FALSE);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 32215e91225..62aa20e90f4 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -49,7 +49,8 @@
*/
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
- SQL_I_List<ORDER> *order_list, ha_rows limit, ulonglong options)
+ SQL_I_List<ORDER> *order_list, ha_rows limit,
+ ulonglong options, select_result *result)
{
bool will_batch;
int error, loc_error;
@@ -67,6 +68,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
SELECT_LEX *select_lex= &thd->lex->select_lex;
killed_state killed_status= NOT_KILLED;
THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
+ bool with_select= !select_lex->item_list.is_empty();
DBUG_ENTER("mysql_delete");
if (open_and_lock_tables(thd, table_list, TRUE, 0))
@@ -91,9 +93,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
thd_proc_info(thd, "init");
table->map=1;
- if (mysql_prepare_delete(thd, table_list, &conds))
+ if (mysql_prepare_delete(thd, table_list, select_lex->with_wild,
+ select_lex->item_list, &conds))
DBUG_RETURN(TRUE);
+ (void) result->prepare(select_lex->item_list, NULL);
+
if (thd->lex->current_select->first_cond_optimization)
{
thd->lex->current_select->save_leaf_tables(thd);
@@ -155,9 +160,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
- We should not be binlogging this statement in row-based, and
- there should be no delete triggers associated with the table.
*/
- if (!using_limit && const_cond_result &&
- (!thd->is_current_stmt_binlog_format_row() &&
- !(table->triggers && table->triggers->has_delete_triggers())))
+ if (!with_select && !using_limit && const_cond_result &&
+ (!thd->is_current_stmt_binlog_format_row() &&
+ !(table->triggers && table->triggers->has_delete_triggers())))
{
/* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
@@ -326,9 +331,16 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
else
will_batch= !table->file->start_bulk_delete();
-
table->mark_columns_needed_for_delete();
+ if (with_select)
+ {
+ if (result->send_result_set_metadata(select_lex->item_list,
+ Protocol::SEND_NUM_ROWS |
+ Protocol::SEND_EOF))
+ goto cleanup;
+ }
+
while (!(error=info.read_record(&info)) && !thd->killed &&
! thd->is_error())
{
@@ -348,6 +360,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
break;
}
+ if (with_select && result->send_data(select_lex->item_list) < 0)
+ {
+ error=1;
+ break;
+ }
+
if (!(error= table->file->ha_delete_row(table->record[0])))
{
deleted++;
@@ -454,7 +472,10 @@ cleanup:
if (error < 0 ||
(thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error))
{
- my_ok(thd, deleted);
+ if (!with_select)
+ my_ok(thd, deleted);
+ else
+ result->send_eof();
DBUG_PRINT("info",("%ld records deleted",(long) deleted));
}
DBUG_RETURN(error >= 0 || thd->is_error());
@@ -468,13 +489,16 @@ cleanup:
mysql_prepare_delete()
thd - thread handler
table_list - global/local table list
+ wild_num - number of wildcards used in optional SELECT clause
+ field_list - list of items in optional SELECT clause
conds - conditions
RETURN VALUE
FALSE OK
TRUE error
*/
-int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
+ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
+ uint wild_num, List<Item> &field_list, Item **conds)
{
Item *fake_conds= 0;
SELECT_LEX *select_lex= &thd->lex->select_lex;
@@ -486,7 +510,10 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
&thd->lex->select_lex.top_join_list,
table_list,
select_lex->leaf_tables, FALSE,
- DELETE_ACL, SELECT_ACL, TRUE) ||
+ DELETE_ACL, SELECT_ACL, TRUE))
+ DBUG_RETURN(TRUE);
+ if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) ||
+ setup_fields(thd, NULL, field_list, MARK_COLUMNS_READ, NULL, 0) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);
diff --git a/sql/sql_delete.h b/sql/sql_delete.h
index 6147e0ea367..9cd09dc5722 100644
--- a/sql/sql_delete.h
+++ b/sql/sql_delete.h
@@ -21,12 +21,15 @@
class THD;
struct TABLE_LIST;
class Item;
+class select_result;
typedef class Item COND;
template <typename T> class SQL_I_List;
-int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
+int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
+ uint wild_num, List<Item> &field_list, Item **conds);
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
- SQL_I_List<ORDER> *order, ha_rows rows, ulonglong options);
+ SQL_I_List<ORDER> *order, ha_rows rows,
+ ulonglong options, select_result *result);
#endif /* SQL_DELETE_INCLUDED */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 97bc98a5b67..5a4f3ad0907 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3243,6 +3243,7 @@ end_with_restore_list:
}
case SQLCOM_DELETE:
{
+ select_result *sel_result=lex->result;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= delete_precheck(thd, all_tables)))
break;
@@ -3250,9 +3251,13 @@ end_with_restore_list:
unit->set_limit(select_lex);
MYSQL_DELETE_START(thd->query());
- res = mysql_delete(thd, all_tables, select_lex->where,
- &select_lex->order_list,
- unit->select_limit_cnt, select_lex->options);
+ if (!(sel_result= lex->result) && !(sel_result= new select_send()))
+ return 1;
+ res = mysql_delete(thd, all_tables,
+ select_lex->where, &select_lex->order_list,
+ unit->select_limit_cnt, select_lex->options,
+ sel_result);
+ delete sel_result;
MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func());
break;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 331a84c5955..e8965842140 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1459,7 +1459,10 @@ static bool mysql_test_delete(Prepared_statement *stmt,
goto error;
}
- DBUG_RETURN(mysql_prepare_delete(thd, table_list, &lex->select_lex.where));
+ DBUG_RETURN(mysql_prepare_delete(thd, table_list,
+ lex->select_lex.with_wild,
+ lex->select_lex.item_list,
+ &lex->select_lex.where));
error:
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f3abc872587..a10612e7266 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1261,6 +1261,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token RESTORE_SYM
%token RESTRICT
%token RESUME_SYM
+%token RETURNING_SYM
%token RETURNS_SYM /* SQL-2003-R */
%token RETURN_SYM /* SQL-2003-R */
%token REVOKE /* SQL-2003-R */
@@ -11428,6 +11429,7 @@ single_multi:
}
where_clause opt_order_clause
delete_limit_clause {}
+ opt_select_expressions {}
| table_wild_list
{
mysql_init_multi_delete(Lex);
@@ -11452,6 +11454,11 @@ single_multi:
}
;
+opt_select_expressions:
+ /* empty */
+ | RETURNING_SYM select_item_list
+ ;
+
table_wild_list:
table_wild_one
| table_wild_list ',' table_wild_one