← Back to team overview

maria-developers team mailing list archive

Please review MDEV-10030 sql_yacc.yy: Split table_expression and remove PROCEDURE from create_select, select_paren_derived, select_derived2, query_specification

 

Hi Sergei,

Please review a patch for MDEV-10030, which is a part of
MDEV-8909 union parser cleanup.

Thanks!

commit 0f4f2e3b5ebabce1308c45772785aec084092674
Author: Alexander Barkov <bar@xxxxxxxxxxx>
Date:   Thu May 5 12:29:36 2016 +0400

    MDEV-10030 sql_yacc.yy: Split table_expression and remove PROCEDURE from create_select, select_paren_derived, select_derived2, query_specification
    
    This change refactors the "table_expression" rule in sql_yacc.yy.
    
    Queries with subselects and derived tables, as well as "CREATE TABLE ... SELECT"
    now return syntax error instead of "Incorrect usage of PROCEDURE and ...".

diff --git a/mysql-test/r/func_analyse.result b/mysql-test/r/func_analyse.result
index 2c30055..bc8ec44 100644
--- a/mysql-test/r/func_analyse.result
+++ b/mysql-test/r/func_analyse.result
@@ -19,7 +19,7 @@ test.t1.empty_string			0	0	4	0	0.0000	NULL	CHAR(0) NOT NULL
 test.t1.bool	N	Y	1	1	0	0	1.0000	NULL	ENUM('N','Y') NOT NULL
 test.t1.d	2002-03-03	2002-03-05	10	10	0	0	10.0000	NULL	ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL
 create table t2 select * from t1 procedure analyse();
-ERROR HY000: Incorrect usage of PROCEDURE and non-SELECT
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'procedure analyse()' at line 1
 drop table t1;
 EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE();
 ERROR HY000: Incorrect usage of PROCEDURE and subquery
@@ -120,7 +120,7 @@ CREATE TABLE t1(a INT);
 INSERT INTO t1 VALUES (1),(2);
 # should not crash
 CREATE TABLE t2 SELECT 1 FROM t1, t1 t3 GROUP BY t3.a PROCEDURE ANALYSE();
-ERROR HY000: Incorrect usage of PROCEDURE and non-SELECT
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE()' at line 1
 DROP TABLE t1;
 End of 5.0 tests
 #
@@ -149,3 +149,25 @@ Field_name	Min_value	Max_value	Min_length	Max_length	Empties_or_zeros	Nulls	Avg_
 test.t2.f2	1	1	1	1	0	0	1.0000	0.0000	ENUM('1') NOT NULL
 DROP TABLE t1, t2;
 End of 5.1 tests
+#
+# Start of 10.2 tests
+#
+(SELECT 1 FROM DUAL PROCEDURE ANALYSE());
+Field_name	Min_value	Max_value	Min_length	Max_length	Empties_or_zeros	Nulls	Avg_value_or_avg_length	Std	Optimal_fieldtype
+1	1	1	1	1	0	0	1.0000	0.0000	ENUM('1') NOT NULL
+((SELECT 1 FROM DUAL PROCEDURE ANALYSE()));
+Field_name	Min_value	Max_value	Min_length	Max_length	Empties_or_zeros	Nulls	Avg_value_or_avg_length	Std	Optimal_fieldtype
+1	1	1	1	1	0	0	1.0000	0.0000	ENUM('1') NOT NULL
+SELECT * FROM t1 UNION SELECT * FROM t1 PROCEDURE analyse();
+ERROR HY000: Incorrect usage of PROCEDURE and subquery
+#
+# MDEV-10030 sql_yacc.yy: Split table_expression and remove PROCEDURE from create_select, select_paren_derived, select_derived2, query_specification
+#
+SELECT * FROM (SELECT * FROM t1 PROCEDURE ANALYSE());
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE())' at line 1
+SELECT * FROM t1 NATURAL JOIN (SELECT * FROM t2 PROCEDURE ANALYSE());
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE())' at line 1
+SELECT (SELECT 1 FROM t1 PROCEDURE ANALYSE()) FROM t2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE()) FROM t2' at line 1
+SELECT ((SELECT 1 FROM t1 PROCEDURE ANALYSE())) FROM t2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE())) FROM t2' at line 1
diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result
index 01cc9d7..18a8e13 100644
--- a/mysql-test/r/parser.result
+++ b/mysql-test/r/parser.result
@@ -686,7 +686,7 @@ FOR UPDATE) a;
 SELECT 1 FROM
 (SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
 PROCEDURE ANALYSE() FOR UPDATE) a;
-ERROR HY000: Incorrect usage of PROCEDURE and subquery
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE() FOR UPDATE) a' at line 3
 SELECT 1 FROM t1
 WHERE EXISTS(SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
 FOR UPDATE);
@@ -694,7 +694,7 @@ FOR UPDATE);
 SELECT 1 FROM t1
 WHERE EXISTS(SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
 PROCEDURE ANALYSE() FOR UPDATE);
-ERROR HY000: Incorrect usage of PROCEDURE and subquery
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE() FOR UPDATE)' at line 3
 SELECT 1 FROM t1
 UNION
 SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index b306965..1b11989 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -79,7 +79,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a));
 1
 1
 select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1));
-ERROR HY000: Incorrect usage of PROCEDURE and subquery
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE(1))' at line 1
 SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1));
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 1))' at line 1
 SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL;
diff --git a/mysql-test/r/subselect_no_exists_to_in.result b/mysql-test/r/subselect_no_exists_to_in.result
index 244f605..39d1f64 100644
--- a/mysql-test/r/subselect_no_exists_to_in.result
+++ b/mysql-test/r/subselect_no_exists_to_in.result
@@ -83,7 +83,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a));
 1
 1
 select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1));
-ERROR HY000: Incorrect usage of PROCEDURE and subquery
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE(1))' at line 1
 SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1));
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 1))' at line 1
 SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL;
diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result
index e095ed1..211d320 100644
--- a/mysql-test/r/subselect_no_mat.result
+++ b/mysql-test/r/subselect_no_mat.result
@@ -86,7 +86,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a));
 1
 1
 select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1));
-ERROR HY000: Incorrect usage of PROCEDURE and subquery
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE(1))' at line 1
 SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1));
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 1))' at line 1
 SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL;
diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result
index f471452..6ae9f8a 100644
--- a/mysql-test/r/subselect_no_opts.result
+++ b/mysql-test/r/subselect_no_opts.result
@@ -82,7 +82,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a));
 1
 1
 select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1));
-ERROR HY000: Incorrect usage of PROCEDURE and subquery
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE(1))' at line 1
 SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1));
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 1))' at line 1
 SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL;
diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result
index 5ead5de..9a3fcd1 100644
--- a/mysql-test/r/subselect_no_scache.result
+++ b/mysql-test/r/subselect_no_scache.result
@@ -85,7 +85,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a));
 1
 1
 select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1));
-ERROR HY000: Incorrect usage of PROCEDURE and subquery
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE(1))' at line 1
 SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1));
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 1))' at line 1
 SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL;
diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result
index c57c46b..10cf056 100644
--- a/mysql-test/r/subselect_no_semijoin.result
+++ b/mysql-test/r/subselect_no_semijoin.result
@@ -82,7 +82,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a));
 1
 1
 select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1));
-ERROR HY000: Incorrect usage of PROCEDURE and subquery
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE(1))' at line 1
 SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1));
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 1))' at line 1
 SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL;
diff --git a/mysql-test/t/func_analyse.test b/mysql-test/t/func_analyse.test
index c77967a..6c30c0c 100644
--- a/mysql-test/t/func_analyse.test
+++ b/mysql-test/t/func_analyse.test
@@ -11,7 +11,7 @@ insert into t1 values (1,2,"","Y","2002-03-03"), (3,4,"","N","2002-03-04"), (5,6
 select count(*) from t1 procedure analyse();
 select * from t1 procedure analyse();
 select * from t1 procedure analyse(2);
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 create table t2 select * from t1 procedure analyse();
 drop table t1;
 
@@ -127,7 +127,7 @@ CREATE TABLE t1(a INT);
 INSERT INTO t1 VALUES (1),(2);
 
 --echo # should not crash
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 CREATE TABLE t2 SELECT 1 FROM t1, t1 t3 GROUP BY t3.a PROCEDURE ANALYSE();
 
 DROP TABLE t1;
@@ -157,3 +157,27 @@ SELECT * FROM t2 LIMIT 1 PROCEDURE ANALYSE();
 DROP TABLE t1, t2;
 
 --echo End of 5.1 tests
+
+--echo #
+--echo # Start of 10.2 tests
+--echo #
+(SELECT 1 FROM DUAL PROCEDURE ANALYSE());
+((SELECT 1 FROM DUAL PROCEDURE ANALYSE()));
+
+# TODO:
+--error ER_WRONG_USAGE
+SELECT * FROM t1 UNION SELECT * FROM t1 PROCEDURE analyse();
+
+--echo #
+--echo # MDEV-10030 sql_yacc.yy: Split table_expression and remove PROCEDURE from create_select, select_paren_derived, select_derived2, query_specification
+--echo #
+
+--error ER_PARSE_ERROR
+SELECT * FROM (SELECT * FROM t1 PROCEDURE ANALYSE());
+--ERROR ER_PARSE_ERROR
+SELECT * FROM t1 NATURAL JOIN (SELECT * FROM t2 PROCEDURE ANALYSE());
+
+--error ER_PARSE_ERROR
+SELECT (SELECT 1 FROM t1 PROCEDURE ANALYSE()) FROM t2;
+--error ER_PARSE_ERROR
+SELECT ((SELECT 1 FROM t1 PROCEDURE ANALYSE())) FROM t2;
diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test
index 0a19b03..86cc3c4 100644
--- a/mysql-test/t/parser.test
+++ b/mysql-test/t/parser.test
@@ -806,7 +806,7 @@ SELECT 1 FROM
   (SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
    FOR UPDATE) a;
 
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 SELECT 1 FROM
   (SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
    PROCEDURE ANALYSE() FOR UPDATE) a;
@@ -815,7 +815,7 @@ SELECT 1 FROM t1
   WHERE EXISTS(SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
                FOR UPDATE);
 
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 SELECT 1 FROM t1
   WHERE EXISTS(SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
                PROCEDURE ANALYSE() FOR UPDATE);
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 7a7c01e..5313a4b 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -51,7 +51,7 @@ SELECT * FROM (SELECT 1 as id) b WHERE id IN (SELECT * FROM (SELECT 1 as id) c O
 SELECT * FROM (SELECT 1) a  WHERE 1 IN (SELECT 1,1);
 SELECT 1 IN (SELECT 1);
 SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a));
--- error ER_WRONG_USAGE
+-- error ER_PARSE_ERROR
 select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1));
 -- error ER_PARSE_ERROR
 SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1));
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index a6bbfc8..0d8bfb3 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -988,6 +988,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
     }
     if (thd->lex->derived_tables)
     {
+      // SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE()
       my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", 
                thd->lex->derived_tables & DERIVED_VIEW ?
                "view" : "subquery"); 
@@ -995,6 +996,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
     }
     if (thd->lex->sql_command != SQLCOM_SELECT)
     {
+      // EXPLAIN SELECT * FROM t1 PROCEDURE ANALYSE()
       my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "non-SELECT");
       goto err;
     }
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 5e1f5dc..445f986 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1037,10 +1037,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
 %parse-param { THD *thd }
 %lex-param { THD *thd }
 /*
-  Currently there are 124 shift/reduce conflicts.
+  Currently there are 123 shift/reduce conflicts.
   We should not introduce new conflicts any more.
 */
-%expect 124
+%expect 123
 
 /*
    Comments for TOKENS.
@@ -5695,7 +5695,10 @@ create_select:
           {
             Select->parsing_place= NO_MATTER;
           }
-          table_expression
+          opt_table_expression
+          opt_order_clause
+          opt_limit_clause
+          opt_select_lock_type
           {
             /*
               The following work only with the local list, the global list
@@ -8535,7 +8538,10 @@ select_paren_derived:
             Lex->current_select->set_braces(true);
           }
           SELECT_SYM select_part2_derived
-          table_expression
+          opt_table_expression
+          opt_order_clause
+          opt_limit_clause
+          opt_select_lock_type
           {
             if (setup_select_in_parentheses(Lex))
               MYSQL_YYABORT;
@@ -8566,24 +8572,20 @@ select_part2:
         | select_options_and_item_list into opt_select_lock_type
         | select_options_and_item_list
           opt_into
-          from_clause
-          opt_where_clause
-          opt_group_clause
-          opt_having_clause
-          opt_window_clause
+          table_expression
           opt_order_clause
           opt_limit_clause
           opt_procedure_clause
           opt_into
           opt_select_lock_type
           {
-            if ($2 && $11)
+            if ($2 && $7)
             {
               /* double "INTO" clause */
               my_error(ER_WRONG_USAGE, MYF(0), "INTO", "INTO");
               MYSQL_YYABORT;
             }
-            if ($10 && ($2 || $11))
+            if ($6 && ($2 || $7))
             {
               /* "INTO" with "PROCEDURE ANALYSE" */
               my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "INTO");
@@ -8606,25 +8608,25 @@ select_options_and_item_list:
           }
         ;
 
+
+/**
+  <table expression>, as in the SQL standard.
+*/
 table_expression:
-          opt_from_clause
+          from_clause
           opt_where_clause
           opt_group_clause
           opt_having_clause
           opt_window_clause
-          opt_order_clause
-          opt_limit_clause
-          opt_procedure_clause
-          opt_select_lock_type
         ;
 
-from_clause:
-          FROM table_reference_list
+opt_table_expression:
+            /* Empty */
+          | table_expression
         ;
 
-opt_from_clause:
-          /* empty */
-        | from_clause
+from_clause:
+          FROM table_reference_list
         ;
 
 table_reference_list:
@@ -11208,7 +11210,10 @@ select_derived2:
           {
             Select->parsing_place= NO_MATTER;
           }
-          table_expression
+          opt_table_expression
+          opt_order_clause
+          opt_limit_clause
+          opt_select_lock_type
         ;
 
 get_select_lex:
@@ -11946,9 +11951,11 @@ opt_procedure_clause:
 
             if (&lex->select_lex != lex->current_select)
             {
+              // SELECT * FROM t1 UNION SELECT * FROM t2 PROCEDURE ANALYSE();
               my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery");
               MYSQL_YYABORT;
             }
+
             lex->proc_list.elements=0;
             lex->proc_list.first=0;
             lex->proc_list.next= &lex->proc_list.first;
@@ -16359,7 +16366,10 @@ union_option:
 
 query_specification:
           SELECT_SYM select_init2_derived
-          table_expression
+          opt_table_expression
+          opt_order_clause
+          opt_limit_clause
+          opt_select_lock_type
           {
             $$= Lex->current_select->master_unit()->first_select();
           }

Follow ups