[Commits] Rev 3445: MWL#205 DELETE with result set (mdev-3814) in file:///home/igor/maria/maria-10.0-mdev3814/

Igor Babaev igor at askmonty.org
Tue Aug 6 23:31:40 EEST 2013


At file:///home/igor/maria/maria-10.0-mdev3814/

------------------------------------------------------------
revno: 3445
revision-id: igor at askmonty.org-20130806203138-rd74u51dkb96al1c
parent: psergey at askmonty.org-20121011030144-ddej9ug9vql7tgsw
committer: Igor Babaev <igor at askmonty.org>
branch nick: maria-10.0-mdev3814
timestamp: Tue 2013-08-06 13:31:38 -0700
message:
  MWL#205 DELETE with result set (mdev-3814)
  Includes all post-review fixes as well. 
-------------- next part --------------
=== added file 'mysql-test/r/delete_returning.result'
--- a/mysql-test/r/delete_returning.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/delete_returning.result	2013-08-06 20:31:38 +0000
@@ -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 at localhost;
+GRANT SELECT(b) ON mysqltest.t1 TO mysqltest_1 at 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 at 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 at 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 at 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 at localhost;
+DROP VIEW v1;
+DROP TABLE t1,t2;
+DROP TABLE t1c,t2c;

=== added file 'mysql-test/t/delete_returning.test'
--- a/mysql-test/t/delete_returning.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/delete_returning.test	2013-08-06 20:31:38 +0000
@@ -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 at localhost;  
+
+GRANT SELECT(b) ON mysqltest.t1 TO mysqltest_1 at 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 at 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 at 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 at 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 at localhost;
+
+# Cleanup
+DROP VIEW v1;
+DROP TABLE t1,t2;
+DROP TABLE t1c,t2c;
+
+

=== modified file 'sql/lex.h'
--- a/sql/lex.h	2012-10-02 22:44:54 +0000
+++ b/sql/lex.h	2013-08-06 20:31:38 +0000
@@ -480,6 +480,7 @@
   { "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)},

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2012-10-06 07:30:52 +0000
+++ b/sql/sql_class.cc	2013-08-06 20:31:38 +0000
@@ -2281,7 +2281,8 @@
   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);

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2012-09-02 02:41:38 +0000
+++ b/sql/sql_delete.cc	2013-08-06 20:31:38 +0000
@@ -48,7 +48,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;
@@ -66,6 +67,7 @@
   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))
@@ -90,9 +92,12 @@
   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);
@@ -154,9 +159,9 @@
       - 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);
@@ -323,9 +328,16 @@
   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())
   {
@@ -343,6 +355,12 @@
         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++;
@@ -449,7 +467,10 @@
   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());
@@ -463,13 +484,16 @@
     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;
@@ -481,7 +505,10 @@
                                     &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);

=== modified file 'sql/sql_delete.h'
--- a/sql/sql_delete.h	2011-06-30 15:46:53 +0000
+++ b/sql/sql_delete.h	2013-08-06 20:31:38 +0000
@@ -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 */

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2012-10-06 07:30:52 +0000
+++ b/sql/sql_parse.cc	2013-08-06 20:31:38 +0000
@@ -3169,6 +3169,7 @@
   }
   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;
@@ -3176,9 +3177,13 @@
     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;
   }

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2012-10-06 07:30:52 +0000
+++ b/sql/sql_prepare.cc	2013-08-06 20:31:38 +0000
@@ -1451,7 +1451,10 @@
     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);
 }

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2012-10-06 07:30:52 +0000
+++ b/sql/sql_yacc.yy	2013-08-06 20:31:38 +0000
@@ -1256,6 +1256,7 @@
 %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 */
@@ -11212,6 +11213,7 @@
           }
           where_clause opt_order_clause
           delete_limit_clause {}
+          opt_select_expressions {}
         | table_wild_list
           {
             mysql_init_multi_delete(Lex);
@@ -11236,6 +11238,11 @@
           }
         ;
 
+opt_select_expressions:
+          /* empty */ 
+        | RETURNING_SYM select_item_list 
+        ;
+
 table_wild_list:
           table_wild_one
         | table_wild_list ',' table_wild_one



More information about the commits mailing list