← Back to team overview

maria-developers team mailing list archive

Re: Fwd: [Commits] b32031991e4: initial oracle parser fix

 

Hello Sanja, Igor,


This patch removes a lot of main_select_push() / pop_select() that
you had to add into *.yy files in the 10.3-MDEV-11953 branch.

The patch does the following:
- Disallows creation of Item_field in the select stack is empty.
  An error is returned instead (ER_BAD_FIELD_ERROR).
  The point is that Item_field requires a Name_resolution_context,
  which is not available with the empty select stack.
  This additionally fixed the problem reported in:
  MDEV-14347 CREATE PROCEDURE returns no error when using an unknown
variable

- Disallows creation of Item_sum and Item_windowfunc the same way,
  as they also need a Name_resolution_context.
  It fixed the second part of MDEV-14347, about aggregate and window
functions.
  It also fixed:
  MDEV-15870 Using aggregate and window function in unexpected places
can crash the server
  (repeatable since 10.2)

- Adds FOR_LOOP_BOUND into enum_parsing_place, to force creation of a
temporary
  Item_field when inside a FOR loop:
     FOR x IN ident
  If the "ident" is later resolves to a cursor name,
  then the loop is treated as "explicit cursor FOR loop", otherwise
  it's a normal field name and therefore the same error (ER_BAD_FIELD_ERROR)
  is returned.

- Adds a new method LEX::create_item_query_expression()
  to reuse the same code in sql_yacc.yy and sql_yacc_ora.yy.
  Adds a test for curr_sel, in case of NULL resets curr_sel
  to &lex->builtin_select.

- Adds tests to cover IN and EXISTS subselects in various query parts.
  This was very weakly covered. While working on this patch I had problems
  with IN and EXISTS subselects, so I had to cover them.

- Adds a function relink_hack() to properly bind st_select_lex containing
  an IN/EXISTS subselect to thd->lex->builtin_select. This is needed for
  the cases when the statement does not do main_select_push().
  I does not know this code well, so you can fine a better solution.
  Please suggest.


I propose the following plan:

1. Move tests for IN/EXISTS from this patch just to 10.3
   and rebase your branch.

2. Please review the remaining main_select_push()/pop_select().

  Note, these rules must have push/pop for sure,
  as they need Item_field as a part of their syntax:

    insert:
    update:
    delete:
    show:
    handler:

  But some of push/pop pairs should also be further removed:

    - Some rules can probably assume (and assert) that the select stack
is not
      empty, as the parent rule must have pushed an entry earlier:
        partition_entry:
        parse_vcol_expr:
        single_multi:

    - Non-TABLE related entries in:
        create:
        alter:
      cannot use Item_field (e.g CREATE DATABASE or ALTER DATABASE),
      so push/pop can be removed.

    - I'm not sure about
        load:
        set:
      I can study these separately (if we generally agree on the plan).


3. Move the part of the patch fixing MDEV-15870 and MDEV-14347 to 10.4,
   so then you rebase on top of it.
   Alternatively, just keep MDEV-15870 and MDEV-14347
   as a part of 10.3-MDEV-11953. Please decide.




On 04/10/2018 03:37 PM, Oleksandr Byelkin wrote:
> Am 10.04.2018 um 10:58 schrieb Alexander Barkov:
>>    Hello Sanja,
>>
>>
>> I reviewed your recent changes in "10.3-MDEV-11953"
>> (and the attached additional patch for sql_yacc_ora.yy)
>>
>> I have some proposals:
>>
>>
>>
>> 1. Can you please move huge pieces of the code from sql_yacc.yy to LEX
>> or other relevant classes?
>>
>> It makes the grammar much more readable (patches are aslo much more
>> readable).
>>
>> I'd move the relevant pieces of the code to LEX as a separate patch,
>> even before fixing the grammar.
> OK
>>
>> 2. You're adding too many main_select_push() and pop_select().
>> Please move them to upper level rules (it should be possible in many
>> cases).
> Impossible
>>
>> Add new helper rules when needed.
>> For example, this piece of code repeats many times:
>>
>> +          {
>> +            if (Lex->main_select_push())
>> +              MYSQL_YYABORT;
>> +          }
>> +          expr
>> +          {
>> +            Lex->pop_select(); //main select
>> +            $$= $3;
>>
>> It deserved a rule, say, expr_with_select_push_pop.
>> You can find a better name :)
>>
> OK
>> - Serg and I spent a lot of time working on this task:
>>    MDEV-8909 union parser cleanup
>>    (and its 13 dependency tasks, and 3 related tasks,
>>     see the "Issue links" section in MDEV).
>>
>> We think that it should be the parser who disallows bad grammar, instead
>> of post-analysis with raising errors like
>> ER_CANT_USE_OPTION_HERE.
>> Please keep using the same approach.
> The task did not made parser recognizing brackets, and I have no ideas
> how to return parser errors when all SELECT parsed in the same way in
> difference from the previous parser which could recognize only one level
> of SELECTs.
>> Thanks!
>>
> [skip]
diff --git a/mysql-test/main/get_diagnostics.result b/mysql-test/main/get_diagnostics.result
index 732be7c..6944103 100644
--- a/mysql-test/main/get_diagnostics.result
+++ b/mysql-test/main/get_diagnostics.result
@@ -133,7 +133,7 @@ DROP PROCEDURE p1;
 GET DIAGNOSTICS CONDITION;
 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 '' at line 1
 GET DIAGNOSTICS CONDITION a;
-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 '' at line 1
+ERROR 42S22: Unknown column 'a' in 'field list'
 GET DIAGNOSTICS CONDITION 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 '' at line 1
 GET DIAGNOSTICS CONDITION 1 @var;
@@ -212,9 +212,9 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
 GET DIAGNOSTICS CONDITION (1) @var = CLASS_ORIGIN;
 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 '(1) @var = CLASS_ORIGIN' at line 1
 GET DIAGNOSTICS CONDITION p1() @var = CLASS_ORIGIN;
-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 '() @var = CLASS_ORIGIN' at line 1
+ERROR 42S22: Unknown column 'p1' in 'field list'
 GET DIAGNOSTICS CONDITION ABS(2) @var = CLASS_ORIGIN;
-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 '(2) @var = CLASS_ORIGIN' at line 1
+ERROR 42S22: Unknown column 'ABS' in 'field list'
 GET DIAGNOSTICS CONDITION 1.1 @var = CLASS_ORIGIN;
 GET DIAGNOSTICS CONDITION "1" @var = CLASS_ORIGIN;
 SELECT COUNT(max_questions) INTO @var FROM mysql.user;
@@ -226,10 +226,7 @@ Warnings:
 Error	1758	Invalid condition number
 Error	1758	Invalid condition number
 GET DIAGNOSTICS CONDITION a @var = CLASS_ORIGIN;
-Warnings:
-Error	1758	Invalid condition number
-Error	1758	Invalid condition number
-Error	1054	Unknown column 'a' in 'field list'
+ERROR 42S22: Unknown column 'a' in 'field list'
 SELECT COUNT(max_questions) INTO @var FROM mysql.user;
 SET @cond = 1;
 GET DIAGNOSTICS CONDITION @cond @var1 = CLASS_ORIGIN;
diff --git a/mysql-test/main/get_diagnostics.test b/mysql-test/main/get_diagnostics.test
index a30bad7..1553eb5 100644
--- a/mysql-test/main/get_diagnostics.test
+++ b/mysql-test/main/get_diagnostics.test
@@ -169,7 +169,7 @@ DROP PROCEDURE p1;
 
 --error ER_PARSE_ERROR
 GET DIAGNOSTICS CONDITION;
---error ER_PARSE_ERROR
+--error ER_BAD_FIELD_ERROR
 GET DIAGNOSTICS CONDITION a;
 --error ER_PARSE_ERROR
 GET DIAGNOSTICS CONDITION 1;
@@ -271,9 +271,9 @@ GET DIAGNOSTICS CONDITION 1+1 @var = CLASS_ORIGIN;
 GET DIAGNOSTICS CONDITION ? @var = CLASS_ORIGIN;
 --error ER_PARSE_ERROR
 GET DIAGNOSTICS CONDITION (1) @var = CLASS_ORIGIN;
---error ER_PARSE_ERROR
+--error ER_BAD_FIELD_ERROR
 GET DIAGNOSTICS CONDITION p1() @var = CLASS_ORIGIN;
---error ER_PARSE_ERROR
+--error ER_BAD_FIELD_ERROR
 GET DIAGNOSTICS CONDITION ABS(2) @var = CLASS_ORIGIN;
 
 # Unfortunate side effects...
@@ -285,6 +285,7 @@ SELECT COUNT(max_questions) INTO @var FROM mysql.user;
 
 GET DIAGNOSTICS CONDITION 9999 @var = CLASS_ORIGIN;
 GET DIAGNOSTICS CONDITION NULL @var = CLASS_ORIGIN;
+--error ER_BAD_FIELD_ERROR
 GET DIAGNOSTICS CONDITION a @var = CLASS_ORIGIN;
 
 # Reset warnings
diff --git a/mysql-test/main/mysqldump.result b/mysql-test/main/mysqldump.result
index a1e206d..7034a7b 100644
--- a/mysql-test/main/mysqldump.result
+++ b/mysql-test/main/mysqldump.result
@@ -5153,7 +5153,7 @@ USE BUG52792;
 SET NAMES utf8;
 CREATE FUNCTION `straße` ( c1 CHAR(20))
 RETURNS CHAR(50) DETERMINISTIC
-RETURN CONCAT(']]>, ', s, '!');
+RETURN CONCAT(']]>, ', c1, '!');
 <?xml version="1.0"?>
 <mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";>
 <database name="BUG52792">
@@ -5162,7 +5162,7 @@ RETURN CONCAT(']]>, ', s, '!');
 <![CDATA[
 CREATE DEFINER=`root`@`localhost` FUNCTION `straße`( c1 CHAR(20)) RETURNS char(50) CHARSET latin1
     DETERMINISTIC
-RETURN CONCAT(']]]]><![CDATA[>, ', s, '!')
+RETURN CONCAT(']]]]><![CDATA[>, ', c1, '!')
 ]]>
 		</routine>
 	</routines>
diff --git a/mysql-test/main/mysqldump.test b/mysql-test/main/mysqldump.test
index 6dde5aa..05aabcc 100644
--- a/mysql-test/main/mysqldump.test
+++ b/mysql-test/main/mysqldump.test
@@ -2351,7 +2351,7 @@ USE BUG52792;
 SET NAMES utf8;
 CREATE FUNCTION `straße` ( c1 CHAR(20))
   RETURNS CHAR(50) DETERMINISTIC
-RETURN CONCAT(']]>, ', s, '!');
+RETURN CONCAT(']]>, ', c1, '!');
 
 --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=utf8 --compatible=mysql323 -R -X BUG52792
 
diff --git a/mysql-test/main/signal.result b/mysql-test/main/signal.result
index 905842b..a37e25e 100644
--- a/mysql-test/main/signal.result
+++ b/mysql-test/main/signal.result
@@ -2285,17 +2285,13 @@ begin
 DECLARE foo CONDITION FOR SQLSTATE '12345';
 SIGNAL foo SET MYSQL_ERRNO = `65`; /* illegal */
 end $$
-call test_signal $$
 ERROR 42S22: Unknown column '65' in 'field list'
-drop procedure test_signal $$
 create procedure test_signal()
 begin
 DECLARE foo CONDITION FOR SQLSTATE '12345';
 SIGNAL foo SET MYSQL_ERRNO = `A`; /* illegal */
 end $$
-call test_signal $$
 ERROR 42S22: Unknown column 'A' in 'field list'
-drop procedure test_signal $$
 create procedure test_signal()
 begin
 DECLARE foo CONDITION FOR SQLSTATE '12345';
@@ -2346,9 +2342,7 @@ DECLARE foo CONDITION FOR SQLSTATE '12345';
 SIGNAL foo SET MYSQL_ERRNO = 1000,
 MESSAGE_TEXT = `Hello`;
 end $$
-call test_signal $$
 ERROR 42S22: Unknown column 'Hello' in 'field list'
-drop procedure test_signal $$
 create procedure test_signal()
 begin
 DECLARE foo CONDITION FOR SQLSTATE '12345';
diff --git a/mysql-test/main/signal.test b/mysql-test/main/signal.test
index cdb5796..54c6107 100644
--- a/mysql-test/main/signal.test
+++ b/mysql-test/main/signal.test
@@ -2546,25 +2546,21 @@ end $$
 call test_signal $$
 drop procedure test_signal $$
 
+-- error ER_BAD_FIELD_ERROR
 create procedure test_signal()
 begin
   DECLARE foo CONDITION FOR SQLSTATE '12345';
   SIGNAL foo SET MYSQL_ERRNO = `65`; /* illegal */
 end $$
 
--- error ER_BAD_FIELD_ERROR
-call test_signal $$
-drop procedure test_signal $$
 
+-- error ER_BAD_FIELD_ERROR
 create procedure test_signal()
 begin
   DECLARE foo CONDITION FOR SQLSTATE '12345';
   SIGNAL foo SET MYSQL_ERRNO = `A`; /* illegal */
 end $$
 
--- error ER_BAD_FIELD_ERROR
-call test_signal $$
-drop procedure test_signal $$
 
 create procedure test_signal()
 begin
@@ -2620,6 +2616,7 @@ end $$
 call test_signal $$
 drop procedure test_signal $$
 
+-- error ER_BAD_FIELD_ERROR
 create procedure test_signal()
 begin
   DECLARE foo CONDITION FOR SQLSTATE '12345';
@@ -2627,10 +2624,6 @@ begin
     MESSAGE_TEXT = `Hello`;
 end $$
 
--- error ER_BAD_FIELD_ERROR
-call test_signal $$
-drop procedure test_signal $$
-
 create procedure test_signal()
 begin
   DECLARE foo CONDITION FOR SQLSTATE '12345';
diff --git a/mysql-test/main/sp-error.result b/mysql-test/main/sp-error.result
index de4c4cf..cf74e6c 100644
--- a/mysql-test/main/sp-error.result
+++ b/mysql-test/main/sp-error.result
@@ -439,6 +439,9 @@ create procedure nodb.bug3339() begin end|
 ERROR 42000: Unknown database 'nodb'
 create procedure bug2653_1(a int, out b int)
 set b = aa|
+call bug2653_1(1, @b)|
+ERROR 42S22: Unknown column 'aa' in 'field list'
+drop procedure bug2653_1|
 create procedure bug2653_2(a int, out b int)
 begin
 if aa < 0 then
@@ -447,12 +450,7 @@ else
 set b = a;
 end if;
 end|
-call bug2653_1(1, @b)|
-ERROR 42S22: Unknown column 'aa' in 'field list'
-call bug2653_2(2, @b)|
 ERROR 42S22: Unknown column 'aa' in 'field list'
-drop procedure bug2653_1|
-drop procedure bug2653_2|
 create procedure bug4344() drop procedure bug4344|
 ERROR HY000: Can't drop or alter a PROCEDURE from within another stored routine
 create procedure bug4344() drop function bug4344|
@@ -1067,6 +1065,7 @@ IF bug13037_foo THEN
 SELECT 1;
 END IF;
 END|
+ERROR 42S22: Unknown column 'bug13037_foo' in 'field list'
 CREATE PROCEDURE bug13037_p2()
 BEGIN
 SET @bug13037_foo = bug13037_bar;
@@ -1076,19 +1075,14 @@ BEGIN
 SELECT bug13037_foo;
 END|
 
-CALL bug13037_p1();
-ERROR 42S22: Unknown column 'bug13037_foo' in 'field list'
 CALL bug13037_p2();
 ERROR 42S22: Unknown column 'bug13037_bar' in 'field list'
 CALL bug13037_p3();
 ERROR 42S22: Unknown column 'bug13037_foo' in 'field list'
-CALL bug13037_p1();
-ERROR 42S22: Unknown column 'bug13037_foo' in 'field list'
 CALL bug13037_p2();
 ERROR 42S22: Unknown column 'bug13037_bar' in 'field list'
 CALL bug13037_p3();
 ERROR 42S22: Unknown column 'bug13037_foo' in 'field list'
-DROP PROCEDURE bug13037_p1;
 DROP PROCEDURE bug13037_p2;
 DROP PROCEDURE bug13037_p3;
 create database mysqltest1;
diff --git a/mysql-test/main/sp-error.test b/mysql-test/main/sp-error.test
index 88d9809..e2adea8 100644
--- a/mysql-test/main/sp-error.test
+++ b/mysql-test/main/sp-error.test
@@ -608,6 +608,12 @@ create procedure nodb.bug3339() begin end|
 create procedure bug2653_1(a int, out b int)
   set b = aa|
 
+--error ER_BAD_FIELD_ERROR
+call bug2653_1(1, @b)|
+
+drop procedure bug2653_1|
+
+--error ER_BAD_FIELD_ERROR
 create procedure bug2653_2(a int, out b int)
 begin
   if aa < 0 then
@@ -617,13 +623,6 @@ begin
   end if;
 end|
 
---error 1054
-call bug2653_1(1, @b)|
---error 1054
-call bug2653_2(2, @b)|
-
-drop procedure bug2653_1|
-drop procedure bug2653_2|
 
 #
 # BUG#4344
@@ -1507,6 +1506,7 @@ DROP PROCEDURE IF EXISTS bug13037_p3;
 
 delimiter |;
 
+--error ER_BAD_FIELD_ERROR
 CREATE PROCEDURE bug13037_p1()
 BEGIN
   IF bug13037_foo THEN
@@ -1529,20 +1529,15 @@ delimiter ;|
 --echo
 
 --error 1054
-CALL bug13037_p1();
---error 1054
 CALL bug13037_p2();
 --error 1054
 CALL bug13037_p3();
 
 --error 1054
-CALL bug13037_p1();
---error 1054
 CALL bug13037_p2();
 --error 1054
 CALL bug13037_p3();
 
-DROP PROCEDURE bug13037_p1;
 DROP PROCEDURE bug13037_p2;
 DROP PROCEDURE bug13037_p3;
 
diff --git a/mysql-test/main/sp-expr.result b/mysql-test/main/sp-expr.result
new file mode 100644
index 0000000..3b4efb2e
--- /dev/null
+++ b/mysql-test/main/sp-expr.result
@@ -0,0 +1,574 @@
+#
+# Start of 10.4 tests
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+BEGIN NOT ATOMIC
+CASE ((1) IN (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+CASE (EXISTS (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+IF ((1) IN (SELECT a FROM t1)) THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+IF (EXISTS (SELECT a FROM t1)) THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+WHILE ((1234) IN (SELECT * FROM t1)) DO
+SELECT 1;
+END WHILE;
+END;
+$$
+BEGIN NOT ATOMIC
+WHILE (EXISTS (SELECT * FROM t1 WHERE a=1234)) DO
+SELECT 1;
+END WHILE;
+END;
+$$
+BEGIN NOT ATOMIC
+REPEAT
+SELECT 1;
+UNTIL (1 IN (SELECT * FROM t1))
+END REPEAT;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+REPEAT
+SELECT 1;
+UNTIL EXISTS (SELECT * FROM t1 WHERE a=1)
+END REPEAT;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+FOR i IN 0..(1 IN (SELECT * FROM t1))
+DO
+SELECT i;
+END FOR;
+END;
+$$
+i
+0
+i
+1
+BEGIN NOT ATOMIC
+FOR i IN 0..EXISTS (SELECT * FROM t1 WHERE a=1)
+DO
+SELECT i;
+END FOR;
+END;
+$$
+i
+0
+i
+1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT ((10) IN (SELECT * FROM t1));
+SELECT a;
+END;
+$$
+a
+1
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT EXISTS (SELECT * FROM t1);
+SELECT a;
+END;
+$$
+a
+1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+CREATE FUNCTION f1() RETURNS INT
+BEGIN
+RETURN ((1) IN (SELECT * FROM t1));
+END;
+$$
+CREATE FUNCTION f2() RETURNS INT
+BEGIN
+RETURN EXISTS (SELECT * FROM t1 WHERE a=1);
+END;
+$$
+SELECT f1();
+f1()
+1
+SELECT f2();
+f2()
+1
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+BEGIN NOT ATOMIC
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(1 IN (SELECT * FROM t1));
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+va
+2
+BEGIN NOT ATOMIC
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(EXISTS (SELECT * FROM t1));
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+va
+2
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+CREATE PROCEDURE p1()
+BEGIN
+CASE unknown_identifier WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+CASE unknown_identifier.a WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+CASE unknown_identifier.a.b WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+CASE unknown_identifier.a.b.c WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+IF unknown_identifier THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+IF unknown_identifier.a THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+IF unknown_identifier.a.b THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+IF unknown_identifier.a.b.c THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+WHILE unknown_identifier DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+WHILE unknown_identifier.a DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+WHILE unknown_identifier.a.b DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+WHILE unknown_identifier.a.b.c DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a.b;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a.b.c;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN 0..unknown_identifier
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN 0..unknown_identifier.field1
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier.field1
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN 0..unknown_identifier.field1.field2
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: field1.field2
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN unknown_identifier..10
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN unknown_identifier.field1..10
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier.field1
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN unknown_identifier.field1.field2..10
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: field1.field2
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE a INT DEFAULT unknown_identifier;
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE a INT DEFAULT unknown_identifier.a;
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE a INT DEFAULT unknown_identifier.a.b;
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(unknown_identifier);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'ORDER clause'
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(unknown_identifier.a);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'ORDER clause'
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(unknown_identifier.a.b);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'ORDER clause'
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(unknown_identifier.a.b.c);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'ORDER clause'
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+# (testing aggregate functions)
+CREATE PROCEDURE p1()
+BEGIN
+CASE SUM(1) WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1()
+BEGIN
+IF SUM(1) THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1()
+BEGIN
+WHILE SUM(1) DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1()
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL SUM(1);
+END REPEAT;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN 0..SUM(1)
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN SUM(1)..10
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE a INT DEFAULT SUM(1);
+SELECT a;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE FUNCTION f1() RETURNS INT RETURN SUM(1);
+ERROR HY000: Invalid use of group function
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(SUM(1));
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR HY000: Invalid use of group function
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+# (testing window functions)
+CREATE PROCEDURE p1()
+BEGIN
+CASE ROW_NUMBER() OVER() WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1()
+BEGIN
+IF ROW_NUMBER() OVER() THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1()
+BEGIN
+WHILE ROW_NUMBER() OVER() DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1()
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL ROW_NUMBER() OVER();
+END REPEAT;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN 0..ROW_NUMBER() OVER()
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1()
+BEGIN
+FOR i IN ROW_NUMBER() OVER()..10
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE a INT DEFAULT ROW_NUMBER() OVER();
+SELECT a;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE FUNCTION f1() RETURNS INT RETURN ROW_NUMBER() OVER();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(ROW_NUMBER() OVER());
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+DROP TABLE t1;
diff --git a/mysql-test/main/sp-expr.test b/mysql-test/main/sp-expr.test
new file mode 100644
index 0000000..6c61e7a
--- /dev/null
+++ b/mysql-test/main/sp-expr.test
@@ -0,0 +1,804 @@
+# Testing expressions of different kinds in various parts of SP syntax
+
+--echo #
+--echo # Start of 10.4 tests
+--echo #
+
+#
+# Subselects in SP control structures
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+DELIMITER $$;
+
+BEGIN NOT ATOMIC
+  CASE ((1) IN (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+BEGIN NOT ATOMIC
+  CASE (EXISTS (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+BEGIN NOT ATOMIC
+  IF ((1) IN (SELECT a FROM t1)) THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+BEGIN NOT ATOMIC
+  IF (EXISTS (SELECT a FROM t1)) THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+BEGIN NOT ATOMIC
+  WHILE ((1234) IN (SELECT * FROM t1)) DO
+    SELECT 1;
+  END WHILE;
+END;
+$$
+BEGIN NOT ATOMIC
+  WHILE (EXISTS (SELECT * FROM t1 WHERE a=1234)) DO
+    SELECT 1;
+  END WHILE;
+END;
+$$
+
+BEGIN NOT ATOMIC
+  REPEAT
+    SELECT 1;
+  UNTIL (1 IN (SELECT * FROM t1))
+  END REPEAT;
+END;
+$$
+BEGIN NOT ATOMIC
+  REPEAT
+    SELECT 1;
+  UNTIL EXISTS (SELECT * FROM t1 WHERE a=1)
+  END REPEAT;
+END;
+$$
+
+BEGIN NOT ATOMIC
+  FOR i IN 0..(1 IN (SELECT * FROM t1))
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+BEGIN NOT ATOMIC
+  FOR i IN 0..EXISTS (SELECT * FROM t1 WHERE a=1)
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+#
+# Subselects as SP variable default values
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+BEGIN NOT ATOMIC
+  DECLARE a INT DEFAULT ((10) IN (SELECT * FROM t1));
+  SELECT a;
+END;
+$$
+BEGIN NOT ATOMIC
+  DECLARE a INT DEFAULT EXISTS (SELECT * FROM t1);
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+#
+# Subselects SP function return values
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+DELIMITER $$;
+CREATE FUNCTION f1() RETURNS INT
+BEGIN
+  RETURN ((1) IN (SELECT * FROM t1));
+END;
+$$
+CREATE FUNCTION f2() RETURNS INT
+BEGIN
+  RETURN EXISTS (SELECT * FROM t1 WHERE a=1);
+END;
+$$
+DELIMITER ;$$
+SELECT f1();
+SELECT f2();
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP TABLE t1;
+
+
+#
+# Subselects in CURSOR parameters
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DELIMITER $$;
+BEGIN NOT ATOMIC
+  DECLARE va INT;
+  DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+  OPEN cur(1 IN (SELECT * FROM t1));
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+BEGIN NOT ATOMIC
+  DECLARE va INT;
+  DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+  OPEN cur(EXISTS (SELECT * FROM t1));
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+--echo #
+
+#
+# Unknown identifiers in CASE SP control
+#
+
+DELIMITER $$;
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  CASE unknown_identifier WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  CASE unknown_identifier.a WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  CASE unknown_identifier.a.b WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  CASE unknown_identifier.a.b.c WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+
+#
+# Unknown identifier in IF
+#
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  IF unknown_identifier THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  IF unknown_identifier.a THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  IF unknown_identifier.a.b THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  IF unknown_identifier.a.b.c THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+
+#
+# Unknown identifier in WHILE
+#
+
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  WHILE unknown_identifier DO
+    SELECT 1;
+  END WHILE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  WHILE unknown_identifier.a DO
+    SELECT 1;
+  END WHILE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  WHILE unknown_identifier.a.b DO
+    SELECT 1;
+  END WHILE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  WHILE unknown_identifier.a.b.c DO
+    SELECT 1;
+  END WHILE;
+END;
+$$
+
+
+
+#
+# Unknown identifier in REPEAT
+#
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL unknown_identifier;
+  END REPEAT;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL unknown_identifier.a;
+  END REPEAT;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL unknown_identifier.a.b;
+  END REPEAT;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL unknown_identifier.a.b.c;
+  END REPEAT;
+END;
+$$
+
+
+#
+# Unknown identifier in FOR
+#
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN 0..unknown_identifier
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN 0..unknown_identifier.field1
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN 0..unknown_identifier.field1.field2
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN unknown_identifier..10
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN unknown_identifier.field1..10
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN unknown_identifier.field1.field2..10
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+DELIMITER ;$$
+
+
+#
+# Unknown identifiers as SP variable default values
+#
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE a INT DEFAULT unknown_identifier;
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE a INT DEFAULT unknown_identifier.a;
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE a INT DEFAULT unknown_identifier.a.b;
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+#
+# Unknown identifiers as SP function return values
+#
+
+--error ER_BAD_FIELD_ERROR
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier;
+
+--error ER_BAD_FIELD_ERROR
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a;
+
+--error ER_BAD_FIELD_ERROR
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a.b;
+
+--error ER_BAD_FIELD_ERROR
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a.b.c;
+
+
+#
+# Unknown identifiers in CURSOR parameters
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DELIMITER $$;
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE va INT;
+  DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+  OPEN cur(unknown_identifier);
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE va INT;
+  DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+  OPEN cur(unknown_identifier.a);
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE va INT;
+  DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+  OPEN cur(unknown_identifier.a.b);
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE va INT;
+  DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+  OPEN cur(unknown_identifier.a.b.c);
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+--echo #
+
+--echo # (testing aggregate functions)
+
+#
+# Aggregate functions in CASE SP control
+#
+
+DELIMITER $$;
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1()
+BEGIN
+  CASE SUM(1) WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+
+#
+# Aggregate function in IF
+#
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1()
+BEGIN
+  IF SUM(1) THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+
+#
+# Aggregate function in WHILE
+#
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1()
+BEGIN
+  WHILE SUM(1) DO
+    SELECT 1;
+  END WHILE;
+END;
+$$
+
+
+#
+# Aggregate function in REPEAT
+#
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1()
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL SUM(1);
+  END REPEAT;
+END;
+$$
+
+
+#
+# Aggregate function in FOR
+#
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN 0..SUM(1)
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN SUM(1)..10
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+
+DELIMITER ;$$
+
+
+#
+# Aggregate functions as SP variable default values
+#
+
+DELIMITER $$;
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE a INT DEFAULT SUM(1);
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+
+#
+# Aggregate functions as SP function return values
+#
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE FUNCTION f1() RETURNS INT RETURN SUM(1);
+
+
+#
+# Aggregate functions in CURSOR parameters
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DELIMITER $$;
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE va INT;
+  DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+  OPEN cur(SUM(1));
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+--echo #
+
+--echo # (testing window functions)
+
+#
+# Aggregate functions in CASE SP control
+#
+
+DELIMITER $$;
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1()
+BEGIN
+  CASE ROW_NUMBER() OVER() WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+
+#
+# Aggregate function in IF
+#
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1()
+BEGIN
+  IF ROW_NUMBER() OVER() THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+
+#
+# Aggregate function in WHILE
+#
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1()
+BEGIN
+  WHILE ROW_NUMBER() OVER() DO
+    SELECT 1;
+  END WHILE;
+END;
+$$
+
+
+#
+# Aggregate function in REPEAT
+#
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1()
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL ROW_NUMBER() OVER();
+  END REPEAT;
+END;
+$$
+
+
+#
+# Aggregate function in FOR
+#
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN 0..ROW_NUMBER() OVER()
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1()
+BEGIN
+  FOR i IN ROW_NUMBER() OVER()..10
+  DO
+    SELECT i;
+  END FOR;
+END;
+$$
+
+
+DELIMITER ;$$
+
+
+#
+# Aggregate functions as SP variable default values
+#
+
+DELIMITER $$;
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE a INT DEFAULT ROW_NUMBER() OVER();
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+
+#
+# Aggregate functions as SP function return values
+#
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE FUNCTION f1() RETURNS INT RETURN ROW_NUMBER() OVER();
+
+
+#
+# Aggregate functions in CURSOR parameters
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DELIMITER $$;
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1()
+BEGIN
+  DECLARE va INT;
+  DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+  OPEN cur(ROW_NUMBER() OVER());
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+
+DELIMITER ;$$
+DROP TABLE t1;
diff --git a/mysql-test/main/sp.result b/mysql-test/main/sp.result
index a79d90d..572015d 100644
--- a/mysql-test/main/sp.result
+++ b/mysql-test/main/sp.result
@@ -4179,6 +4179,7 @@ select v, isnull(v);
 end if;
 end;
 end|
+ERROR 42S22: Unknown column 'undefined_var' in 'field list'
 create procedure bug14643_2()
 begin
 declare continue handler for sqlexception select 'boo' as 'Handler';
@@ -4190,18 +4191,7 @@ select 2;
 end case;
 select undefined_var;
 end|
-call bug14643_1()|
-Handler
-boo
-v	isnull(v)
-NULL	1
-call bug14643_2()|
-Handler
-boo
-Handler
-boo
-drop procedure bug14643_1|
-drop procedure bug14643_2|
+ERROR 42S22: Unknown column 'undefined_var' in 'field list'
 drop procedure if exists bug14304|
 drop table if exists t3, t4|
 create table t3(a int primary key auto_increment)|
@@ -4231,9 +4221,7 @@ create procedure bug14376()
 begin
 declare x int default x;
 end|
-call bug14376()|
 ERROR 42S22: Unknown column 'x' in 'field list'
-drop procedure bug14376|
 create procedure bug14376()
 begin
 declare x int default 42;
@@ -4476,6 +4464,7 @@ select 'no' as 'v';
 end if;
 select 'done' as 'End';
 end|
+ERROR 42S22: Unknown column 'v' in 'field list'
 create procedure bug14498_2()
 begin
 declare continue handler for sqlexception select 'error' as 'Handler';
@@ -4484,6 +4473,7 @@ select 'yes' as 'v';
 end while;
 select 'done' as 'End';
 end|
+ERROR 42S22: Unknown column 'v' in 'field list'
 create procedure bug14498_3()
 begin
 declare continue handler for sqlexception select 'error' as 'Handler';
@@ -4492,6 +4482,7 @@ select 'maybe' as 'v';
 until v end repeat;
 select 'done' as 'End';
 end|
+ERROR 42S22: Unknown column 'v' in 'field list'
 create procedure bug14498_4()
 begin
 declare continue handler for sqlexception select 'error' as 'Handler';
@@ -4505,6 +4496,7 @@ select '?' as 'v';
 end case;
 select 'done' as 'End';
 end|
+ERROR 42S22: Unknown column 'v' in 'field list'
 create procedure bug14498_5()
 begin
 declare continue handler for sqlexception select 'error' as 'Handler';
@@ -4518,38 +4510,7 @@ select '?' as 'v';
 end case;
 select 'done' as 'End';
 end|
-call bug14498_1()|
-Handler
-error
-End
-done
-call bug14498_2()|
-Handler
-error
-End
-done
-call bug14498_3()|
-v
-maybe
-Handler
-error
-End
-done
-call bug14498_4()|
-Handler
-error
-End
-done
-call bug14498_5()|
-Handler
-error
-End
-done
-drop procedure bug14498_1|
-drop procedure bug14498_2|
-drop procedure bug14498_3|
-drop procedure bug14498_4|
-drop procedure bug14498_5|
+ERROR 42S22: Unknown column 'v' in 'field list'
 drop table if exists t3|
 drop procedure if exists bug15231_1|
 drop procedure if exists bug15231_2|
@@ -8316,14 +8277,12 @@ DECLARE name VARCHAR(10);
 SET name="hello";
 call p1(name2);
 END|
+ERROR 42S22: Unknown column 'name2' in 'field list'
 call p2();
 a
 hello
-call p3();
-ERROR 42S22: Unknown column 'name2' in 'field list'
 drop procedure p1;
 drop procedure p2;
-drop procedure p3;
 #
 # MDEV-15328: MariaDB 10.2.13 Crashes upon CALL PROCEDURE PARAM
 # LAST_INSERT_ID ()
diff --git a/mysql-test/main/sp.test b/mysql-test/main/sp.test
index 56dea01..3d0a6b8 100644
--- a/mysql-test/main/sp.test
+++ b/mysql-test/main/sp.test
@@ -5040,6 +5040,7 @@ drop procedure if exists bug14643_1|
 drop procedure if exists bug14643_2|
 --enable_warnings
 
+--error ER_BAD_FIELD_ERROR
 create procedure bug14643_1()
 begin
   declare continue handler for sqlexception select 'boo' as 'Handler';
@@ -5055,6 +5056,7 @@ begin
   end;
 end|
 
+--error ER_BAD_FIELD_ERROR
 create procedure bug14643_2()
 begin
   declare continue handler for sqlexception select 'boo' as 'Handler';
@@ -5069,11 +5071,6 @@ begin
   select undefined_var;
 end|
 
-call bug14643_1()|
-call bug14643_2()|
-
-drop procedure bug14643_1|
-drop procedure bug14643_2|
 
 #
 # BUG#14304: auto_increment field incorrect set in SP
@@ -5114,15 +5111,12 @@ drop table t3, t4|
 drop procedure if exists bug14376|
 --enable_warnings
 
+--error ER_BAD_FIELD_ERROR
 create procedure bug14376()
 begin
   declare x int default x;
 end|
 
-# Not the error we want, but that's what we got for now...
---error ER_BAD_FIELD_ERROR
-call bug14376()|
-drop procedure bug14376|
 
 create procedure bug14376()
 begin
@@ -5344,6 +5338,7 @@ drop procedure if exists bug14498_4|
 drop procedure if exists bug14498_5|
 --enable_warnings
 
+--error ER_BAD_FIELD_ERROR
 create procedure bug14498_1()
 begin
   declare continue handler for sqlexception select 'error' as 'Handler';
@@ -5356,6 +5351,7 @@ begin
   select 'done' as 'End';
 end|
 
+--error ER_BAD_FIELD_ERROR
 create procedure bug14498_2()
 begin
   declare continue handler for sqlexception select 'error' as 'Handler';
@@ -5366,6 +5362,7 @@ begin
   select 'done' as 'End';
 end|
 
+--error ER_BAD_FIELD_ERROR
 create procedure bug14498_3()
 begin
   declare continue handler for sqlexception select 'error' as 'Handler';
@@ -5376,6 +5373,7 @@ begin
   select 'done' as 'End';
 end|
 
+--error ER_BAD_FIELD_ERROR
 create procedure bug14498_4()
 begin
   declare continue handler for sqlexception select 'error' as 'Handler';
@@ -5391,6 +5389,7 @@ begin
   select 'done' as 'End';
 end|
 
+--error ER_BAD_FIELD_ERROR
 create procedure bug14498_5()
 begin
   declare continue handler for sqlexception select 'error' as 'Handler';
@@ -5406,17 +5405,6 @@ begin
   select 'done' as 'End';
 end|
 
-call bug14498_1()|
-call bug14498_2()|
-call bug14498_3()|
-call bug14498_4()|
-call bug14498_5()|
-
-drop procedure bug14498_1|
-drop procedure bug14498_2|
-drop procedure bug14498_3|
-drop procedure bug14498_4|
-drop procedure bug14498_5|
 
 #
 # BUG#15231: Stored procedure bug with not found condition handler
@@ -9828,6 +9816,8 @@ BEGIN
   SET name="hello";
   call p1(name);
 END|
+
+--error ER_BAD_FIELD_ERROR
 CREATE OR REPLACE PROCEDURE p3 ()
 BEGIN
   DECLARE name VARCHAR(10);
@@ -9838,11 +9828,8 @@ END|
 DELIMITER ;|
 
 call p2();
---error ER_BAD_FIELD_ERROR
-call p3();
 drop procedure p1;
 drop procedure p2;
-drop procedure p3;
 
 --echo #
 --echo # MDEV-15328: MariaDB 10.2.13 Crashes upon CALL PROCEDURE PARAM
diff --git a/mysql-test/main/statement-expr.result b/mysql-test/main/statement-expr.result
new file mode 100644
index 0000000..2e7e3ab
--- /dev/null
+++ b/mysql-test/main/statement-expr.result
@@ -0,0 +1,217 @@
+CREATE TABLE t1 (id INT, id1 INT);
+INSERT INTO t1 VALUES (1,7);
+INSERT INTO t1 VALUES (1,8);
+SELECT ROW(1,7) IN (SELECT id, id1 FROM t1 WHERE id1= 8);
+ROW(1,7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)
+0
+EXECUTE IMMEDIATE 'SELECT ROW(1, 7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)';
+ROW(1, 7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)
+0
+DROP TABLE t1;
+EXECUTE IMMEDIATE 'SELECT ?' USING (1 IN (SELECT * FROM t1));
+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 * FROM t1))' at line 1
+EXECUTE IMMEDIATE 'SELECT ?' USING (SELECT * FROM t1);
+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 * FROM t1)' at line 1
+CREATE TABLE t1 (id INT);
+INSERT INTO t1 VALUES (10);
+CREATE PROCEDURE p1(a INT) BEGIN END;
+CALL p1((1) IN (SELECT * FROM t1));
+CALL p1(EXISTS (SELECT * FROM t1));
+DROP PROCEDURE p1;
+DROP TABLE t1;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1));
+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 '(1 IN (SELECT * FROM t1))' at line 1
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1);
+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 'EXISTS (SELECT * FROM t1)' at line 1
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1));
+SIGNAL SQLSTATE '01000';
+END;
+$$
+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 '(1 IN (SELECT * FROM t1));
+SIGNAL SQLSTATE '01000';
+END' at line 3
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1);
+SIGNAL SQLSTATE '01000';
+END;
+$$
+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 'EXISTS (SELECT * FROM t1);
+SIGNAL SQLSTATE '01000';
+END' at line 3
+PREPARE stmt FROM (1 IN (SELECT * FROM t1));
+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 * FROM t1))' at line 1
+PREPARE stmt FROM EXISTS (SELECT * FROM t1);
+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 * FROM t1)' at line 1
+EXECUTE IMMEDIATE (1 IN (SELECT * FROM t1));
+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 * FROM t1))' at line 1
+EXECUTE IMMEDIATE EXISTS (SELECT * FROM t1);
+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 * FROM t1)' at line 1
+GET DIAGNOSTICS CONDITION (1 IN (SELECT * FROM t1)) @errno=MYSQL_ERRNO;
+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 '(1 IN (SELECT * FROM t1)) @errno=MYSQL_ERRNO' at line 1
+GET DIAGNOSTICS CONDITION EXISTS (SELECT * FROM t1) @errno=MYSQL_ERRNO;
+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 'EXISTS (SELECT * FROM t1) @errno=MYSQL_ERRNO' at line 1
+PURGE BINARY LOGS BEFORE (1 IN (SELECT * FROM t1));
+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 * FROM t1))' at line 1
+PURGE BINARY LOGS BEFORE EXISTS (SELECT * FROM t1);
+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 * FROM t1)' at line 1
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DO 1 IN (SELECT * FROM t1);
+DO EXISTS (SELECT * FROM t1);
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1(a INT) BEGIN END;
+CALL p1(unknown_identifier);
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CALL p1(unknown_identifier.a);
+ERROR 42S22: Unknown column 'a' in 'field list'
+CALL p1(unknown_identifier.a.b);
+ERROR 42S22: Unknown column 'b' in 'field list'
+CALL p1(unknown_identifier.a.b.c);
+ERROR 42S22: Unknown column 'b' in 'field list'
+DROP PROCEDURE p1;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=unknown_identifier;
+SIGNAL SQLSTATE '01000';
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a;
+SIGNAL SQLSTATE '01000';
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a.b;
+SIGNAL SQLSTATE '01000';
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a.b.c;
+SIGNAL SQLSTATE '01000';
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+PREPARE stmt FROM unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+PREPARE stmt FROM unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+PREPARE stmt FROM unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+PREPARE stmt FROM unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+EXECUTE IMMEDIATE unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+EXECUTE IMMEDIATE unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+EXECUTE IMMEDIATE unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+EXECUTE IMMEDIATE unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+GET DIAGNOSTICS CONDITION unknown_identifier @errno=MYSQL_ERRNO;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+GET DIAGNOSTICS CONDITION unknown_identifier.a @errno=MYSQL_ERRNO;
+ERROR 42S22: Unknown column 'a' in 'field list'
+GET DIAGNOSTICS CONDITION unknown_identifier.a.b @errno=MYSQL_ERRNO;
+ERROR 42S22: Unknown column 'b' in 'field list'
+GET DIAGNOSTICS CONDITION unknown_identifier.a.b.c @errno=MYSQL_ERRNO;
+ERROR 42S22: Unknown column 'b' in 'field list'
+PURGE BINARY LOGS BEFORE unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+PURGE BINARY LOGS BEFORE unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+PURGE BINARY LOGS BEFORE unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+PURGE BINARY LOGS BEFORE unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1()
+BEGIN
+DO unknown_identifier;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+#
+# MDEV-15870 Using aggregate and window function in unexpected places can crash the server
+#
+# (aggreate functions)
+EXECUTE IMMEDIATE 'SELECT ?' USING SUM(1);
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1(a INT) BEGIN END;
+CALL p1(SUM(1));
+ERROR HY000: Invalid use of group function
+DROP PROCEDURE p1;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=SUM(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 'SUM(1)' at line 1
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=SUM(1);
+SIGNAL SQLSTATE '01000';
+END;
+$$
+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 'SUM(1);
+SIGNAL SQLSTATE '01000';
+END' at line 3
+PREPARE stmt FROM SUM(1);
+ERROR HY000: Invalid use of group function
+EXECUTE IMMEDIATE SUM(1);
+ERROR HY000: Invalid use of group function
+GET DIAGNOSTICS CONDITION SUM(1) @errno=MYSQL_ERRNO;
+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 'SUM(1) @errno=MYSQL_ERRNO' at line 1
+PURGE BINARY LOGS BEFORE SUM(1);
+ERROR HY000: Invalid use of group function
+#
+# MDEV-15870 Using aggregate and window function in unexpected places can crash the server
+#
+# (window functions)
+EXECUTE IMMEDIATE 'SELECT ?' USING ROW_NUMBER() OVER ();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1(a INT) BEGIN END;
+CALL p1(ROW_NUMBER() OVER ());
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+DROP PROCEDURE p1;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=ROW_NUMBER() OVER ();
+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 'ROW_NUMBER() OVER ()' at line 1
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=ROW_NUMBER() OVER ();
+SIGNAL SQLSTATE '01000';
+END;
+$$
+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 'ROW_NUMBER() OVER ();
+SIGNAL SQLSTATE '01000';
+END' at line 3
+PREPARE stmt FROM ROW_NUMBER() OVER ();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+EXECUTE IMMEDIATE ROW_NUMBER() OVER ();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+GET DIAGNOSTICS CONDITION ROW_NUMBER() OVER () @errno=MYSQL_ERRNO;
+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 'ROW_NUMBER() OVER () @errno=MYSQL_ERRNO' at line 1
+PURGE BINARY LOGS BEFORE ROW_NUMBER() OVER ();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
diff --git a/mysql-test/main/statement-expr.test b/mysql-test/main/statement-expr.test
new file mode 100644
index 0000000..7b96a7d
--- /dev/null
+++ b/mysql-test/main/statement-expr.test
@@ -0,0 +1,291 @@
+# Testing expressions of different kinds in various non-SELECT statements
+
+
+#
+# Subselects in non-SELECT statements
+#
+
+CREATE TABLE t1 (id INT, id1 INT);
+INSERT INTO t1 VALUES (1,7);
+INSERT INTO t1 VALUES (1,8);
+SELECT ROW(1,7) IN (SELECT id, id1 FROM t1 WHERE id1= 8);
+EXECUTE IMMEDIATE 'SELECT ROW(1, 7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)';
+DROP TABLE t1;
+
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING (1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING (SELECT * FROM t1);
+
+
+CREATE TABLE t1 (id INT);
+INSERT INTO t1 VALUES (10);
+CREATE PROCEDURE p1(a INT) BEGIN END;
+CALL p1((1) IN (SELECT * FROM t1));
+CALL p1(EXISTS (SELECT * FROM t1));
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1);
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1));
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+--error ER_PARSE_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1);
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+DELIMITER ;$$
+
+
+--error ER_PARSE_ERROR
+PREPARE stmt FROM (1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+PREPARE stmt FROM EXISTS (SELECT * FROM t1);
+
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE (1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE EXISTS (SELECT * FROM t1);
+
+--error ER_PARSE_ERROR
+GET DIAGNOSTICS CONDITION (1 IN (SELECT * FROM t1)) @errno=MYSQL_ERRNO;
+--error ER_PARSE_ERROR
+GET DIAGNOSTICS CONDITION EXISTS (SELECT * FROM t1) @errno=MYSQL_ERRNO;
+
+--error ER_PARSE_ERROR
+PURGE BINARY LOGS BEFORE (1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+PURGE BINARY LOGS BEFORE EXISTS (SELECT * FROM t1);
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DO 1 IN (SELECT * FROM t1);
+DO EXISTS (SELECT * FROM t1);
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+--echo #
+
+#TODO: warp into CREATE
+
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a.b.c;
+
+
+CREATE PROCEDURE p1(a INT) BEGIN END;
+--error ER_BAD_FIELD_ERROR
+CALL p1(unknown_identifier);
+--error ER_BAD_FIELD_ERROR
+CALL p1(unknown_identifier.a);
+--error ER_BAD_FIELD_ERROR
+CALL p1(unknown_identifier.a.b);
+--error ER_BAD_FIELD_ERROR
+CALL p1(unknown_identifier.a.b.c);
+DROP PROCEDURE p1;
+
+
+--error ER_BAD_FIELD_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a.b.c;
+
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=unknown_identifier;
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+--error ER_BAD_FIELD_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a;
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+--error ER_BAD_FIELD_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a.b;
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+--error ER_BAD_FIELD_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a.b.c;
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+DELIMITER ;$$
+
+
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM unknown_identifier.a.b.c;
+
+
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE unknown_identifier.a.b.c;
+
+
+--error ER_BAD_FIELD_ERROR
+GET DIAGNOSTICS CONDITION unknown_identifier @errno=MYSQL_ERRNO;
+--error ER_BAD_FIELD_ERROR
+GET DIAGNOSTICS CONDITION unknown_identifier.a @errno=MYSQL_ERRNO;
+--error ER_BAD_FIELD_ERROR
+GET DIAGNOSTICS CONDITION unknown_identifier.a.b @errno=MYSQL_ERRNO;
+--error ER_BAD_FIELD_ERROR
+GET DIAGNOSTICS CONDITION unknown_identifier.a.b.c @errno=MYSQL_ERRNO;
+
+
+--error ER_BAD_FIELD_ERROR
+PURGE BINARY LOGS BEFORE unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+PURGE BINARY LOGS BEFORE unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+PURGE BINARY LOGS BEFORE unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+PURGE BINARY LOGS BEFORE unknown_identifier.a.b.c;
+
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1()
+BEGIN
+  DO unknown_identifier;
+END;
+$$
+DELIMITER ;$$
+
+
+--echo #
+--echo # MDEV-15870 Using aggregate and window function in unexpected places can crash the server
+--echo #
+
+--echo # (aggreate functions)
+
+--error ER_INVALID_GROUP_FUNC_USE
+EXECUTE IMMEDIATE 'SELECT ?' USING SUM(1);
+
+
+CREATE PROCEDURE p1(a INT) BEGIN END;
+--error ER_INVALID_GROUP_FUNC_USE
+CALL p1(SUM(1));
+DROP PROCEDURE p1;
+
+
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=SUM(1);
+
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=SUM(1);
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+DELIMITER ;$$
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+PREPARE stmt FROM SUM(1);
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+EXECUTE IMMEDIATE SUM(1);
+
+
+--error ER_PARSE_ERROR
+GET DIAGNOSTICS CONDITION SUM(1) @errno=MYSQL_ERRNO;
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+PURGE BINARY LOGS BEFORE SUM(1);
+
+
+
+--echo #
+--echo # MDEV-15870 Using aggregate and window function in unexpected places can crash the server
+--echo #
+
+--echo # (window functions)
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+EXECUTE IMMEDIATE 'SELECT ?' USING ROW_NUMBER() OVER ();
+
+
+CREATE PROCEDURE p1(a INT) BEGIN END;
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CALL p1(ROW_NUMBER() OVER ());
+DROP PROCEDURE p1;
+
+
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=ROW_NUMBER() OVER ();
+
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=ROW_NUMBER() OVER ();
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+DELIMITER ;$$
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+PREPARE stmt FROM ROW_NUMBER() OVER ();
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+EXECUTE IMMEDIATE ROW_NUMBER() OVER ();
+
+
+--error ER_PARSE_ERROR
+GET DIAGNOSTICS CONDITION ROW_NUMBER() OVER () @errno=MYSQL_ERRNO;
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+PURGE BINARY LOGS BEFORE ROW_NUMBER() OVER ();
diff --git a/mysql-test/suite/compat/oracle/r/sp-expr.result b/mysql-test/suite/compat/oracle/r/sp-expr.result
new file mode 100644
index 0000000..e9383d5
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/sp-expr.result
@@ -0,0 +1,585 @@
+SET sql_mode=ORACLE;
+#
+# Start of 10.4 tests
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+BEGIN
+CASE ((1) IN (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+1
+1
+BEGIN
+CASE (EXISTS (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+1
+1
+BEGIN
+IF ((1) IN (SELECT a FROM t1)) THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+1
+1
+BEGIN
+IF (EXISTS (SELECT a FROM t1)) THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+1
+1
+BEGIN
+WHILE ((1234) IN (SELECT * FROM t1)) LOOP
+SELECT 1;
+END LOOP;
+END;
+$$
+BEGIN
+WHILE (EXISTS (SELECT * FROM t1 WHERE a=1234)) LOOP
+SELECT 1;
+END LOOP;
+END;
+$$
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL (1 IN (SELECT * FROM t1))
+END REPEAT;
+END;
+$$
+1
+1
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL EXISTS (SELECT * FROM t1 WHERE a=1)
+END REPEAT;
+END;
+$$
+1
+1
+BEGIN
+FOR i IN 0..(1 IN (SELECT * FROM t1))
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+i
+0
+i
+1
+BEGIN
+FOR i IN 0..EXISTS (SELECT * FROM t1 WHERE a=1)
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+i
+0
+i
+1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+DECLARE
+a INT DEFAULT ((10) IN (SELECT * FROM t1));
+BEGIN
+SELECT a;
+END;
+$$
+a
+1
+DECLARE
+a INT DEFAULT EXISTS (SELECT * FROM t1);
+BEGIN
+SELECT a;
+END;
+$$
+a
+1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+CREATE FUNCTION f1() RETURN INT AS
+BEGIN
+RETURN ((1) IN (SELECT * FROM t1));
+END;
+$$
+CREATE FUNCTION f2() RETURN INT AS
+BEGIN
+RETURN EXISTS (SELECT * FROM t1 WHERE a=1);
+END;
+$$
+SELECT f1();
+f1()
+1
+SELECT f2();
+f2()
+1
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DECLARE
+va INT;
+CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+OPEN cur(1 IN (SELECT * FROM t1));
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+va
+2
+DECLARE
+va INT;
+CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+OPEN cur(EXISTS (SELECT * FROM t1));
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+va
+2
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+CREATE PROCEDURE p1() AS
+BEGIN
+CASE unknown_identifier WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+CASE unknown_identifier.a WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+CASE unknown_identifier.a.b WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+CASE unknown_identifier.a.b.c WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+IF unknown_identifier THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+IF unknown_identifier.a THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+IF unknown_identifier.a.b THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+IF unknown_identifier.a.b.c THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+WHILE unknown_identifier LOOP
+SELECT 1;
+END LOOP;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+WHILE unknown_identifier.a LOOP
+SELECT 1;
+END LOOP;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+WHILE unknown_identifier.a.b LOOP
+SELECT 1;
+END LOOP;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+WHILE unknown_identifier.a.b.c LOOP
+SELECT 1;
+END LOOP;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a.b;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a.b.c;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN 0..unknown_identifier
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN 0..unknown_identifier.field1
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier.field1
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN 0..unknown_identifier.field1.field2
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR 42000: Undeclared variable: field1.field2
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN unknown_identifier..10
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN unknown_identifier.field1..10
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier.field1
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN unknown_identifier.field1.field2..10
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR 42000: Undeclared variable: field1.field2
+CREATE PROCEDURE p1() AS
+a INT DEFAULT unknown_identifier;
+BEGIN
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE PROCEDURE p1() AS
+a INT DEFAULT unknown_identifier.a;
+BEGIN
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE PROCEDURE p1() AS
+a INT DEFAULT unknown_identifier.a.b;
+BEGIN
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN unknown_identifier; END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN unknown_identifier.a; END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN unknown_identifier.a.b; END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN unknown_identifier.a.b.c; END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE PROCEDURE p1() AS
+va INT;
+CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+OPEN cur(unknown_identifier);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'ORDER clause'
+CREATE PROCEDURE p1() AS
+va INT;
+CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+OPEN cur(unknown_identifier.a);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'ORDER clause'
+CREATE PROCEDURE p1() AS
+va INT;
+CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+OPEN cur(unknown_identifier.a.b);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'ORDER clause'
+CREATE PROCEDURE p1() AS
+va INT;
+CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+OPEN cur(unknown_identifier.a.b.c);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'ORDER clause'
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+# (testing aggregate functions)
+CREATE PROCEDURE p1() AS
+BEGIN
+CASE SUM(1) WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1() AS
+BEGIN
+IF SUM(1) THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1() AS
+BEGIN
+WHILE SUM(1) LOOP
+SELECT 1;
+END LOOP;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1() AS
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL SUM(1);
+END REPEAT;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN 0..SUM(1)
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN SUM(1)..10
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1() AS
+a INT DEFAULT SUM(1);
+BEGIN
+SELECT a;
+END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN SUM(1); END;
+$$
+ERROR HY000: Invalid use of group function
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE PROCEDURE p1() AS
+va INT;
+CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+OPEN cur(SUM(1));
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR HY000: Invalid use of group function
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+# (testing window functions)
+CREATE PROCEDURE p1() AS
+BEGIN
+CASE ROW_NUMBER() OVER() WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1() AS
+BEGIN
+IF ROW_NUMBER() OVER() THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1() AS
+BEGIN
+WHILE ROW_NUMBER() OVER() LOOP
+SELECT 1;
+END LOOP;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1() AS
+BEGIN
+REPEAT
+SELECT 1;
+UNTIL ROW_NUMBER() OVER();
+END REPEAT;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN 0..ROW_NUMBER() OVER()
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1() AS
+BEGIN
+FOR i IN ROW_NUMBER() OVER()..10
+LOOP
+SELECT i;
+END LOOP;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1() AS
+a INT DEFAULT ROW_NUMBER() OVER();
+BEGIN
+SELECT a;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN ROW_NUMBER() OVER(); END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE PROCEDURE p1() AS
+va INT;
+CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+OPEN cur(ROW_NUMBER() OVER());
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/r/sp.result b/mysql-test/suite/compat/oracle/r/sp.result
index 7f04282..2049f23 100644
--- a/mysql-test/suite/compat/oracle/r/sp.result
+++ b/mysql-test/suite/compat/oracle/r/sp.result
@@ -1019,9 +1019,7 @@ LOOP
 EXIT WHEN unknown_ident IS NULL;
 END LOOP;
 END$$
-CALL p1;
 ERROR 42S22: Unknown column 'unknown_ident' in 'field list'
-DROP PROCEDURE p1;
 CREATE PROCEDURE p1
 AS
 BEGIN
@@ -1030,9 +1028,7 @@ LOOP
 EXIT label WHEN unknown_ident IS NULL;
 END LOOP;
 END$$
-CALL p1;
 ERROR 42S22: Unknown column 'unknown_ident' in 'field list'
-DROP PROCEDURE p1;
 CREATE PROCEDURE p1
 AS
 BEGIN
@@ -1040,9 +1036,7 @@ LOOP
 CONTINUE WHEN unknown_ident IS NULL;
 END LOOP;
 END$$
-CALL p1;
 ERROR 42S22: Unknown column 'unknown_ident' in 'field list'
-DROP PROCEDURE p1;
 CREATE PROCEDURE p1
 AS
 BEGIN
@@ -1051,9 +1045,7 @@ LOOP
 CONTINUE label WHEN unknown_ident IS NULL;
 END LOOP;
 END$$
-CALL p1;
 ERROR 42S22: Unknown column 'unknown_ident' in 'field list'
-DROP PROCEDURE p1;
 #
 # MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT
 #
diff --git a/mysql-test/suite/compat/oracle/r/statement-expr.result b/mysql-test/suite/compat/oracle/r/statement-expr.result
new file mode 100644
index 0000000..3f37a22
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/statement-expr.result
@@ -0,0 +1,222 @@
+SET sql_mode=ORACLE;
+CREATE TABLE t1 (id INT, id1 INT);
+INSERT INTO t1 VALUES (1,7);
+INSERT INTO t1 VALUES (1,8);
+SELECT ROW(1,7) IN (SELECT id, id1 FROM t1 WHERE id1= 8);
+ROW(1,7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)
+0
+EXECUTE IMMEDIATE 'SELECT ROW(1, 7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)';
+ROW(1, 7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)
+0
+DROP TABLE t1;
+EXECUTE IMMEDIATE 'SELECT ?' USING (1 IN (SELECT * FROM t1));
+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 * FROM t1))' at line 1
+EXECUTE IMMEDIATE 'SELECT ?' USING (SELECT * FROM t1);
+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 * FROM t1)' at line 1
+CREATE TABLE t1 (id INT);
+INSERT INTO t1 VALUES (10);
+CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END;
+$$
+CALL p1((1) IN (SELECT * FROM t1));
+CALL p1(EXISTS (SELECT * FROM t1));
+DROP PROCEDURE p1;
+DROP TABLE t1;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1));
+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 '(1 IN (SELECT * FROM t1))' at line 1
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1);
+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 'EXISTS (SELECT * FROM t1)' at line 1
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1));
+SIGNAL SQLSTATE '01000';
+END;
+$$
+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 '(1 IN (SELECT * FROM t1));
+SIGNAL SQLSTATE '01000';
+END' at line 3
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1);
+SIGNAL SQLSTATE '01000';
+END;
+$$
+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 'EXISTS (SELECT * FROM t1);
+SIGNAL SQLSTATE '01000';
+END' at line 3
+PREPARE stmt FROM (1 IN (SELECT * FROM t1));
+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 * FROM t1))' at line 1
+PREPARE stmt FROM EXISTS (SELECT * FROM t1);
+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 * FROM t1)' at line 1
+EXECUTE IMMEDIATE (1 IN (SELECT * FROM t1));
+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 * FROM t1))' at line 1
+EXECUTE IMMEDIATE EXISTS (SELECT * FROM t1);
+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 * FROM t1)' at line 1
+GET DIAGNOSTICS CONDITION (1 IN (SELECT * FROM t1)) @errno=MYSQL_ERRNO;
+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 '(1 IN (SELECT * FROM t1)) @errno=MYSQL_ERRNO' at line 1
+GET DIAGNOSTICS CONDITION EXISTS (SELECT * FROM t1) @errno=MYSQL_ERRNO;
+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 'EXISTS (SELECT * FROM t1) @errno=MYSQL_ERRNO' at line 1
+PURGE BINARY LOGS BEFORE (1 IN (SELECT * FROM t1));
+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 * FROM t1))' at line 1
+PURGE BINARY LOGS BEFORE EXISTS (SELECT * FROM t1);
+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 * FROM t1)' at line 1
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DO 1 IN (SELECT * FROM t1);
+DO EXISTS (SELECT * FROM t1);
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END;
+$$
+CALL p1(unknown_identifier);
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CALL p1(unknown_identifier.a);
+ERROR 42S22: Unknown column 'a' in 'field list'
+CALL p1(unknown_identifier.a.b);
+ERROR 42S22: Unknown column 'b' in 'field list'
+CALL p1(unknown_identifier.a.b.c);
+ERROR 42S22: Unknown column 'b' in 'field list'
+DROP PROCEDURE p1;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=unknown_identifier;
+SIGNAL SQLSTATE '01000';
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a;
+SIGNAL SQLSTATE '01000';
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a.b;
+SIGNAL SQLSTATE '01000';
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a.b.c;
+SIGNAL SQLSTATE '01000';
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+PREPARE stmt FROM unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+PREPARE stmt FROM unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+PREPARE stmt FROM unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+PREPARE stmt FROM unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+EXECUTE IMMEDIATE unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+EXECUTE IMMEDIATE unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+EXECUTE IMMEDIATE unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+EXECUTE IMMEDIATE unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+GET DIAGNOSTICS CONDITION unknown_identifier @errno=MYSQL_ERRNO;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+GET DIAGNOSTICS CONDITION unknown_identifier.a @errno=MYSQL_ERRNO;
+ERROR 42S22: Unknown column 'a' in 'field list'
+GET DIAGNOSTICS CONDITION unknown_identifier.a.b @errno=MYSQL_ERRNO;
+ERROR 42S22: Unknown column 'b' in 'field list'
+GET DIAGNOSTICS CONDITION unknown_identifier.a.b.c @errno=MYSQL_ERRNO;
+ERROR 42S22: Unknown column 'b' in 'field list'
+PURGE BINARY LOGS BEFORE unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+PURGE BINARY LOGS BEFORE unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+PURGE BINARY LOGS BEFORE unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+PURGE BINARY LOGS BEFORE unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+#
+# MDEV-15870 Using aggregate and window function in unexpected places can crash the server
+#
+# (aggreate functions)
+EXECUTE IMMEDIATE 'SELECT ?' USING SUM(1);
+ERROR HY000: Invalid use of group function
+CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END;
+$$
+CALL p1(SUM(1));
+ERROR HY000: Invalid use of group function
+DROP PROCEDURE p1;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=SUM(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 'SUM(1)' at line 1
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=SUM(1);
+SIGNAL SQLSTATE '01000';
+END;
+$$
+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 'SUM(1);
+SIGNAL SQLSTATE '01000';
+END' at line 3
+PREPARE stmt FROM SUM(1);
+ERROR HY000: Invalid use of group function
+EXECUTE IMMEDIATE SUM(1);
+ERROR HY000: Invalid use of group function
+GET DIAGNOSTICS CONDITION SUM(1) @errno=MYSQL_ERRNO;
+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 'SUM(1) @errno=MYSQL_ERRNO' at line 1
+PURGE BINARY LOGS BEFORE SUM(1);
+ERROR HY000: Invalid use of group function
+#
+# MDEV-15870 Using aggregate and window function in unexpected places can crash the server
+#
+# (window functions)
+EXECUTE IMMEDIATE 'SELECT ?' USING ROW_NUMBER() OVER ();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END;
+$$
+CALL p1(ROW_NUMBER() OVER ());
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+DROP PROCEDURE p1;
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=ROW_NUMBER() OVER ();
+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 'ROW_NUMBER() OVER ()' at line 1
+BEGIN NOT ATOMIC
+DECLARE CONTINUE HANDLER FOR SQLWARNING
+RESIGNAL SET MYSQL_ERRNO=ROW_NUMBER() OVER ();
+SIGNAL SQLSTATE '01000';
+END;
+$$
+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 'ROW_NUMBER() OVER ();
+SIGNAL SQLSTATE '01000';
+END' at line 3
+PREPARE stmt FROM ROW_NUMBER() OVER ();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+EXECUTE IMMEDIATE ROW_NUMBER() OVER ();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+GET DIAGNOSTICS CONDITION ROW_NUMBER() OVER () @errno=MYSQL_ERRNO;
+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 'ROW_NUMBER() OVER () @errno=MYSQL_ERRNO' at line 1
+PURGE BINARY LOGS BEFORE ROW_NUMBER() OVER ();
+ERROR HY000: Window function is allowed only in SELECT list and ORDER BY clause
+CREATE PROCEDURE p1() AS
+BEGIN
+DO unknown_identifier;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
diff --git a/mysql-test/suite/compat/oracle/t/sp-expr.result b/mysql-test/suite/compat/oracle/t/sp-expr.result
new file mode 100644
index 0000000..38a3d4c
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-expr.result
@@ -0,0 +1,389 @@
+#
+# Start of 10.4 tests
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+BEGIN NOT ATOMIC
+CASE ((1) IN (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+CASE (EXISTS (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+IF ((1) IN (SELECT a FROM t1)) THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+IF (EXISTS (SELECT a FROM t1)) THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+WHILE ((1234) IN (SELECT * FROM t1)) DO
+SELECT 1;
+END WHILE;
+END;
+$$
+BEGIN NOT ATOMIC
+WHILE (EXISTS (SELECT * FROM t1 WHERE a=1234)) DO
+SELECT 1;
+END WHILE;
+END;
+$$
+BEGIN NOT ATOMIC
+REPEAT
+SELECT 1;
+UNTIL (1 IN (SELECT * FROM t1))
+END REPEAT;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+REPEAT
+SELECT 1;
+UNTIL EXISTS (SELECT * FROM t1 WHERE a=1)
+END REPEAT;
+END;
+$$
+1
+1
+BEGIN NOT ATOMIC
+FOR i IN 0..(1 IN (SELECT * FROM t1))
+DO
+SELECT i;
+END FOR;
+END;
+$$
+i
+0
+i
+1
+BEGIN NOT ATOMIC
+FOR i IN 0..EXISTS (SELECT * FROM t1 WHERE a=1)
+DO
+SELECT i;
+END FOR;
+END;
+$$
+i
+0
+i
+1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT ((10) IN (SELECT * FROM t1));
+SELECT a;
+END;
+$$
+a
+1
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT EXISTS (SELECT * FROM t1);
+SELECT a;
+END;
+$$
+a
+1
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+CREATE FUNCTION f1() RETURNS INT
+BEGIN
+RETURN ((1) IN (SELECT * FROM t1));
+END;
+$$
+CREATE FUNCTION f2() RETURNS INT
+BEGIN
+RETURN EXISTS (SELECT * FROM t1 WHERE a=1);
+END;
+$$
+SELECT f1();
+f1()
+1
+SELECT f2();
+f2()
+1
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+BEGIN NOT ATOMIC
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(1 IN (SELECT * FROM t1));
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+va
+2
+BEGIN NOT ATOMIC
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(EXISTS (SELECT * FROM t1));
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+va
+2
+DROP TABLE t1;
+#
+# MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+#
+BEGIN NOT ATOMIC
+CASE unknown_identifier WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+BEGIN NOT ATOMIC
+CASE unknown_identifier.a WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+BEGIN NOT ATOMIC
+CASE unknown_identifier.a.b WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+CASE unknown_identifier.a.b.c WHEN 1 THEN SELECT 1;
+ELSE SELECT NULL;
+END CASE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+IF unknown_identifier THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+BEGIN NOT ATOMIC
+IF unknown_identifier.a THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+BEGIN NOT ATOMIC
+IF unknown_identifier.a.b THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+IF unknown_identifier.a.b.c THEN SELECT 1;
+ELSE SELECT NULL;
+END IF;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+WHILE unknown_identifier DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+BEGIN NOT ATOMIC
+WHILE unknown_identifier.a DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+BEGIN NOT ATOMIC
+WHILE unknown_identifier.a.b DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+WHILE unknown_identifier.a.b.c DO
+SELECT 1;
+END WHILE;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+BEGIN NOT ATOMIC
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+BEGIN NOT ATOMIC
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a.b;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+REPEAT
+SELECT 1;
+UNTIL unknown_identifier.a.b.c;
+END REPEAT;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+BEGIN NOT ATOMIC
+FOR i IN 0..unknown_identifier
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier
+BEGIN NOT ATOMIC
+FOR i IN 0..unknown_identifier.field1
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier.field1
+BEGIN NOT ATOMIC
+FOR i IN 0..unknown_identifier.field1.field2
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: field1.field2
+BEGIN NOT ATOMIC
+FOR i IN unknown_identifier..10
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier
+BEGIN NOT ATOMIC
+FOR i IN unknown_identifier.field1..10
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: unknown_identifier.field1
+BEGIN NOT ATOMIC
+FOR i IN unknown_identifier.field1.field2..10
+DO
+SELECT i;
+END FOR;
+END;
+$$
+ERROR 42000: Undeclared variable: field1.field2
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT unknown_identifier;
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT unknown_identifier.a;
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'field list'
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT unknown_identifier.a.b;
+SELECT a;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier;
+ERROR 42S22: Unknown column 'unknown_identifier' in 'field list'
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a.b;
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE FUNCTION f1() RETURNS INT RETURN unknown_identifier.a.b.c;
+ERROR 42S22: Unknown column 'b' in 'field list'
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+BEGIN NOT ATOMIC
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(unknown_identifier);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'unknown_identifier' in 'ORDER clause'
+BEGIN NOT ATOMIC
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(unknown_identifier.a);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'a' in 'ORDER clause'
+BEGIN NOT ATOMIC
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(unknown_identifier.a.b);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'ORDER clause'
+BEGIN NOT ATOMIC
+DECLARE va INT;
+DECLARE cur CURSOR(amin INT) FOR SELECT a FROM t1 WHERE a>amin ORDER BY a;
+OPEN cur(unknown_identifier.a.b.c);
+FETCH cur INTO va;
+SELECT va;
+CLOSE cur;
+END;
+$$
+ERROR 42S22: Unknown column 'b' in 'ORDER clause'
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-expr.test b/mysql-test/suite/compat/oracle/t/sp-expr.test
new file mode 100644
index 0000000..2e589f7
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/sp-expr.test
@@ -0,0 +1,820 @@
+# Testing expressions of different kinds in various parts of SP syntax
+
+SET sql_mode=ORACLE;
+
+--echo #
+--echo # Start of 10.4 tests
+--echo #
+
+#
+# Subselects in SP control structures
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+DELIMITER $$;
+
+BEGIN
+  CASE ((1) IN (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+BEGIN
+  CASE (EXISTS (SELECT a FROM t1)) WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+BEGIN
+  IF ((1) IN (SELECT a FROM t1)) THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+BEGIN
+  IF (EXISTS (SELECT a FROM t1)) THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+BEGIN
+  WHILE ((1234) IN (SELECT * FROM t1)) LOOP
+    SELECT 1;
+  END LOOP;
+END;
+$$
+BEGIN
+  WHILE (EXISTS (SELECT * FROM t1 WHERE a=1234)) LOOP
+    SELECT 1;
+  END LOOP;
+END;
+$$
+
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL (1 IN (SELECT * FROM t1))
+  END REPEAT;
+END;
+$$
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL EXISTS (SELECT * FROM t1 WHERE a=1)
+  END REPEAT;
+END;
+$$
+
+BEGIN
+  FOR i IN 0..(1 IN (SELECT * FROM t1))
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+BEGIN
+  FOR i IN 0..EXISTS (SELECT * FROM t1 WHERE a=1)
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+#
+# Subselects as SP variable default values
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+DECLARE
+  a INT DEFAULT ((10) IN (SELECT * FROM t1));
+BEGIN
+  SELECT a;
+END;
+$$
+DECLARE
+  a INT DEFAULT EXISTS (SELECT * FROM t1);
+BEGIN
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+#
+# Subselects SP function return values
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+DELIMITER $$;
+CREATE FUNCTION f1() RETURN INT AS
+BEGIN
+  RETURN ((1) IN (SELECT * FROM t1));
+END;
+$$
+CREATE FUNCTION f2() RETURN INT AS
+BEGIN
+  RETURN EXISTS (SELECT * FROM t1 WHERE a=1);
+END;
+$$
+DELIMITER ;$$
+SELECT f1();
+SELECT f2();
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP TABLE t1;
+
+
+#
+# Subselects in CURSOR parameters
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DELIMITER $$;
+DECLARE
+  va INT;
+  CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+  OPEN cur(1 IN (SELECT * FROM t1));
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+DECLARE
+  va INT;
+  CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+  OPEN cur(EXISTS (SELECT * FROM t1));
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+--echo #
+
+#
+# Unknown identifiers in CASE SP control
+#
+
+DELIMITER $$;
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  CASE unknown_identifier WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  CASE unknown_identifier.a WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  CASE unknown_identifier.a.b WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  CASE unknown_identifier.a.b.c WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+
+#
+# Unknown identifiers in IF
+#
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  IF unknown_identifier THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  IF unknown_identifier.a THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  IF unknown_identifier.a.b THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  IF unknown_identifier.a.b.c THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+
+#
+# Unknown identifiers in WHILE
+#
+
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  WHILE unknown_identifier LOOP
+    SELECT 1;
+  END LOOP;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  WHILE unknown_identifier.a LOOP
+    SELECT 1;
+  END LOOP;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  WHILE unknown_identifier.a.b LOOP
+    SELECT 1;
+  END LOOP;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  WHILE unknown_identifier.a.b.c LOOP
+    SELECT 1;
+  END LOOP;
+END;
+$$
+
+
+
+#
+# Unknown identifiers in REPEAT
+#
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL unknown_identifier;
+  END REPEAT;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL unknown_identifier.a;
+  END REPEAT;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL unknown_identifier.a.b;
+  END REPEAT;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL unknown_identifier.a.b.c;
+  END REPEAT;
+END;
+$$
+
+
+#
+# Unknown identifiers in FOR
+#
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN 0..unknown_identifier
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN 0..unknown_identifier.field1
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN 0..unknown_identifier.field1.field2
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN unknown_identifier..10
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN unknown_identifier.field1..10
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+--error ER_SP_UNDECLARED_VAR
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN unknown_identifier.field1.field2..10
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+DELIMITER ;$$
+
+
+#
+# Unknown identifiers as SP variable default values
+#
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+  a INT DEFAULT unknown_identifier;
+BEGIN
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+  a INT DEFAULT unknown_identifier.a;
+BEGIN
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+  a INT DEFAULT unknown_identifier.a.b;
+BEGIN
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+#
+# Unknown identifiers as SP function return values
+#
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN unknown_identifier; END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN unknown_identifier.a; END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN unknown_identifier.a.b; END;
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN unknown_identifier.a.b.c; END;
+$$
+DELIMITER ;$$
+
+
+#
+# Unknown identifiers in CURSOR parameters
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DELIMITER $$;
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+  va INT;
+  CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+  OPEN cur(unknown_identifier);
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+  va INT;
+  CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+  OPEN cur(unknown_identifier.a);
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+  va INT;
+  CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+  OPEN cur(unknown_identifier.a.b);
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+  va INT;
+  CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+  OPEN cur(unknown_identifier.a.b.c);
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+--echo #
+--echo # (testing aggregate functions)
+
+#
+# Aggregate functions in CASE SP control
+#
+
+DELIMITER $$;
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1() AS
+BEGIN
+  CASE SUM(1) WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+
+#
+# Aggregate functions in IF
+#
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1() AS
+BEGIN
+  IF SUM(1) THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+
+#
+# Aggregate functions in WHILE
+#
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1() AS
+BEGIN
+  WHILE SUM(1) LOOP
+    SELECT 1;
+  END LOOP;
+END;
+$$
+
+
+
+#
+# Aggregate functions in REPEAT
+#
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1() AS
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL SUM(1);
+  END REPEAT;
+END;
+$$
+
+#
+# Aggregate functions in FOR
+#
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN 0..SUM(1)
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN SUM(1)..10
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+DELIMITER ;$$
+
+
+#
+# Aggregate functions as SP variable default values
+#
+
+DELIMITER $$;
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1() AS
+  a INT DEFAULT SUM(1);
+BEGIN
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+#
+# Aggregate functions as SP function return values
+#
+
+DELIMITER $$;
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN SUM(1); END;
+$$
+DELIMITER ;$$
+
+
+#
+# Aggregate functions in CURSOR parameters
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DELIMITER $$;
+
+--error ER_INVALID_GROUP_FUNC_USE
+CREATE PROCEDURE p1() AS
+  va INT;
+  CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+  OPEN cur(SUM(1));
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+DELIMITER ;$$
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+--echo #
+--echo # (testing window functions)
+
+#
+# Window functions in CASE SP control
+#
+
+DELIMITER $$;
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1() AS
+BEGIN
+  CASE ROW_NUMBER() OVER() WHEN 1 THEN SELECT 1;
+  ELSE SELECT NULL;
+  END CASE;
+END;
+$$
+
+
+#
+# Window functions in IF
+#
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1() AS
+BEGIN
+  IF ROW_NUMBER() OVER() THEN SELECT 1;
+  ELSE SELECT NULL;
+  END IF;
+END;
+$$
+
+
+#
+# Window functions in WHILE
+#
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1() AS
+BEGIN
+  WHILE ROW_NUMBER() OVER() LOOP
+    SELECT 1;
+  END LOOP;
+END;
+$$
+
+
+
+#
+# Window functions in REPEAT
+#
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1() AS
+BEGIN
+  REPEAT
+    SELECT 1;
+  UNTIL ROW_NUMBER() OVER();
+  END REPEAT;
+END;
+$$
+
+#
+# Window functions in FOR
+#
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN 0..ROW_NUMBER() OVER()
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1() AS
+BEGIN
+  FOR i IN ROW_NUMBER() OVER()..10
+  LOOP
+    SELECT i;
+  END LOOP;
+END;
+$$
+
+DELIMITER ;$$
+
+
+#
+# Window functions as SP variable default values
+#
+
+DELIMITER $$;
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1() AS
+  a INT DEFAULT ROW_NUMBER() OVER();
+BEGIN
+  SELECT a;
+END;
+$$
+DELIMITER ;$$
+
+
+#
+# Window functions as SP function return values
+#
+
+DELIMITER $$;
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE FUNCTION f1() RETURN INT AS BEGIN RETURN ROW_NUMBER() OVER(); END;
+$$
+DELIMITER ;$$
+
+
+#
+# Window functions in CURSOR parameters
+#
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DELIMITER $$;
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CREATE PROCEDURE p1() AS
+  va INT;
+  CURSOR cur(amin INT) IS SELECT a FROM t1 WHERE a>amin ORDER BY a;
+BEGIN
+  OPEN cur(ROW_NUMBER() OVER());
+  FETCH cur INTO va;
+  SELECT va;
+  CLOSE cur;
+END;
+$$
+
+DELIMITER ;$$
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/sp.test b/mysql-test/suite/compat/oracle/t/sp.test
index b88271a..de2a4a5 100644
--- a/mysql-test/suite/compat/oracle/t/sp.test
+++ b/mysql-test/suite/compat/oracle/t/sp.test
@@ -1092,6 +1092,7 @@ DROP FUNCTION f1;
 --echo #
 
 DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
 CREATE PROCEDURE p1
 AS
 BEGIN
@@ -1100,12 +1101,10 @@ BEGIN
   END LOOP;
 END$$
 DELIMITER ;$$
---error ER_BAD_FIELD_ERROR
-CALL p1;
-DROP PROCEDURE p1;
 
 
 DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
 CREATE PROCEDURE p1
 AS
 BEGIN
@@ -1115,12 +1114,10 @@ BEGIN
   END LOOP;
 END$$
 DELIMITER ;$$
---error ER_BAD_FIELD_ERROR
-CALL p1;
-DROP PROCEDURE p1;
 
 
 DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
 CREATE PROCEDURE p1
 AS
 BEGIN
@@ -1129,12 +1126,10 @@ BEGIN
   END LOOP;
 END$$
 DELIMITER ;$$
---error ER_BAD_FIELD_ERROR
-CALL p1;
-DROP PROCEDURE p1;
 
 
 DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
 CREATE PROCEDURE p1
 AS
 BEGIN
@@ -1144,9 +1139,6 @@ BEGIN
   END LOOP;
 END$$
 DELIMITER ;$$
---error ER_BAD_FIELD_ERROR
-CALL p1;
-DROP PROCEDURE p1;
 
 --echo #
 --echo # MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT
diff --git a/mysql-test/suite/compat/oracle/t/statement-expr.test b/mysql-test/suite/compat/oracle/t/statement-expr.test
new file mode 100644
index 0000000..3970caf
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/statement-expr.test
@@ -0,0 +1,304 @@
+# Testing expressions of different kinds in various non-SELECT statements
+
+SET sql_mode=ORACLE;
+
+#
+# Subselects in non-SELECT statements
+#
+
+CREATE TABLE t1 (id INT, id1 INT);
+INSERT INTO t1 VALUES (1,7);
+INSERT INTO t1 VALUES (1,8);
+SELECT ROW(1,7) IN (SELECT id, id1 FROM t1 WHERE id1= 8);
+EXECUTE IMMEDIATE 'SELECT ROW(1, 7) IN (SELECT id, id1 FROM t1 WHERE id1= 8)';
+DROP TABLE t1;
+
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING (1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING (SELECT * FROM t1);
+
+
+CREATE TABLE t1 (id INT);
+INSERT INTO t1 VALUES (10);
+DELIMITER $$;
+CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END;
+$$
+DELIMITER ;$$
+CALL p1((1) IN (SELECT * FROM t1));
+CALL p1(EXISTS (SELECT * FROM t1));
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1);
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=(1 IN (SELECT * FROM t1));
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+--error ER_PARSE_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=EXISTS (SELECT * FROM t1);
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+DELIMITER ;$$
+
+
+--error ER_PARSE_ERROR
+PREPARE stmt FROM (1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+PREPARE stmt FROM EXISTS (SELECT * FROM t1);
+
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE (1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+EXECUTE IMMEDIATE EXISTS (SELECT * FROM t1);
+
+--error ER_PARSE_ERROR
+GET DIAGNOSTICS CONDITION (1 IN (SELECT * FROM t1)) @errno=MYSQL_ERRNO;
+--error ER_PARSE_ERROR
+GET DIAGNOSTICS CONDITION EXISTS (SELECT * FROM t1) @errno=MYSQL_ERRNO;
+
+--error ER_PARSE_ERROR
+PURGE BINARY LOGS BEFORE (1 IN (SELECT * FROM t1));
+--error ER_PARSE_ERROR
+PURGE BINARY LOGS BEFORE EXISTS (SELECT * FROM t1);
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+DO 1 IN (SELECT * FROM t1);
+DO EXISTS (SELECT * FROM t1);
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-14347 CREATE PROCEDURE returns no error when using an unknown variable
+--echo #
+
+# TODO: wrap into CREATE
+
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE 'SELECT ?' USING unknown_identifier.a.b.c;
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END;
+$$
+DELIMITER ;$$
+--error ER_BAD_FIELD_ERROR
+CALL p1(unknown_identifier);
+--error ER_BAD_FIELD_ERROR
+CALL p1(unknown_identifier.a);
+--error ER_BAD_FIELD_ERROR
+CALL p1(unknown_identifier.a.b);
+--error ER_BAD_FIELD_ERROR
+CALL p1(unknown_identifier.a.b.c);
+DROP PROCEDURE p1;
+
+
+--error ER_BAD_FIELD_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=unknown_identifier.a.b.c;
+
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=unknown_identifier;
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+--error ER_BAD_FIELD_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a;
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+--error ER_BAD_FIELD_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a.b;
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+--error ER_BAD_FIELD_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=unknown_identifier.a.b.c;
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+DELIMITER ;$$
+
+
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+PREPARE stmt FROM unknown_identifier.a.b.c;
+
+
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+EXECUTE IMMEDIATE unknown_identifier.a.b.c;
+
+
+--error ER_BAD_FIELD_ERROR
+GET DIAGNOSTICS CONDITION unknown_identifier @errno=MYSQL_ERRNO;
+--error ER_BAD_FIELD_ERROR
+GET DIAGNOSTICS CONDITION unknown_identifier.a @errno=MYSQL_ERRNO;
+--error ER_BAD_FIELD_ERROR
+GET DIAGNOSTICS CONDITION unknown_identifier.a.b @errno=MYSQL_ERRNO;
+--error ER_BAD_FIELD_ERROR
+GET DIAGNOSTICS CONDITION unknown_identifier.a.b.c @errno=MYSQL_ERRNO;
+
+
+--error ER_BAD_FIELD_ERROR
+PURGE BINARY LOGS BEFORE unknown_identifier;
+--error ER_BAD_FIELD_ERROR
+PURGE BINARY LOGS BEFORE unknown_identifier.a;
+--error ER_BAD_FIELD_ERROR
+PURGE BINARY LOGS BEFORE unknown_identifier.a.b;
+--error ER_BAD_FIELD_ERROR
+PURGE BINARY LOGS BEFORE unknown_identifier.a.b.c;
+
+
+--echo #
+--echo # MDEV-15870 Using aggregate and window function in unexpected places can crash the server
+--echo #
+
+--echo # (aggreate functions)
+
+--error ER_INVALID_GROUP_FUNC_USE
+EXECUTE IMMEDIATE 'SELECT ?' USING SUM(1);
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END;
+$$
+DELIMITER ;$$
+--error ER_INVALID_GROUP_FUNC_USE
+CALL p1(SUM(1));
+DROP PROCEDURE p1;
+
+
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=SUM(1);
+
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=SUM(1);
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+DELIMITER ;$$
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+PREPARE stmt FROM SUM(1);
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+EXECUTE IMMEDIATE SUM(1);
+
+
+--error ER_PARSE_ERROR
+GET DIAGNOSTICS CONDITION SUM(1) @errno=MYSQL_ERRNO;
+
+
+--error ER_INVALID_GROUP_FUNC_USE
+PURGE BINARY LOGS BEFORE SUM(1);
+
+
+
+--echo #
+--echo # MDEV-15870 Using aggregate and window function in unexpected places can crash the server
+--echo #
+
+--echo # (window functions)
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+EXECUTE IMMEDIATE 'SELECT ?' USING ROW_NUMBER() OVER ();
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a INT) AS BEGIN NULL; END;
+$$
+DELIMITER ;$$
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+CALL p1(ROW_NUMBER() OVER ());
+DROP PROCEDURE p1;
+
+
+--error ER_PARSE_ERROR
+SIGNAL SQLSTATE '01000' SET MYSQL_ERRNO=ROW_NUMBER() OVER ();
+
+
+DELIMITER $$;
+--error ER_PARSE_ERROR
+BEGIN NOT ATOMIC
+  DECLARE CONTINUE HANDLER FOR SQLWARNING
+    RESIGNAL SET MYSQL_ERRNO=ROW_NUMBER() OVER ();
+  SIGNAL SQLSTATE '01000';
+END;
+$$
+DELIMITER ;$$
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+PREPARE stmt FROM ROW_NUMBER() OVER ();
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+EXECUTE IMMEDIATE ROW_NUMBER() OVER ();
+
+
+--error ER_PARSE_ERROR
+GET DIAGNOSTICS CONDITION ROW_NUMBER() OVER () @errno=MYSQL_ERRNO;
+
+
+--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION
+PURGE BINARY LOGS BEFORE ROW_NUMBER() OVER ();
+
+
+DELIMITER $$;
+--error ER_BAD_FIELD_ERROR
+CREATE PROCEDURE p1() AS
+BEGIN
+  DO unknown_identifier;
+END;
+$$
+DELIMITER ;$$
diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result
index e5e009a..0fe7082 100644
--- a/mysql-test/suite/funcs_1/r/storedproc.result
+++ b/mysql-test/suite/funcs_1/r/storedproc.result
@@ -15723,6 +15723,7 @@ Testcase 4.3.7:
 DROP PROCEDURE IF EXISTS sp7;
 CREATE PROCEDURE sp7()
 BEGIN
+DECLARE count INT DEFAULT 100;
 label1: loop
 set @dummystring = 'temp value';
 if count > 10 then leave label1;
@@ -15732,7 +15733,7 @@ END label1 loop;
 END//
 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 'iterate;
 END label1 loop;
-END' at line 7
+END' at line 8
 DROP PROCEDURE IF EXISTS sp7;
 CREATE PROCEDURE sp7()
 BEGIN
diff --git a/mysql-test/suite/funcs_1/t/storedproc.test b/mysql-test/suite/funcs_1/t/storedproc.test
index 98385d4..3178641 100644
--- a/mysql-test/suite/funcs_1/t/storedproc.test
+++ b/mysql-test/suite/funcs_1/t/storedproc.test
@@ -18861,6 +18861,7 @@ delimiter //;
 --error ER_PARSE_ERROR
 CREATE PROCEDURE sp7()
 BEGIN
+  DECLARE count INT DEFAULT 100;
   label1: loop
     set @dummystring = 'temp value';
     if count > 10 then leave label1;
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 901dfa0..b3fbdfd 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -3487,12 +3487,11 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name,
   sph->add_used_routine(lex, thd, qname);
   if (pkgname.m_name.length)
     sp_handler_package_body.add_used_routine(lex, thd, &pkgname);
+  Name_resolution_context *ctx= lex->current_context_or_default();
   if (arg_count > 0)
-    func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(),
-                                           qname, sph, *item_list);
+    func= new (thd->mem_root) Item_func_sp(thd, ctx, qname, sph, *item_list);
   else
-    func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(),
-                                           qname, sph);
+    func= new (thd->mem_root) Item_func_sp(thd, ctx, qname, sph);
 
   lex->safe_to_cache_query= 0;
   return func;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 5a447ce..9ca44c6 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -115,7 +115,8 @@ void Item_subselect::init(st_select_lex *select_lex,
       do not take into account expression inside aggregate functions because
       they can access original table fields
     */
-    parsing_place= (outer_select->in_sum_expr ?
+    // QQ: shouldn't we use relink_hack() instead ?
+    parsing_place= (!outer_select || outer_select->in_sum_expr ?
                     NO_MATTER :
                     outer_select->parsing_place);
     if (unit->is_unit_op() && unit->first_select()->next_select())
@@ -239,6 +240,9 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
 
   {
     SELECT_LEX *upper= unit->outer_select();
+    // QQ: shouldn't we use relink_hack() instead?
+    if (!upper)
+      upper= &thd_param->lex->builtin_select;
     if (upper->parsing_place == IN_HAVING)
       upper->subquery_in_having= 1;
     /* The subquery is an expression cache candidate */
@@ -1395,12 +1399,46 @@ bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
 }
 
 
+/*
+  "IN" and "EXISTS" subselect can appear in two statement types:
+
+  1. Statements that can have table columns, such as SELECT, DELETE, UPDATE
+  2. Statements that cannot have table columns, e.g:
+     RETURN ((1) IN (SELECT * FROM t1))
+     IF ((1) IN (SELECT * FROM t1))
+
+  Statements of the first type call master_select_push() in the beginning.
+  In such case everything is properly linked.
+
+  Statements of the second type do not call mastr_select_push().
+  Here we catch the second case and relink thd->lex->builtin_select and
+  select_lex to properly point to each other.
+
+  QQ: Shouldn't subselects of other type also call relink_hack()?
+  QQ: Can we do it at constructor time instead?
+*/
+static void relink_hack(THD *thd, st_select_lex *select_lex)
+{
+  if (!thd->lex->select_stack_top) // Statements of the second type
+  {
+    if (!select_lex->get_master()->get_master())
+      ((st_select_lex *) select_lex->get_master())->
+        set_master(&thd->lex->builtin_select);
+    if (!thd->lex->builtin_select.get_slave())
+      thd->lex->builtin_select.set_slave(select_lex->get_master());
+  }
+}
+
+
 Item_exists_subselect::Item_exists_subselect(THD *thd,
                                              st_select_lex *select_lex):
   Item_subselect(thd), upper_not(NULL), abort_on_null(0),
   emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0)
 {
   DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
+
+  relink_hack(thd, select_lex);
+
   init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
   max_columns= UINT_MAX;
   null_value= FALSE; //can't be NULL
@@ -1443,6 +1481,9 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
 {
   DBUG_ENTER("Item_in_subselect::Item_in_subselect");
   DBUG_PRINT("info", ("in_strategy: %u", (uint)in_strategy));
+
+  relink_hack(thd, select_lex);
+
   left_expr_orig= left_expr= left_exp;
   /* prepare to possible disassembling the item in convert_subq_to_sj() */
   if (left_exp->type() == Item::ROW_ITEM)
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 2ec7e3c..a880050 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -72,6 +72,7 @@ size_t Item_sum::ram_limitation(THD *thd)
 bool Item_sum::init_sum_func_check(THD *thd)
 {
   SELECT_LEX *curr_sel= thd->lex->current_select;
+  DBUG_ASSERT(curr_sel);
   if (!curr_sel->name_visibility_map)
   {
     for (SELECT_LEX *sl= curr_sel; sl; sl= sl->context.outer_select())
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index a723980..ef6524c 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -518,6 +518,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
   if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) &&      // 0
         !child_select->is_part_of_union() &&                          // 1
         parent_unit->first_select()->leaf_tables.elements &&          // 2
+        child_select->outer_select() &&
         child_select->outer_select()->leaf_tables.elements &&         // 2A
         subquery_types_allow_materialization(in_subs) &&
         (in_subs->is_top_level_item() ||                               //3
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 0d39a4d..15fc876 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -6006,9 +6006,17 @@ bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd,
   bounds->m_index->sp_lex_in_use= true;
   sphead->reset_lex(thd, bounds->m_index);
   DBUG_ASSERT(thd->lex != this);
-  if (!(item= new (thd->mem_root) Item_field(thd,
-                                             thd->lex->current_context(),
-                                             NullS, NullS, &name)))
+  /*
+    We pass NULL as Name_resolution_context here.
+    It's OK, fix_fields() will not be called for this Item_field created.
+    Item_field is only needed for LEX::sp_for_loop_cursor_declarations()
+    and is used to transfer the loop index variable name, "rec" in this example:
+      FOR rec IN (SELECT * FROM t1)
+      DO
+        SELECT rec.a, rec.b;
+      END FOR;
+  */
+  if (!(item= new (thd->mem_root) Item_field(thd, NULL, NullS, NullS, &name)))
     return true;
   bounds->m_index->set_item_and_free_list(item, NULL);
   if (thd->lex->sphead->restore_lex(thd))
@@ -6112,6 +6120,19 @@ bool LEX::sp_for_loop_intrange_declarations(THD *thd, Lex_for_loop_st *loop,
                                             const LEX_CSTRING *index,
                                             const Lex_for_loop_bounds_st &bounds)
 {
+  Item *item;
+  if ((item= bounds.m_index->get_item())->type() == Item::FIELD_ITEM)
+  {
+    // We're here is the lower bound is unknown identifier
+    my_error(ER_SP_UNDECLARED_VAR, MYF(0), item->full_name());
+    return true;
+  }
+  if ((item= bounds.m_upper_bound->get_item())->type() == Item::FIELD_ITEM)
+  {
+    // We're here is the upper bound is unknown identifier
+    my_error(ER_SP_UNDECLARED_VAR, MYF(0), item->full_name());
+    return true;
+  }
   if (!(loop->m_index=
         bounds.m_index->sp_add_for_loop_variable(thd, index,
                                                  bounds.m_index->get_item())))
@@ -6989,6 +7010,38 @@ bool LEX::add_resignal_statement(THD *thd, const sp_condition_value *v)
 }
 
 
+/*
+  Make an Item when an identifier is found in the FOR loop bounds:
+    FOR rec IN cursor
+    FOR var IN var1 .. xxx
+    FOR var IN row1.field1 .. xxx
+  When we parse the first expression after the "IN" keyword,
+  we don't know yet if it's a cursor name, or a scalar SP variable name,
+  or a field of a ROW SP variable. Here we create Item_field to remember
+  the fully qualified name. Later sp_for_loop_cursor_declarations()
+  detects how to treat this name properly.
+*/
+Item *LEX::create_item_for_loop_bound(THD *thd,
+                                      const LEX_CSTRING *a,
+                                      const LEX_CSTRING *b,
+                                      const LEX_CSTRING *c)
+{
+  /*
+    Pass NULL as the name resolution context.
+    This is OK, fix_fields() won't be called for this Item_field.
+  */
+  return new (thd->mem_root) Item_field(thd, NULL, a->str, b->str, c);
+}
+
+
+bool LEX::check_expr_allows_fields_or_error(THD *thd, const char *name) const
+{
+  if (select_stack_top > 0)
+    return false; // OK, fields are allowed
+  my_error(ER_BAD_FIELD_ERROR, MYF(0), name, thd->where);
+  return true;    // Error, fields are not allowed
+}
+
 Item *LEX::create_item_ident_nospvar(THD *thd,
                                      const LEX_CSTRING *a,
                                      const LEX_CSTRING *b)
@@ -7011,12 +7064,11 @@ Item *LEX::create_item_ident_nospvar(THD *thd,
     my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), a->str, thd->where);
     return NULL;
   }
-  if ((current_select->parsing_place != IN_HAVING) ||
-      (current_select->get_in_sum_expr() > 0))
-    return new (thd->mem_root) Item_field(thd, current_context(),
-                                          NullS, a->str, b);
-  return new (thd->mem_root) Item_ref(thd, current_context(),
-                                      NullS, a->str, b);
+
+  if (current_select->parsing_place == FOR_LOOP_BOUND)
+    return create_item_for_loop_bound(thd, &null_clex_str, a, b);
+
+  return create_item_ident_field(thd, NullS, a->str, b);
 }
 
 
@@ -7217,12 +7269,11 @@ Item *LEX::create_item_ident(THD *thd,
     my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), b->str, thd->where);
     return NULL;
   }
-  if (current_select->parsing_place != IN_HAVING ||
-      current_select->get_in_sum_expr() > 0)
-    return new (thd->mem_root) Item_field(thd, current_context(),
-                                          schema, b->str, c);
-  return new (thd->mem_root) Item_ref(thd, current_context(),
-                                      schema, b->str, c);
+
+  if (current_select->parsing_place == FOR_LOOP_BOUND)
+    return create_item_for_loop_bound(thd, &null_clex_str, b, c);
+
+  return create_item_ident_field(thd, schema, b->str, c);
 }
 
 
@@ -7298,15 +7349,19 @@ bool LEX::set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val)
 }
 
 
-Item *LEX::create_item_ident_nosp(THD *thd, LEX_CSTRING *name)
+Item *LEX::create_item_ident_field(THD *thd, const char *db,
+                                   const char *table, const LEX_CSTRING *name)
 {
+  if (check_expr_allows_fields_or_error(thd, name->str))
+    return NULL;
+
   if (current_select->parsing_place != IN_HAVING ||
       current_select->get_in_sum_expr() > 0)
     return new (thd->mem_root) Item_field(thd, current_context(),
-                                          NullS, NullS, name);
+                                          db, table, name);
 
   return new (thd->mem_root) Item_ref(thd, current_context(),
-                                      NullS, NullS, name);
+                                      db, table, name);
 }
 
 
@@ -7352,6 +7407,11 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name,
     if (!my_strcasecmp(system_charset_info, name->str, "SQLERRM"))
       return new (thd->mem_root) Item_func_sqlerrm(thd);
   }
+
+  if (current_select->parsing_place == FOR_LOOP_BOUND)
+    return create_item_for_loop_bound(thd, &null_clex_str, &null_clex_str,
+                                      name);
+
   return create_item_ident_nosp(thd, name);
 }
 
@@ -8538,3 +8598,29 @@ bool LEX::insert_select_hack(SELECT_LEX *sel)
 
   DBUG_RETURN(FALSE);
 }
+
+
+/*
+  Create an Item_singlerow_subselect for a query expression.
+*/
+Item *LEX::create_item_query_expression(THD *thd,
+                                        const char *tok_start,
+                                        st_select_lex_unit *unit)
+{
+  if (!expr_allows_subselect || sql_command == SQLCOM_PURGE)
+  {
+    thd->parse_error(ER_SYNTAX_ERROR, tok_start);
+    return NULL;
+  }
+
+  // Add the subtree of subquery to the current SELECT_LEX
+  SELECT_LEX *curr_sel= select_stack_head();
+  DBUG_ASSERT(current_select == curr_sel);
+  if (!curr_sel)
+    curr_sel= &builtin_select;
+  curr_sel->register_unit(unit, &curr_sel->context);
+  curr_sel->add_statistics(unit);
+
+  return new (thd->mem_root)
+    Item_singlerow_subselect(thd, unit->first_select());
+}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 4049ac8..ff348a8 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -606,6 +606,7 @@ class st_select_lex_node {
   }
 
   inline st_select_lex_node* get_master() { return master; }
+  inline st_select_lex_node* get_slave() { return slave; }
   void include_down(st_select_lex_node *upper);
   void add_slave(st_select_lex_node *slave_arg);
   void include_neighbour(st_select_lex_node *before);
@@ -1115,6 +1116,10 @@ class st_select_lex: public st_select_lex_node
   {
     master= (st_select_lex_node *)master_unit;
   }
+  void set_master(st_select_lex *master_arg)
+  {
+    master= master_arg;
+  }
   st_select_lex_unit* first_inner_unit() 
   { 
     return (st_select_lex_unit*) slave; 
@@ -2850,6 +2855,12 @@ struct LEX: public Query_tables_list
   bool sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop);
   bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop);
 
+  /*
+    Check if Item_field and Item_ref are allowed in the current statement.
+    @retval false OK (fields are allowed)
+    @retval true  ERROR (fields are not allowed). Error is raised.
+  */
+  bool check_expr_allows_fields_or_error(THD *thd, const char *name) const;
 public:
   void parse_error(uint err_number= ER_SYNTAX_ERROR);
   inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;}
@@ -3321,12 +3332,25 @@ struct LEX: public Query_tables_list
     DBUG_RETURN(select_lex);
   }
 
+  SELECT_LEX *current_select_or_default()
+  {
+    return current_select ? current_select : &builtin_select;
+  }
+
   bool copy_db_to(LEX_CSTRING *to);
 
   Name_resolution_context *current_context()
   {
     return context_stack.head();
   }
+  Name_resolution_context *current_context_or_default()
+  {
+    Name_resolution_context *ctx= current_context();
+    if (!ctx)
+      return &builtin_select.context;
+    return ctx;
+  }
+
   /*
     Restore the LEX and THD in case of a parse error.
   */
@@ -3493,7 +3517,12 @@ struct LEX: public Query_tables_list
   Item_splocal *create_item_for_sp_var(LEX_CSTRING *name, sp_variable *spvar,
                                        const char *start, const char *end);
 
-  Item *create_item_ident_nosp(THD *thd, LEX_CSTRING *name);
+  Item *create_item_ident_field(THD *thd, const char *db, const char *table,
+                                const LEX_CSTRING *name);
+  Item *create_item_ident_nosp(THD *thd, LEX_CSTRING *name)
+  {
+    return create_item_ident_field(thd, NullS, NullS, name);
+  }
   Item *create_item_ident_sp(THD *thd, LEX_CSTRING *name,
                              const char *start, const char *end);
   Item *create_item_ident(THD *thd, LEX_CSTRING *name,
@@ -3623,6 +3652,10 @@ struct LEX: public Query_tables_list
                           const char *start,
                           const char *end);
 
+  Item *create_item_query_expression(THD *thd,
+                                     const char *tok_start,
+                                     st_select_lex_unit *unit);
+
   Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace);
   Item *make_item_func_substr(THD *thd, Item *a, Item *b, Item *c);
   Item *make_item_func_substr(THD *thd, Item *a, Item *b);
@@ -3800,6 +3833,17 @@ struct LEX: public Query_tables_list
            sp_for_loop_cursor_finalize(thd, loop) :
            sp_for_loop_intrange_finalize(thd, loop);
   }
+
+  /*
+    Make an Item when an identifier is found in the FOR loop bounds:
+      FOR rec IN cursor
+      FOR rec IN var1 .. var2
+      FOR rec IN row1.field1 .. xxx
+  */
+  Item *create_item_for_loop_bound(THD *thd,
+                                   const LEX_CSTRING *a,
+                                   const LEX_CSTRING *b,
+                                   const LEX_CSTRING *c);
   /* End of FOR LOOP methods */
 
   bool add_signal_statement(THD *thd, const class sp_condition_value *value);
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 4de8b8c..9c876c0 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -361,6 +361,7 @@ enum enum_parsing_place
   IN_PART_FUNC,
   BEFORE_OPT_LIST,
   AFTER_LIST,
+  FOR_LOOP_BOUND,
   PARSING_PLACE_SIZE /* always should be the last */
 };
 
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index d4122fe..d6758a5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2222,12 +2222,7 @@ deallocate_or_drop:
         ;
 
 prepare:
-          PREPARE_SYM
-          {
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          ident FROM prepare_src
+          PREPARE_SYM ident FROM prepare_src
           {
             LEX *lex= thd->lex;
             if (lex->table_or_sp_used())
@@ -2236,8 +2231,7 @@ prepare:
             if (Lex->check_main_unit_semantics())
               MYSQL_YYABORT;
             lex->sql_command= SQLCOM_PREPARE;
-            lex->prepared_stmt_name= $3;
-            Lex->pop_select(); //main select
+            lex->prepared_stmt_name= $2;
           }
         ;
 
@@ -2256,21 +2250,13 @@ execute:
             LEX *lex= thd->lex;
             lex->sql_command= SQLCOM_EXECUTE;
             lex->prepared_stmt_name= $2;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           execute_using
           {
-            Lex->pop_select(); //main select
             if (Lex->check_main_unit_semantics())
               MYSQL_YYABORT;
           }
-        | EXECUTE_SYM IMMEDIATE_SYM
-          {
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          prepare_src
+        | EXECUTE_SYM IMMEDIATE_SYM prepare_src
           {
             if (Lex->table_or_sp_used())
               my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
@@ -2279,7 +2265,6 @@ execute:
           }
           execute_using
           {
-            Lex->pop_select(); //main select
             if (Lex->check_main_unit_semantics())
               MYSQL_YYABORT;
           }
@@ -2812,7 +2797,6 @@ create:
             if (Lex->main_select_push())
               MYSQL_YYABORT;
             Lex->create_info.set($1);
-            
           }
           sf_tail_aggregate
           {
@@ -3306,13 +3290,8 @@ call:
           {
             if (Lex->call_statement_start(thd, $2))
               MYSQL_YYABORT;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          opt_sp_cparam_list
-          {
-            Lex->pop_select(); //main select
           }
+          opt_sp_cparam_list {}
         ;
 
 /* CALL parameters */
@@ -3729,16 +3708,10 @@ sp_hcond:
         ;
 
 signal_stmt:
-          SIGNAL_SYM
-          {
-            if (Lex->main_select_push())
-              YYABORT;
-          }
-          signal_value opt_set_signal_information
+          SIGNAL_SYM signal_value opt_set_signal_information
           {
-            if (Lex->add_signal_statement(thd, $3))
+            if (Lex->add_signal_statement(thd, $2))
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -3864,14 +3837,9 @@ resignal_stmt:
         ;
 
 get_diagnostics:
-          GET_SYM which_area DIAGNOSTICS_SYM
+          GET_SYM which_area DIAGNOSTICS_SYM diagnostics_information
           {
-            if (Lex->main_select_push())
-              YYABORT;
-          }
-          diagnostics_information
-          {
-            Diagnostics_information *info= $5;
+            Diagnostics_information *info= $4;
 
             info->set_which_da($2);
 
@@ -3880,7 +3848,6 @@ get_diagnostics:
 
             if (Lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -4048,16 +4015,7 @@ sp_decl_idents:
 
 sp_opt_default:
           /* Empty */ { $$ = NULL; }
-        | DEFAULT
-          {
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          expr
-          {
-            Lex->pop_select(); //main select
-            $$ = $3;
-          }
+        | DEFAULT expr { $$ = $2; }
         ;
 
 /*
@@ -4159,15 +4117,10 @@ sp_proc_stmt_statement:
 
 sp_proc_stmt_return:
           RETURN_SYM 
-          {
-            Lex->sphead->reset_lex(thd);
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
+          { Lex->sphead->reset_lex(thd); }
           expr
           {
             LEX *lex= Lex;
-            lex->pop_select(); //main select
             sp_head *sp= lex->sphead;
             if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
                                                  $3, lex) ||
@@ -4205,8 +4158,6 @@ assignment_source_expr:
           {
             DBUG_ASSERT(thd->free_list == NULL);
             Lex->sphead->reset_lex(thd, $1);
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           expr
           {
@@ -4215,7 +4166,6 @@ assignment_source_expr:
             $$->sp_lex_in_use= true;
             $$->set_item_and_free_list($3, thd->free_list);
             thd->free_list= NULL;
-            Lex->pop_select(); //main select
             if ($$->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4225,6 +4175,7 @@ for_loop_bound_expr:
           assignment_source_lex
           {
             Lex->sphead->reset_lex(thd, $1);
+            Lex->current_select->parsing_place= FOR_LOOP_BOUND;
           }
           expr
           {
@@ -4234,6 +4185,7 @@ for_loop_bound_expr:
             $$->set_item_and_free_list($3, NULL);
             if ($$->sphead->restore_lex(thd))
               MYSQL_YYABORT;
+            Lex->current_select->parsing_place= NO_MATTER;
           }
         ;
 
@@ -4348,14 +4300,9 @@ sp_fetch_list:
         ;
 
 sp_if:
-          {
-            Lex->sphead->reset_lex(thd);
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
+          { Lex->sphead->reset_lex(thd); }
           expr THEN_SYM
           {
-            Lex->pop_select(); //main select
             LEX *lex= Lex;
             sp_head *sp= lex->sphead;
             sp_pcontext *ctx= lex->spcont;
@@ -4467,18 +4414,12 @@ case_stmt_specification:
         ;
 
 case_stmt_body:
-          {
-            Lex->sphead->reset_lex(thd); /* For expr $2 */
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
+          { Lex->sphead->reset_lex(thd); /* For expr $2 */ }
           expr
           {
             if (Lex->case_stmt_action_expr($2))
               MYSQL_YYABORT;
 
-            Lex->pop_select(); //main select
             if (Lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4502,9 +4443,6 @@ simple_when_clause:
           WHEN_SYM
           {
             Lex->sphead->reset_lex(thd); /* For expr $3 */
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           expr
           {
@@ -4513,8 +4451,6 @@ simple_when_clause:
             LEX *lex= Lex;
             if (lex->case_stmt_action_when($3, true))
               MYSQL_YYABORT;
-
-            lex->pop_select(); //main select
             /* For expr $3 */
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
@@ -4531,17 +4467,12 @@ searched_when_clause:
           WHEN_SYM
           {
             Lex->sphead->reset_lex(thd); /* For expr $3 */
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           expr
           {
             LEX *lex= Lex;
             if (lex->case_stmt_action_when($3, false))
               MYSQL_YYABORT;
-
-            lex->pop_select(); //main select
             /* For expr $3 */
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
@@ -4690,7 +4621,6 @@ while_body:
             LEX *lex= Lex;
             if (lex->sp_while_loop_expression(thd, $1))
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select pushed before while_body use
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4703,12 +4633,7 @@ while_body:
 
 repeat_body:
           sp_proc_stmts1 UNTIL_SYM 
-          {
-            Lex->sphead->reset_lex(thd);
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
+          { Lex->sphead->reset_lex(thd); }
           expr END REPEAT_SYM
           {
             LEX *lex= Lex;
@@ -4719,8 +4644,6 @@ repeat_body:
             if (i == NULL ||
                 lex->sphead->add_instr(i))
               MYSQL_YYABORT;
-
-            lex->pop_select(); //main select
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
             /* We can shortcut the cont_backpatch here */
@@ -4749,12 +4672,8 @@ sp_labeled_control:
             if (Lex->sp_push_loop_label(thd, &$1))
               MYSQL_YYABORT;
             Lex->sphead->reset_lex(thd);
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           while_body pop_sp_loop_label
-
           { }
         | sp_label FOR_SYM
           {
@@ -4806,13 +4725,9 @@ sp_unlabeled_control:
             if (Lex->sp_push_loop_empty_label(thd))
               MYSQL_YYABORT;
             Lex->sphead->reset_lex(thd);
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           while_body
           {
-            // while body pop main select
             Lex->sp_pop_loop_empty_label(thd);
           }
         | FOR_SYM
@@ -6898,22 +6813,7 @@ parenthesized_expr:
           remember_tok_start
           query_expression
           {
-            if (!Lex->expr_allows_subselect ||
-               Lex->sql_command == (int)SQLCOM_PURGE)
-            {
-              thd->parse_error(ER_SYNTAX_ERROR, $1);
-              MYSQL_YYABORT;
-            }
-
-            // Add the subtree of subquery to the current SELECT_LEX
-            SELECT_LEX *curr_sel= Lex->select_stack_head();
-            DBUG_ASSERT(Lex->current_select == curr_sel);
-            curr_sel->register_unit($2, &curr_sel->context);
-            curr_sel->add_statistics($2);
-
-            $$= new (thd->mem_root)
-              Item_singlerow_subselect(thd, $2->first_select());
-            if ($$ == NULL)
+            if (!($$= Lex->create_item_query_expression(thd, $1, $2)))
               MYSQL_YYABORT;
           }
         | expr
@@ -8756,13 +8656,9 @@ checksum:
             lex->sql_command = SQLCOM_CHECKSUM;
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_list opt_checksum_type
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 opt_checksum_type:
@@ -8788,8 +8684,6 @@ repair:
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           repair_table_or_view
           {
@@ -8798,7 +8692,6 @@ repair:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_repair_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -8827,8 +8720,6 @@ analyze:
           ANALYZE_SYM opt_no_write_to_binlog table_or_tables
           {
             LEX *lex=Lex;
-            if (lex->main_select_push())
-              YYABORT;
             lex->sql_command = SQLCOM_ANALYZE;
             lex->no_write_to_binlog= $2;
             lex->check_opt.init();
@@ -8843,7 +8734,6 @@ analyze:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_analyze_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -8960,8 +8850,6 @@ check:    CHECK_SYM
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           check_view_or_table
           {
@@ -8972,7 +8860,6 @@ check:    CHECK_SYM
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_check_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -9010,8 +8897,6 @@ optimize:
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_list opt_lock_wait_timeout
           {
@@ -9020,7 +8905,6 @@ optimize:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_optimize_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -9034,13 +8918,9 @@ rename:
           RENAME table_or_tables
           {
             Lex->sql_command= SQLCOM_RENAME_TABLE;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_to_table_list
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         | RENAME USER_SYM clear_privileges rename_list
           {
             Lex->sql_command = SQLCOM_RENAME_USER;
@@ -9134,13 +9014,9 @@ preload:
             LEX *lex=Lex;
             lex->sql_command=SQLCOM_PRELOAD_KEYS;
             lex->alter_info.reset();
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           preload_list_or_parts
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 preload_list_or_parts:
@@ -9526,6 +9402,7 @@ query_expression:
           }
         ;
 
+
 subselect:
           remember_tok_start
           query_expression
@@ -10332,7 +10209,21 @@ column_default_non_parenthesized_expr:
         | param_marker { $$= $1; }
         | variable
         | sum_expr
+          {
+            if (!Lex->select_stack_top)
+            {
+              my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
+              MYSQL_YYABORT;
+            }
+          }
         | window_func_expr
+          {
+            if (!Lex->select_stack_top)
+            {
+               my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0));
+               MYSQL_YYABORT;
+            }
+          }
         | inverse_distribution_function
         | ROW_SYM '(' expr ',' expr_list ')'
           {
@@ -11456,7 +11347,7 @@ sum_expr:
             SELECT_LEX *sel= Select;
             sel->in_sum_expr--;
             $$= new (thd->mem_root)
-                  Item_func_group_concat(thd, Lex->current_context(),
+                  Item_func_group_concat(thd, Lex->current_context_or_default(),
                                         $3, $5,
                                         sel->gorder_list, $7, $8,
                                         sel->select_limit,
@@ -13160,15 +13051,10 @@ do:
             LEX *lex=Lex;
             lex->sql_command = SQLCOM_DO;
             mysql_init_select(lex);
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           expr_list
           {
             Lex->insert_list= $3;
-            Lex->pop_select(); //main select
-            if (Lex->check_main_unit_semantics())
-              MYSQL_YYABORT;
           }
         ;
 
@@ -13310,7 +13196,8 @@ table_list:
 table_name:
           table_ident
           {
-            if (!Select->add_table_to_list(thd, $1, NULL,
+            if (!thd->lex->current_select_or_default()->
+                                           add_table_to_list(thd, $1, NULL,
                                            TL_OPTION_UPDATING,
                                            YYPS->m_lock_type,
                                            YYPS->m_mdl_type))
@@ -13726,6 +13613,7 @@ delete_part2:
         | HISTORY_SYM delete_single_table opt_delete_system_time
           {
             Lex->last_table()->vers_conditions= Lex->vers_conditions;
+            Lex->pop_select();
           }
         ;
 
@@ -13852,8 +13740,6 @@ truncate:
           {
             LEX* lex= Lex;
             lex->sql_command= SQLCOM_TRUNCATE;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
             lex->alter_info.reset();
             lex->builtin_select.options= 0;
             lex->builtin_select.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
@@ -13868,7 +13754,6 @@ truncate:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -14680,13 +14565,9 @@ purge:
             LEX *lex=Lex;
             lex->type=0;
             lex->sql_command = SQLCOM_PURGE;
-            if (lex->main_select_push())
-              MYSQL_YYABORT;
           }
           purge_options
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 purge_options:
@@ -14715,8 +14596,6 @@ kill:
           KILL_SYM
           {
             LEX *lex=Lex;
-            if (lex->main_select_push())
-              YYABORT;
             lex->value_list.empty();
             lex->users_list.empty();
             lex->sql_command= SQLCOM_KILL;
@@ -14725,7 +14604,6 @@ kill:
           kill_type kill_option kill_expr
           {
             Lex->kill_signal= (killed_state) ($3 | $4);
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -16545,13 +16423,9 @@ lock:
             if (lex->sphead)
               my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK"));
             lex->sql_command= SQLCOM_LOCK_TABLES;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_lock_list opt_lock_wait_timeout
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 opt_lock_wait_timeout:
@@ -16616,13 +16490,9 @@ unlock:
             if (lex->sphead)
               my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "UNLOCK"));
             lex->sql_command= SQLCOM_UNLOCK_TABLES;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_or_tables
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 /*
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 55d837b..1b80f78 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -1640,22 +1640,14 @@ deallocate_or_drop:
         ;
 
 prepare:
-          PREPARE_SYM
-          {
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          ident FROM prepare_src
+          PREPARE_SYM ident FROM prepare_src
           {
             LEX *lex= thd->lex;
             if (lex->table_or_sp_used())
               my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
                                "PREPARE..FROM"));
-            if (Lex->check_main_unit_semantics())
-              MYSQL_YYABORT;
             lex->sql_command= SQLCOM_PREPARE;
-            lex->prepared_stmt_name= $3;
-            Lex->pop_select(); //main select
+            lex->prepared_stmt_name= $2;
           }
         ;
 
@@ -1674,21 +1666,10 @@ execute:
             LEX *lex= thd->lex;
             lex->sql_command= SQLCOM_EXECUTE;
             lex->prepared_stmt_name= $2;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           execute_using
-          {
-            Lex->pop_select(); //main select
-            if (Lex->check_main_unit_semantics())
-              MYSQL_YYABORT;
-          }
-        | EXECUTE_SYM IMMEDIATE_SYM
-          {
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          prepare_src
+          {}
+        | EXECUTE_SYM IMMEDIATE_SYM prepare_src
           {
             if (Lex->table_or_sp_used())
               my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
@@ -1696,11 +1677,7 @@ execute:
             Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE;
           }
           execute_using
-          {
-            Lex->pop_select(); //main select
-            if (Lex->check_main_unit_semantics())
-              MYSQL_YYABORT;
-          }
+          {}
         ;
 
 execute_using:
@@ -2952,13 +2929,8 @@ call:
           {
             if (Lex->call_statement_start(thd, $2))
               MYSQL_YYABORT;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          opt_sp_cparam_list
-          {
-            Lex->pop_select(); //main select
           }
+          opt_sp_cparam_list {}
         ;
 
 /* CALL parameters */
@@ -3488,16 +3460,10 @@ raise_stmt:
         ;
 
 signal_stmt:
-          SIGNAL_SYM
+          SIGNAL_SYM signal_value opt_set_signal_information
           {
-            if (Lex->main_select_push())
-              YYABORT;
-          }
-          signal_value opt_set_signal_information
-          {
-            if (Lex->add_signal_statement(thd, $3))
+            if (Lex->add_signal_statement(thd, $2))
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -3623,14 +3589,9 @@ resignal_stmt:
         ;
 
 get_diagnostics:
-          GET_SYM which_area DIAGNOSTICS_SYM
+          GET_SYM which_area DIAGNOSTICS_SYM diagnostics_information
           {
-            if (Lex->main_select_push())
-              YYABORT;
-          }
-          diagnostics_information
-          {
-            Diagnostics_information *info= $5;
+            Diagnostics_information *info= $4;
 
             info->set_which_da($2);
 
@@ -3639,7 +3600,6 @@ get_diagnostics:
 
             if (Lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -3820,26 +3780,8 @@ sp_decl_idents:
 
 sp_opt_default:
           /* Empty */ { $$ = NULL; }
-        | DEFAULT
-          {
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          expr
-          {
-            Lex->pop_select(); //main select
-            $$ = $3;
-          }
-        | SET_VAR
-          {
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
-          expr
-          {
-            Lex->pop_select(); //main select
-            $$ = $3;
-          }
+        | DEFAULT expr { $$ = $2; }
+        | SET_VAR expr { $$ = $2; }
         ;
 
 sp_proc_stmt:
@@ -3956,15 +3898,10 @@ sp_proc_stmt_statement:
 
 sp_proc_stmt_return:
           RETURN_SYM 
-          {
-            Lex->sphead->reset_lex(thd);
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
+          { Lex->sphead->reset_lex(thd); }
           expr
           {
             LEX *lex= Lex;
-            lex->pop_select(); //main select
             sp_head *sp= lex->sphead;
             if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
                                                  $3, lex) ||
@@ -4079,8 +4016,6 @@ assignment_source_expr:
           {
             DBUG_ASSERT(thd->free_list == NULL);
             Lex->sphead->reset_lex(thd, $1);
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           expr
           {
@@ -4089,7 +4024,6 @@ assignment_source_expr:
             $$->sp_lex_in_use= true;
             $$->set_item_and_free_list($3, thd->free_list);
             thd->free_list= NULL;
-            Lex->pop_select(); //main select
             if ($$->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4099,6 +4033,7 @@ for_loop_bound_expr:
           assignment_source_lex
           {
             Lex->sphead->reset_lex(thd, $1);
+            Lex->current_select->parsing_place= FOR_LOOP_BOUND;
           }
           expr
           {
@@ -4108,6 +4043,7 @@ for_loop_bound_expr:
             $$->set_item_and_free_list($3, NULL);
             if ($$->sphead->restore_lex(thd))
               MYSQL_YYABORT;
+            Lex->current_select->parsing_place= NO_MATTER;
           }
         ;
 
@@ -4210,14 +4146,9 @@ sp_fetch_list:
         ;
 
 sp_if:
-          {
-            Lex->sphead->reset_lex(thd);
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
+          { Lex->sphead->reset_lex(thd); }
           expr THEN_SYM
           {
-            Lex->pop_select(); //main select
             LEX *lex= Lex;
             sp_head *sp= lex->sphead;
             sp_pcontext *ctx= lex->spcont;
@@ -4329,18 +4260,12 @@ case_stmt_specification:
         ;
 
 case_stmt_body:
-          {
-            Lex->sphead->reset_lex(thd); /* For expr $2 */
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
+          { Lex->sphead->reset_lex(thd); /* For expr $2 */ }
           expr
           {
             if (Lex->case_stmt_action_expr($2))
               MYSQL_YYABORT;
 
-            Lex->pop_select(); //main select
             if (Lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4364,9 +4289,6 @@ simple_when_clause:
           WHEN_SYM
           {
             Lex->sphead->reset_lex(thd); /* For expr $3 */
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           expr
           {
@@ -4375,8 +4297,6 @@ simple_when_clause:
             LEX *lex= Lex;
             if (lex->case_stmt_action_when($3, true))
               MYSQL_YYABORT;
-
-            lex->pop_select(); //main select
             /* For expr $3 */
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
@@ -4393,17 +4313,12 @@ searched_when_clause:
           WHEN_SYM
           {
             Lex->sphead->reset_lex(thd); /* For expr $3 */
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           expr
           {
             LEX *lex= Lex;
             if (lex->case_stmt_action_when($3, false))
               MYSQL_YYABORT;
-
-            lex->pop_select(); //main select
             /* For expr $3 */
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
@@ -4643,7 +4558,6 @@ while_body:
             LEX *lex= Lex;
             if (lex->sp_while_loop_expression(thd, $1))
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select pushed before while_body use
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4656,12 +4570,7 @@ while_body:
 
 repeat_body:
           sp_proc_stmts1 UNTIL_SYM 
-          {
-            Lex->sphead->reset_lex(thd);
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
-          }
+          { Lex->sphead->reset_lex(thd); }
           expr END REPEAT_SYM
           {
             LEX *lex= Lex;
@@ -4672,8 +4581,6 @@ repeat_body:
             if (i == NULL ||
                 lex->sphead->add_instr(i))
               MYSQL_YYABORT;
-
-            lex->pop_select(); //main select
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
             /* We can shortcut the cont_backpatch here */
@@ -4702,12 +4609,8 @@ sp_labeled_control:
             if (Lex->sp_push_loop_label(thd, &$1))
               MYSQL_YYABORT;
             Lex->sphead->reset_lex(thd);
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           while_body pop_sp_loop_label
-
           { }
         | labels_declaration_oracle FOR_SYM
           {
@@ -4759,13 +4662,9 @@ sp_unlabeled_control:
             if (Lex->sp_push_loop_empty_label(thd))
               MYSQL_YYABORT;
             Lex->sphead->reset_lex(thd);
-
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           while_body
           {
-            // while body pop main select
             Lex->sp_pop_loop_empty_label(thd);
           }
         | FOR_SYM
@@ -6667,22 +6566,7 @@ parenthesized_expr:
           remember_tok_start
           query_expression
           {
-            if (!Lex->expr_allows_subselect ||
-               Lex->sql_command == (int)SQLCOM_PURGE)
-            {
-              thd->parse_error(ER_SYNTAX_ERROR, $1);
-              MYSQL_YYABORT;
-            }
-
-            // Add the subtree of subquery to the current SELECT_LEX
-            SELECT_LEX *curr_sel= Lex->select_stack_head();
-            DBUG_ASSERT(Lex->current_select == curr_sel);
-            curr_sel->register_unit($2, &curr_sel->context);
-            curr_sel->add_statistics($2);
-
-            $$= new (thd->mem_root)
-              Item_singlerow_subselect(thd, $2->first_select());
-            if ($$ == NULL)
+            if (!($$= Lex->create_item_query_expression(thd, $1, $2)))
               MYSQL_YYABORT;
           }
         | expr
@@ -8579,13 +8463,9 @@ checksum:
             lex->sql_command = SQLCOM_CHECKSUM;
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_list opt_checksum_type
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 opt_checksum_type:
@@ -8611,8 +8491,6 @@ repair:
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           repair_table_or_view
           {
@@ -8621,7 +8499,6 @@ repair:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_repair_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -8650,8 +8527,6 @@ analyze:
           ANALYZE_SYM opt_no_write_to_binlog table_or_tables
           {
             LEX *lex=Lex;
-            if (lex->main_select_push())
-              YYABORT;
             lex->sql_command = SQLCOM_ANALYZE;
             lex->no_write_to_binlog= $2;
             lex->check_opt.init();
@@ -8666,7 +8541,6 @@ analyze:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_analyze_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -8783,8 +8657,6 @@ check:    CHECK_SYM
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           check_view_or_table
           {
@@ -8795,7 +8667,6 @@ check:    CHECK_SYM
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_check_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -8833,8 +8704,6 @@ optimize:
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_list opt_lock_wait_timeout
           {
@@ -8843,7 +8712,6 @@ optimize:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_optimize_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -8857,13 +8725,9 @@ rename:
           RENAME table_or_tables
           {
             Lex->sql_command= SQLCOM_RENAME_TABLE;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_to_table_list
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         | RENAME USER_SYM clear_privileges rename_list
           {
             Lex->sql_command = SQLCOM_RENAME_USER;
@@ -8957,13 +8821,9 @@ preload:
             LEX *lex=Lex;
             lex->sql_command=SQLCOM_PRELOAD_KEYS;
             lex->alter_info.reset();
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           preload_list_or_parts
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 preload_list_or_parts:
@@ -10140,7 +10000,21 @@ column_default_non_parenthesized_expr:
         | param_marker { $$= $1; }
         | variable
         | sum_expr
+          {
+            if (!Lex->select_stack_top)
+            {
+              my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
+              MYSQL_YYABORT;
+            }
+          }
         | window_func_expr
+          {
+            if (!Lex->select_stack_top)
+            {
+               my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0));
+               MYSQL_YYABORT;
+            }
+          }
         | inverse_distribution_function
         | ROW_SYM '(' expr ',' expr_list ')'
           {
@@ -11263,7 +11137,7 @@ sum_expr:
             SELECT_LEX *sel= Select;
             sel->in_sum_expr--;
             $$= new (thd->mem_root)
-                  Item_func_group_concat(thd, Lex->current_context(),
+                  Item_func_group_concat(thd, Lex->current_context_or_default(),
                                         $3, $5,
                                         sel->gorder_list, $7, $8,
                                         sel->select_limit,
@@ -12976,15 +12850,10 @@ do:
             LEX *lex=Lex;
             lex->sql_command = SQLCOM_DO;
             mysql_init_select(lex);
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           expr_list
           {
             Lex->insert_list= $3;
-            Lex->pop_select(); //main select
-            if (Lex->check_main_unit_semantics())
-              MYSQL_YYABORT;
           }
         ;
 
@@ -13666,7 +13535,6 @@ truncate:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
-            Lex->pop_select(); //main select
           }
           opt_truncate_table_storage_clause { }
         ;
@@ -14459,13 +14327,9 @@ purge:
             LEX *lex=Lex;
             lex->type=0;
             lex->sql_command = SQLCOM_PURGE;
-            if (lex->main_select_push())
-              MYSQL_YYABORT;
           }
           purge_options
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 purge_options:
@@ -14483,8 +14347,6 @@ purge_option:
             lex->value_list.empty();
             lex->value_list.push_front($2, thd->mem_root);
             lex->sql_command= SQLCOM_PURGE_BEFORE;
-            if (Lex->check_main_unit_semantics())
-              MYSQL_YYABORT;
           }
         ;
 
@@ -14494,8 +14356,6 @@ kill:
           KILL_SYM
           {
             LEX *lex=Lex;
-            if (lex->main_select_push())
-              YYABORT;
             lex->value_list.empty();
             lex->users_list.empty();
             lex->sql_command= SQLCOM_KILL;
@@ -14504,7 +14364,6 @@ kill:
           kill_type kill_option kill_expr
           {
             Lex->kill_signal= (killed_state) ($3 | $4);
-            Lex->pop_select(); //main select
           }
         ;
 
@@ -16457,13 +16316,9 @@ lock:
             if (lex->sphead)
               my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK"));
             lex->sql_command= SQLCOM_LOCK_TABLES;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_lock_list opt_lock_wait_timeout
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 opt_lock_wait_timeout:
@@ -16528,13 +16383,9 @@ unlock:
             if (lex->sphead)
               my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "UNLOCK"));
             lex->sql_command= SQLCOM_UNLOCK_TABLES;
-            if (Lex->main_select_push())
-              MYSQL_YYABORT;
           }
           table_or_tables
-          {
-            Lex->pop_select(); //main select
-          }
+          {}
         ;
 
 /*

Follow ups

References