List:Commits« Previous MessageNext Message »
From:Bjorn Munch Date:September 10 2010 8:07am
Subject:bzr commit into mysql-trunk-merge branch (bjorn.munch:3193)
View as plain text  
#At file:///home/bm136801/my/merge-tr/ based on revid:bjorn.munch@stripped

 3193 Bjorn Munch	2010-09-10 [merge]
      upmerge from 5.5-merge

    modified:
      include/mysql.h
      include/mysql.h.pp
      libmysql/libmysql.c
      mysql-test/r/gis.result
      mysql-test/r/multi_update.result
      mysql-test/r/row.result
      mysql-test/r/select.result
      mysql-test/r/subselect.result
      mysql-test/r/subselect4.result
      mysql-test/r/trigger_notembedded.result
      mysql-test/t/gis.test
      mysql-test/t/multi_update.test
      mysql-test/t/row.test
      mysql-test/t/select.test
      mysql-test/t/subselect4.test
      mysql-test/t/trigger_notembedded.test
      sql/item.cc
      sql/item_cmpfunc.cc
      sql/item_subselect.cc
      sql/spatial.cc
      sql/sql_trigger.cc
      tests/mysql_client_test.c
=== modified file 'include/mysql.h'
--- a/include/mysql.h	2010-07-20 17:54:05 +0000
+++ b/include/mysql.h	2010-09-07 07:49:47 +0000
@@ -208,7 +208,8 @@ struct st_mysql_options {
 
 enum mysql_status 
 {
-  MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,MYSQL_STATUS_USE_RESULT
+  MYSQL_STATUS_READY, MYSQL_STATUS_GET_RESULT, MYSQL_STATUS_USE_RESULT,
+  MYSQL_STATUS_STATEMENT_GET_RESULT
 };
 
 enum mysql_protocol_type 

=== modified file 'include/mysql.h.pp'
--- a/include/mysql.h.pp	2010-07-23 14:24:00 +0000
+++ b/include/mysql.h.pp	2010-09-10 08:06:58 +0000
@@ -297,7 +297,8 @@ struct st_mysql_options {
 };
 enum mysql_status
 {
-  MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,MYSQL_STATUS_USE_RESULT
+  MYSQL_STATUS_READY, MYSQL_STATUS_GET_RESULT, MYSQL_STATUS_USE_RESULT,
+  MYSQL_STATUS_STATEMENT_GET_RESULT
 };
 enum mysql_protocol_type
 {

=== modified file 'libmysql/libmysql.c'
--- a/libmysql/libmysql.c	2010-07-23 20:13:36 +0000
+++ b/libmysql/libmysql.c	2010-09-09 12:36:57 +0000
@@ -2118,6 +2118,8 @@ static my_bool execute(MYSQL_STMT *stmt,
       set_stmt_errmsg(stmt, net);
     DBUG_RETURN(1);
   }
+  else if (mysql->status == MYSQL_STATUS_GET_RESULT)
+    stmt->mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT;
   DBUG_RETURN(0);
 }
 
@@ -2256,7 +2258,7 @@ static int stmt_read_row_unbuffered(MYSQ
     set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
     return 1;
   }
-  if (mysql->status != MYSQL_STATUS_GET_RESULT)
+  if (mysql->status != MYSQL_STATUS_STATEMENT_GET_RESULT)
   {
     set_stmt_error(stmt, stmt->unbuffered_fetch_cancelled ?
                    CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
@@ -4448,7 +4450,7 @@ int STDCALL mysql_stmt_store_result(MYSQ
       DBUG_RETURN(1);
     }
   }
-  else if (mysql->status != MYSQL_STATUS_GET_RESULT)
+  else if (mysql->status != MYSQL_STATUS_STATEMENT_GET_RESULT)
   {
     set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
     DBUG_RETURN(1);
@@ -4872,6 +4874,9 @@ int STDCALL mysql_stmt_next_result(MYSQL
     DBUG_RETURN(rc);
   }
 
+  if (mysql->status == MYSQL_STATUS_GET_RESULT)
+    mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT;
+
   stmt->state= MYSQL_STMT_EXECUTE_DONE;
   stmt->bind_result_done= FALSE;
 

=== modified file 'mysql-test/r/gis.result'
--- a/mysql-test/r/gis.result	2010-04-11 06:52:42 +0000
+++ b/mysql-test/r/gis.result	2010-09-06 09:54:44 +0000
@@ -1057,6 +1057,13 @@ NULL
 SELECT Polygon(12345123,'');
 Polygon(12345123,'')
 NULL
+#
+# BUG#51875: crash when loading data into geometry function polyfromwkb
+#
+SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
+SET @a=POLYFROMWKB(@a);
+SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
+SET @a=POLYFROMWKB(@a);
 End of 5.1 tests
 CREATE TABLE t1(
 col0 BINARY NOT NULL,

=== modified file 'mysql-test/r/multi_update.result'
--- a/mysql-test/r/multi_update.result	2010-06-19 09:24:34 +0000
+++ b/mysql-test/r/multi_update.result	2010-09-10 08:06:58 +0000
@@ -649,4 +649,24 @@ SET SESSION sql_safe_updates = 1;
 UPDATE IGNORE t1, t1 t1a SET t1.a = 1 WHERE t1a.a = 1;
 ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
 DROP TABLE t1;
+#
+# Bug#54543: update ignore with incorrect subquery leads to assertion
+# failure: inited==INDEX
+#
+SET SESSION sql_safe_updates = 0;
+CREATE TABLE t1 ( a INT );
+INSERT INTO t1 VALUES (1), (2);
+CREATE TABLE t2 ( a INT );
+INSERT INTO t2 VALUES (1), (2);
+CREATE TABLE t3 ( a INT );
+INSERT INTO t3 VALUES (1), (2);
+# Should not crash
+UPDATE IGNORE
+( SELECT ( SELECT COUNT(*) FROM t1 GROUP BY a, @v ) a FROM t2 ) x, t3
+SET t3.a = 0;
+Warnings:
+Error	1242	Subquery returns more than 1 row
+Error	1242	Subquery returns more than 1 row
+DROP TABLE t1, t2, t3;
+SET SESSION sql_safe_updates = DEFAULT;
 end of tests

=== modified file 'mysql-test/r/row.result'
--- a/mysql-test/r/row.result	2010-04-16 11:42:34 +0000
+++ b/mysql-test/r/row.result	2010-09-09 12:46:13 +0000
@@ -466,3 +466,26 @@ SELECT 1 FROM t1 WHERE ROW(a, b) >=
 ROW('1', (SELECT 1 FROM t1 WHERE a > 1234));
 1
 DROP TABLE t1;
+#
+# Bug #54190: Comparison to row subquery produces incorrect result
+# 
+SELECT ROW(1,2) = (SELECT 1,2 FROM DUAL WHERE 1 = 0);
+ROW(1,2) = (SELECT 1,2 FROM DUAL WHERE 1 = 0)
+NULL
+SELECT ROW(1,2) = (SELECT 1,3 FROM DUAL WHERE 1 = 0);
+ROW(1,2) = (SELECT 1,3 FROM DUAL WHERE 1 = 0)
+NULL
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 () VALUES (1), (2), (3);
+SELECT ROW(1,2) = (SELECT 1,2 FROM t1 WHERE 1 = 0);
+ROW(1,2) = (SELECT 1,2 FROM t1 WHERE 1 = 0)
+NULL
+SELECT ROW(1,2) = (SELECT 1,3 FROM t1 WHERE 1 = 0);
+ROW(1,2) = (SELECT 1,3 FROM t1 WHERE 1 = 0)
+NULL
+SELECT i FROM t1 WHERE ROW(1,2) = (SELECT 1,2 FROM DUAL WHERE 1 = 0);
+i
+SELECT i FROM t1 WHERE ROW(1,2) = (SELECT 1,3 FROM DUAL WHERE 1 = 0);
+i
+DROP TABLE t1;
+End of 5.1 tests

=== modified file 'mysql-test/r/select.result'
--- a/mysql-test/r/select.result	2010-08-25 19:00:38 +0000
+++ b/mysql-test/r/select.result	2010-09-09 15:00:33 +0000
@@ -4430,11 +4430,6 @@ SELECT 1 FROM t1 WHERE a <> 1 AND NOT
 ROW(1,a) <=> ROW(1,(SELECT 1 FROM t1))
 INTO @var0;
 ERROR 21000: Subquery returns more than 1 row
-SELECT 1 FROM t1 WHERE a <> 1 AND NOT
-ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1));
-1
-1
-1
 DROP TABLE t1;
 #
 # Bug #48458: simple query tries to allocate enormous amount of

=== modified file 'mysql-test/r/subselect.result'
--- a/mysql-test/r/subselect.result	2010-07-16 21:00:50 +0000
+++ b/mysql-test/r/subselect.result	2010-09-10 08:06:58 +0000
@@ -922,7 +922,7 @@ select a, (select a,b,c from t1 where t1
 a	(select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a')	(select c from t1 where a=t2.a)
 1	1	a
 2	0	b
-NULL	0	NULL
+NULL	NULL	NULL
 select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2;
 a	(select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b')	(select c from t1 where a=t2.a)
 1	0	a
@@ -932,7 +932,7 @@ select a, (select a,b,c from t1 where t1
 a	(select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c')	(select c from t1 where a=t2.a)
 1	0	a
 2	0	b
-NULL	0	NULL
+NULL	NULL	NULL
 drop table t1,t2;
 create table t1 (a int, b real, c varchar(10));
 insert into t1 values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b');

=== modified file 'mysql-test/r/subselect4.result'
--- a/mysql-test/r/subselect4.result	2010-08-12 14:08:21 +0000
+++ b/mysql-test/r/subselect4.result	2010-09-10 08:06:58 +0000
@@ -77,6 +77,92 @@ Note	1249	Select 2 was reduced during op
 CREATE VIEW v1 AS SELECT 1 LIKE ( 1 IN ( SELECT 1 ) );
 CREATE VIEW v2 AS SELECT 1 LIKE '%' ESCAPE ( 1 IN ( SELECT 1 ) );
 DROP VIEW v1, v2;
+# 
+# Bug#51070: Query with a NOT IN subquery predicate returns a wrong
+# result set
+# 
+CREATE TABLE t1 ( a INT, b INT );
+INSERT INTO t1 VALUES ( 1, NULL ), ( 2, NULL );
+CREATE TABLE t2 ( c INT, d INT );
+INSERT INTO t2 VALUES ( NULL, 3 ), ( NULL, 4 );
+CREATE TABLE t3 ( e INT, f INT );
+INSERT INTO t3 VALUES ( NULL, NULL ), ( NULL, NULL );
+CREATE TABLE t4 ( a INT );
+INSERT INTO t4 VALUES (1), (2), (3);
+CREATE TABLE t5 ( a INT );
+INSERT INTO t5 VALUES (NULL), (2);
+EXPLAIN
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 );
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+x	PRIMARY	x	x	x	x	x	x	x	x
+x	DEPENDENT SUBQUERY	x	x	x	x	x	x	x	x
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 );
+a	b
+EXPLAIN
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 ) IS NULL;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 ) IS NULL;
+a	b
+1	NULL
+2	NULL
+SELECT * FROM t1 WHERE ( a, b ) IN ( SELECT c, d FROM t2 ) IS NULL;
+a	b
+1	NULL
+2	NULL
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 ) IS UNKNOWN;
+a	b
+1	NULL
+2	NULL
+SELECT * FROM t1 WHERE (( a, b ) NOT IN ( SELECT c, d FROM t2 )) IS UNKNOWN;
+a	b
+1	NULL
+2	NULL
+SELECT * FROM t1 WHERE 1 = 1 AND ( a, b ) NOT IN ( SELECT c, d FROM t2 );
+a	b
+EXPLAIN
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT e, f FROM t3 );
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+x	PRIMARY	x	x	x	x	x	x	x	x
+x	DEPENDENT SUBQUERY	x	x	x	x	x	x	x	x
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT e, f FROM t3 );
+a	b
+EXPLAIN
+SELECT * FROM t2 WHERE ( c, d ) NOT IN ( SELECT a, b FROM t1 );
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+x	PRIMARY	x	x	x	x	x	x	x	x
+x	DEPENDENT SUBQUERY	x	x	x	x	x	x	x	x
+SELECT * FROM t2 WHERE ( c, d ) NOT IN ( SELECT a, b FROM t1 );
+c	d
+EXPLAIN
+SELECT * FROM t3 WHERE ( e, f ) NOT IN ( SELECT c, d FROM t2 );
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+x	PRIMARY	x	x	x	x	x	x	x	x
+x	DEPENDENT SUBQUERY	x	x	x	x	x	x	x	x
+SELECT * FROM t3 WHERE ( e, f ) NOT IN ( SELECT c, d FROM t2 );
+e	f
+EXPLAIN
+SELECT * FROM t2 WHERE ( c, d ) NOT IN ( SELECT e, f FROM t3 );
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+x	PRIMARY	x	x	x	x	x	x	x	x
+x	DEPENDENT SUBQUERY	x	x	x	x	x	x	x	x
+SELECT * FROM t2 WHERE ( c, d ) NOT IN ( SELECT e, f FROM t3 );
+c	d
+SELECT * FROM t1 WHERE ( a, b ) NOT IN 
+( SELECT c, d FROM t2 WHERE c = 1 AND c <> 1 );
+a	b
+1	NULL
+2	NULL
+SELECT * FROM t1 WHERE b NOT IN ( SELECT c FROM t2 WHERE c = 1 );
+a	b
+1	NULL
+2	NULL
+SELECT * FROM t1 WHERE NULL NOT IN ( SELECT c FROM t2 WHERE c = 1 AND c <> 1 );
+a	b
+1	NULL
+2	NULL
+DROP TABLE t1, t2, t3, t4, t5;
 #
 # End of 5.1 tests.
 #

=== modified file 'mysql-test/r/trigger_notembedded.result'
--- a/mysql-test/r/trigger_notembedded.result	2010-04-14 10:33:14 +0000
+++ b/mysql-test/r/trigger_notembedded.result	2010-09-10 08:06:58 +0000
@@ -472,4 +472,25 @@ SHOW CREATE TRIGGER db1.trg;
 ERROR 42000: Access denied; you need (at least one of) the TRIGGER privilege(s) for this operation
 DROP USER 'no_rights'@'localhost';
 DROP DATABASE db1;
+DROP DATABASE IF EXISTS mysqltest_db1;
+CREATE DATABASE mysqltest_db1;
+USE mysqltest_db1;
+GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost;
+CREATE TABLE t1 (
+a1 int,
+a2 int
+);
+INSERT INTO t1 VALUES (1, 20);
+CREATE TRIGGER mysqltest_db1.upd_t1
+BEFORE UPDATE ON t1 FOR EACH ROW SET new.a2 = 200;
+CREATE TABLE t2 (
+a1 int
+);
+INSERT INTO t2 VALUES (2);
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost;
+UPDATE IGNORE t1, t2 SET t1.a1 = 2, t2.a1 = 3 WHERE t1.a1 = 1 AND t2.a1 = 2;
+ERROR 42000: TRIGGER command denied to user 'mysqltest_u1'@'localhost' for table 't1'
+DROP DATABASE mysqltest_db1;
+DROP USER mysqltest_u1@localhost;
+USE test;
 End of 5.1 tests.

=== modified file 'mysql-test/t/gis.test'
--- a/mysql-test/t/gis.test	2010-03-01 09:45:36 +0000
+++ b/mysql-test/t/gis.test	2010-09-06 09:54:44 +0000
@@ -725,6 +725,16 @@ SELECT Polygon(123451,'');
 SELECT Polygon(1234512,'');
 SELECT Polygon(12345123,'');
 
+
+--echo #
+--echo # BUG#51875: crash when loading data into geometry function polyfromwkb
+--echo #
+SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
+SET @a=POLYFROMWKB(@a);
+SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
+SET @a=POLYFROMWKB(@a);
+
+
 --echo End of 5.1 tests
 
 #

=== modified file 'mysql-test/t/multi_update.test'
--- a/mysql-test/t/multi_update.test	2010-08-20 08:48:59 +0000
+++ b/mysql-test/t/multi_update.test	2010-09-10 08:06:58 +0000
@@ -650,5 +650,26 @@ SET SESSION sql_safe_updates = 1;
 UPDATE IGNORE t1, t1 t1a SET t1.a = 1 WHERE t1a.a = 1;
 DROP TABLE t1;
 
+--echo #
+--echo # Bug#54543: update ignore with incorrect subquery leads to assertion
+--echo # failure: inited==INDEX
+--echo #
+SET SESSION sql_safe_updates = 0;
+CREATE TABLE t1 ( a INT );
+INSERT INTO t1 VALUES (1), (2);
+
+CREATE TABLE t2 ( a INT );
+INSERT INTO t2 VALUES (1), (2);
+
+CREATE TABLE t3 ( a INT );
+INSERT INTO t3 VALUES (1), (2);
+
+--echo # Should not crash
+UPDATE IGNORE
+  ( SELECT ( SELECT COUNT(*) FROM t1 GROUP BY a, @v ) a FROM t2 ) x, t3
+SET t3.a = 0;
+
+DROP TABLE t1, t2, t3;
+SET SESSION sql_safe_updates = DEFAULT;
 
 --echo end of tests

=== modified file 'mysql-test/t/row.test'
--- a/mysql-test/t/row.test	2010-04-16 11:42:34 +0000
+++ b/mysql-test/t/row.test	2010-09-09 12:46:13 +0000
@@ -266,3 +266,22 @@ SELECT 1 FROM t1 WHERE ROW(a, b) >=
 ROW('1', (SELECT 1 FROM t1 WHERE a > 1234));
 --enable_warnings
 DROP TABLE t1;
+
+--echo #
+--echo # Bug #54190: Comparison to row subquery produces incorrect result
+--echo # 
+
+SELECT ROW(1,2) = (SELECT 1,2 FROM DUAL WHERE 1 = 0);
+SELECT ROW(1,2) = (SELECT 1,3 FROM DUAL WHERE 1 = 0);
+
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 () VALUES (1), (2), (3);
+
+SELECT ROW(1,2) = (SELECT 1,2 FROM t1 WHERE 1 = 0);
+SELECT ROW(1,2) = (SELECT 1,3 FROM t1 WHERE 1 = 0);
+SELECT i FROM t1 WHERE ROW(1,2) = (SELECT 1,2 FROM DUAL WHERE 1 = 0);
+SELECT i FROM t1 WHERE ROW(1,2) = (SELECT 1,3 FROM DUAL WHERE 1 = 0);
+
+DROP TABLE t1;
+
+--echo End of 5.1 tests

=== modified file 'mysql-test/t/select.test'
--- a/mysql-test/t/select.test	2010-07-15 13:47:50 +0000
+++ b/mysql-test/t/select.test	2010-09-09 15:00:33 +0000
@@ -3772,11 +3772,6 @@ SELECT 1 FROM t1 WHERE a <> 1 AND NOT
 ROW(1,a) <=> ROW(1,(SELECT 1 FROM t1))
 INTO @var0;
 
-# Query correctly return 2 rows since comparison a <=> fisrt_subquery is
-# always false, thus the second query is never executed.
-SELECT 1 FROM t1 WHERE a <> 1 AND NOT
-ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1));
-
 DROP TABLE t1;
  
 --echo #

=== modified file 'mysql-test/t/subselect4.test'
--- a/mysql-test/t/subselect4.test	2010-08-12 14:08:21 +0000
+++ b/mysql-test/t/subselect4.test	2010-09-10 08:06:58 +0000
@@ -74,6 +74,68 @@ CREATE VIEW v1 AS SELECT 1 LIKE ( 1 IN (
 CREATE VIEW v2 AS SELECT 1 LIKE '%' ESCAPE ( 1 IN ( SELECT 1 ) );
 DROP VIEW v1, v2;
 
+--echo # 
+--echo # Bug#51070: Query with a NOT IN subquery predicate returns a wrong
+--echo # result set
+--echo # 
+CREATE TABLE t1 ( a INT, b INT );
+INSERT INTO t1 VALUES ( 1, NULL ), ( 2, NULL );
+
+CREATE TABLE t2 ( c INT, d INT );
+INSERT INTO t2 VALUES ( NULL, 3 ), ( NULL, 4 );
+
+CREATE TABLE t3 ( e INT, f INT );
+INSERT INTO t3 VALUES ( NULL, NULL ), ( NULL, NULL );
+
+CREATE TABLE t4 ( a INT );
+INSERT INTO t4 VALUES (1), (2), (3);
+
+CREATE TABLE t5 ( a INT );
+INSERT INTO t5 VALUES (NULL), (2);
+
+--replace_column 1 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x
+EXPLAIN
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 );
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 );
+
+EXPLAIN
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 ) IS NULL;
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 ) IS NULL;
+SELECT * FROM t1 WHERE ( a, b ) IN ( SELECT c, d FROM t2 ) IS NULL;
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT c, d FROM t2 ) IS UNKNOWN;
+SELECT * FROM t1 WHERE (( a, b ) NOT IN ( SELECT c, d FROM t2 )) IS UNKNOWN;
+
+SELECT * FROM t1 WHERE 1 = 1 AND ( a, b ) NOT IN ( SELECT c, d FROM t2 );
+
+--replace_column 1 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x
+EXPLAIN
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT e, f FROM t3 );
+SELECT * FROM t1 WHERE ( a, b ) NOT IN ( SELECT e, f FROM t3 );
+
+--replace_column 1 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x
+EXPLAIN
+SELECT * FROM t2 WHERE ( c, d ) NOT IN ( SELECT a, b FROM t1 );
+SELECT * FROM t2 WHERE ( c, d ) NOT IN ( SELECT a, b FROM t1 );
+
+--replace_column 1 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x
+EXPLAIN
+SELECT * FROM t3 WHERE ( e, f ) NOT IN ( SELECT c, d FROM t2 );
+SELECT * FROM t3 WHERE ( e, f ) NOT IN ( SELECT c, d FROM t2 );
+
+--replace_column 1 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x
+EXPLAIN
+SELECT * FROM t2 WHERE ( c, d ) NOT IN ( SELECT e, f FROM t3 );
+SELECT * FROM t2 WHERE ( c, d ) NOT IN ( SELECT e, f FROM t3 );
+
+SELECT * FROM t1 WHERE ( a, b ) NOT IN 
+  ( SELECT c, d FROM t2 WHERE c = 1 AND c <> 1 );
+
+SELECT * FROM t1 WHERE b NOT IN ( SELECT c FROM t2 WHERE c = 1 );
+
+SELECT * FROM t1 WHERE NULL NOT IN ( SELECT c FROM t2 WHERE c = 1 AND c <> 1 );
+
+DROP TABLE t1, t2, t3, t4, t5;
+
 
 --echo #
 --echo # End of 5.1 tests.

=== modified file 'mysql-test/t/trigger_notembedded.test'
--- a/mysql-test/t/trigger_notembedded.test	2010-08-06 11:29:37 +0000
+++ b/mysql-test/t/trigger_notembedded.test	2010-09-07 09:00:41 +0000
@@ -932,4 +932,52 @@ disconnect con1;
 DROP USER 'no_rights'@'localhost';
 DROP DATABASE db1;
 
+#
+# Bug#55421 Protocol::end_statement(): Assertion `0' on multi-table UPDATE IGNORE
+# To reproduce a crash we need to provoke a trigger execution with
+# the following conditions:
+#   - active SELECT statement during trigger execution
+#    (i.e. LEX::current_select != NULL);
+#   - IGNORE option (i.e. LEX::current_select->no_error == TRUE);
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest_db1;
+--enable_warnings
+
+CREATE DATABASE mysqltest_db1;
+USE mysqltest_db1;
+
+GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost;
+
+--connect(con1,localhost,mysqltest_u1,,mysqltest_db1)
+
+CREATE TABLE t1 (
+  a1 int,
+  a2 int
+);
+INSERT INTO t1 VALUES (1, 20);
+
+CREATE TRIGGER mysqltest_db1.upd_t1
+BEFORE UPDATE ON t1 FOR EACH ROW SET new.a2 = 200;
+
+CREATE TABLE t2 (
+  a1 int
+);
+
+INSERT INTO t2 VALUES (2);
+
+--connection default
+
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+UPDATE IGNORE t1, t2 SET t1.a1 = 2, t2.a1 = 3 WHERE t1.a1 = 1 AND t2.a1 = 2;
+# Cleanup
+
+DROP DATABASE mysqltest_db1;
+DROP USER mysqltest_u1@localhost;
+
+--disconnect con1
+--connection default
+USE test;
+
 --echo End of 5.1 tests.

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2010-08-25 08:36:17 +0000
+++ b/sql/item.cc	2010-09-10 08:06:58 +0000
@@ -7850,9 +7850,12 @@ bool Item_cache_row::null_inside()
 
 void Item_cache_row::bring_value()
 {
+  if (!example)
+    return;
+  example->bring_value();
+  null_value= example->null_value;
   for (uint i= 0; i < item_count; i++)
     values[i]->bring_value();
-  return;
 }
 
 

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2010-08-19 12:17:24 +0000
+++ b/sql/item_cmpfunc.cc	2010-09-10 08:06:58 +0000
@@ -1595,6 +1595,13 @@ int Arg_comparator::compare_row()
   bool was_null= 0;
   (*a)->bring_value();
   (*b)->bring_value();
+
+  if ((*a)->null_value || (*b)->null_value)
+  {
+    owner->null_value= 1;
+    return -1;
+  }
+
   uint n= (*a)->cols();
   for (uint i= 0; i<n; i++)
   {
@@ -1763,6 +1770,76 @@ bool Item_in_optimizer::fix_fields(THD *
 }
 
 
+/**
+   The implementation of optimized \<outer expression\> [NOT] IN \<subquery\>
+   predicates. The implementation works as follows.
+
+   For the current value of the outer expression
+   
+   - If it contains only NULL values, the original (before rewrite by the
+     Item_in_subselect rewrite methods) inner subquery is non-correlated and
+     was previously executed, there is no need to re-execute it, and the
+     previous return value is returned.
+
+   - If it contains NULL values, check if there is a partial match for the
+     inner query block by evaluating it. For clarity we repeat here the
+     transformation previously performed on the sub-query. The expression
+
+     <tt>
+     ( oc_1, ..., oc_n ) 
+     \<in predicate\>
+     ( SELECT ic_1, ..., ic_n
+       FROM \<table\>
+       WHERE \<inner where\> 
+     )
+     </tt>
+
+     was transformed into
+     
+     <tt>
+     ( oc_1, ..., oc_n ) 
+     \<in predicate\>
+     ( SELECT ic_1, ..., ic_n 
+       FROM \<table\> 
+       WHERE \<inner where\> AND ... ( ic_k = oc_k OR ic_k IS NULL ) 
+       HAVING ... NOT ic_k IS NULL
+     )
+     </tt>
+
+     The evaluation will now proceed according to special rules set up
+     elsewhere. These rules include:
+
+     - The HAVING NOT \<inner column\> IS NULL conditions added by the
+       aforementioned rewrite methods will detect whether they evaluated (and
+       rejected) a NULL value and if so, will cause the subquery to evaluate
+       to NULL. 
+
+     - The added WHERE and HAVING conditions are present only for those inner
+       columns that correspond to outer column that are not NULL at the moment.
+     
+     - If there is an eligible index for executing the subquery, the special
+       access method "Full scan on NULL key" is employed which ensures that
+       the inner query will detect if there are NULL values resulting from the
+       inner query. This access method will quietly resort to table scan if it
+       needs to find NULL values as well.
+
+     - Under these conditions, the sub-query need only be evaluated in order to
+       find out whether it produced any rows.
+     
+       - If it did, we know that there was a partial match since there are
+         NULL values in the outer row expression.
+
+       - If it did not, the result is FALSE or UNKNOWN. If at least one of the
+         HAVING sub-predicates rejected a NULL value corresponding to an outer
+         non-NULL, and hence the inner query block returns UNKNOWN upon
+         evaluation, there was a partial match and the result is UNKNOWN.
+
+   - If it contains no NULL values, the call is forwarded to the inner query
+     block.
+
+     @see Item_in_subselect::val_bool()
+     @see Item_is_not_null_test::val_int()
+ */
 longlong Item_in_optimizer::val_int()
 {
   bool tmp;
@@ -1816,7 +1893,7 @@ longlong Item_in_optimizer::val_int()
           all_left_cols_null= false;
       }
 
-      if (!((Item_in_subselect*)args[1])->is_correlated && 
+      if (!item_subs->is_correlated && 
           all_left_cols_null && result_for_null_param != UNKNOWN)
       {
         /* 
@@ -1830,8 +1907,11 @@ longlong Item_in_optimizer::val_int()
       else 
       {
         /* The subquery has to be evaluated */
-        (void) args[1]->val_bool_result();
-        null_value= !item_subs->engine->no_rows();
+        (void) item_subs->val_bool_result();
+        if (item_subs->engine->no_rows())
+          null_value= item_subs->null_value;
+        else
+          null_value= TRUE;
         if (all_left_cols_null)
           result_for_null_param= null_value;
       }

=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc	2010-07-23 17:08:41 +0000
+++ b/sql/item_subselect.cc	2010-09-10 08:06:58 +0000
@@ -55,7 +55,7 @@ Item_subselect::Item_subselect():
     item value is NULL if select_subselect not changed this value
     (i.e. some rows will be found returned)
   */
-  null_value= 1;
+  null_value= TRUE;
 }
 
 
@@ -435,9 +435,9 @@ void Item_maxmin_subselect::print(String
 
 void Item_singlerow_subselect::reset()
 {
-  null_value= 1;
+  null_value= TRUE;
   if (value)
-    value->null_value= 1;
+    value->null_value= TRUE;
 }
 
 
@@ -574,7 +574,10 @@ bool Item_singlerow_subselect::null_insi
 
 void Item_singlerow_subselect::bring_value()
 {
-  exec();
+  if (!exec() && assigned())
+    null_value= 0;
+  else
+    reset();
 }
 
 double Item_singlerow_subselect::val_real()
@@ -582,7 +585,7 @@ double Item_singlerow_subselect::val_rea
   DBUG_ASSERT(fixed == 1);
   if (!exec() && !value->null_value)
   {
-    null_value= 0;
+    null_value= FALSE;
     return value->val_real();
   }
   else
@@ -597,7 +600,7 @@ longlong Item_singlerow_subselect::val_i
   DBUG_ASSERT(fixed == 1);
   if (!exec() && !value->null_value)
   {
-    null_value= 0;
+    null_value= FALSE;
     return value->val_int();
   }
   else
@@ -611,7 +614,7 @@ String *Item_singlerow_subselect::val_st
 {
   if (!exec() && !value->null_value)
   {
-    null_value= 0;
+    null_value= FALSE;
     return value->val_str(str);
   }
   else
@@ -626,7 +629,7 @@ my_decimal *Item_singlerow_subselect::va
 {
   if (!exec() && !value->null_value)
   {
-    null_value= 0;
+    null_value= FALSE;
     return value->val_decimal(decimal_value);
   }
   else
@@ -641,7 +644,7 @@ bool Item_singlerow_subselect::val_bool(
 {
   if (!exec() && !value->null_value)
   {
-    null_value= 0;
+    null_value= FALSE;
     return value->val_bool();
   }
   else
@@ -659,7 +662,7 @@ Item_exists_subselect::Item_exists_subse
   bool val_bool();
   init(select_lex, new select_exists_subselect(this));
   max_columns= UINT_MAX;
-  null_value= 0; //can't be NULL
+  null_value= FALSE; //can't be NULL
   maybe_null= 0; //can't be NULL
   value= 0;
   DBUG_VOID_RETURN;
@@ -822,15 +825,14 @@ double Item_in_subselect::val_real()
   */
   DBUG_ASSERT(0);
   DBUG_ASSERT(fixed == 1);
-  null_value= 0;
+  null_value= was_null= FALSE;
   if (exec())
   {
     reset();
-    null_value= 1;
     return 0;
   }
   if (was_null && !value)
-    null_value= 1;
+    null_value= TRUE;
   return (double) value;
 }
 
@@ -843,15 +845,14 @@ longlong Item_in_subselect::val_int()
   */
   DBUG_ASSERT(0);
   DBUG_ASSERT(fixed == 1);
-  null_value= 0;
+  null_value= was_null= FALSE;
   if (exec())
   {
     reset();
-    null_value= 1;
     return 0;
   }
   if (was_null && !value)
-    null_value= 1;
+    null_value= TRUE;
   return value;
 }
 
@@ -864,16 +865,15 @@ String *Item_in_subselect::val_str(Strin
   */
   DBUG_ASSERT(0);
   DBUG_ASSERT(fixed == 1);
-  null_value= 0;
+  null_value= was_null= FALSE;
   if (exec())
   {
     reset();
-    null_value= 1;
     return 0;
   }
   if (was_null && !value)
   {
-    null_value= 1;
+    null_value= TRUE;
     return 0;
   }
   str->set((ulonglong)value, &my_charset_bin);
@@ -884,20 +884,14 @@ String *Item_in_subselect::val_str(Strin
 bool Item_in_subselect::val_bool()
 {
   DBUG_ASSERT(fixed == 1);
-  null_value= 0;
+  null_value= was_null= FALSE;
   if (exec())
   {
     reset();
-    /* 
-      Must mark the IN predicate as NULL so as to make sure an enclosing NOT
-      predicate will return FALSE. See the comments in 
-      subselect_uniquesubquery_engine::copy_ref_key for further details.
-    */
-    null_value= 1;
     return 0;
   }
   if (was_null && !value)
-    null_value= 1;
+    null_value= TRUE;
   return value;
 }
 
@@ -908,16 +902,15 @@ my_decimal *Item_in_subselect::val_decim
     method should not be used
   */
   DBUG_ASSERT(0);
-  null_value= 0;
+  null_value= was_null= FALSE;
   DBUG_ASSERT(fixed == 1);
   if (exec())
   {
     reset();
-    null_value= 1;
     return 0;
   }
   if (was_null && !value)
-    null_value= 1;
+    null_value= TRUE;
   int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value);
   return decimal_value;
 }

=== modified file 'sql/spatial.cc'
--- a/sql/spatial.cc	2010-07-23 14:24:00 +0000
+++ b/sql/spatial.cc	2010-09-10 08:06:58 +0000
@@ -511,7 +511,7 @@ uint Gis_line_string::init_from_wkb(cons
   n_points= wkb_get_uint(wkb, bo);
   proper_length= 4 + n_points * POINT_DATA_SIZE;
 
-  if (len < proper_length || res->reserve(proper_length))
+  if (!n_points || len < proper_length || res->reserve(proper_length))
     return 0;
 
   res->q_append(n_points);
@@ -729,7 +729,9 @@ uint Gis_polygon::init_from_wkb(const ch
   if (len < 4)
     return 0;
 
-  n_linear_rings= wkb_get_uint(wkb, bo);
+  if (!(n_linear_rings= wkb_get_uint(wkb, bo)))
+    return 0;
+
   if (res->reserve(4, 512))
     return 0;
   wkb+= 4;

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2010-08-20 08:48:59 +0000
+++ b/sql/sql_trigger.cc	2010-09-10 08:06:58 +0000
@@ -2006,6 +2006,7 @@ bool Table_triggers_list::process_trigge
   bool err_status;
   Sub_statement_state statement_state;
   sp_head *sp_trigger= bodies[event][time_type];
+  SELECT_LEX *save_current_select;
 
   if (sp_trigger == NULL)
     return FALSE;
@@ -2029,11 +2030,19 @@ bool Table_triggers_list::process_trigge
 
   thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
 
+  /*
+    Reset current_select before call execute_trigger() and
+    restore it after return from one. This way error is set
+    in case of failure during trigger execution.
+  */
+  save_current_select= thd->lex->current_select;
+  thd->lex->current_select= NULL;
   err_status=
     sp_trigger->execute_trigger(thd,
                                 &trigger_table->s->db,
                                 &trigger_table->s->table_name,
                                 &subject_table_grants[event][time_type]);
+  thd->lex->current_select= save_current_select;
 
   thd->restore_sub_statement_state(&statement_state);
 

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2010-08-16 07:22:36 +0000
+++ b/tests/mysql_client_test.c	2010-09-10 08:06:58 +0000
@@ -18937,6 +18937,107 @@ static void test_bug54041()
 }
 
 
+/**
+  Bug#47485: mysql_store_result returns a result set for a prepared statement
+*/
+static void test_bug47485()
+{
+  MYSQL_STMT   *stmt;
+  MYSQL_RES    *res;
+  MYSQL_BIND    bind[2];
+  int           rc;
+  const char*   sql_select = "SELECT 1, 'a'";
+  int           int_data;
+  char          str_data[16];
+  my_bool       is_null[2];
+  my_bool       error[2];
+  unsigned long length[2];
+
+  DBUG_ENTER("test_bug47485");
+  myheader("test_bug47485");
+
+  stmt= mysql_stmt_init(mysql);
+  check_stmt(stmt);
+  rc= mysql_stmt_prepare(stmt, sql_select, strlen(sql_select));
+  check_execute(stmt, rc);
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  res = mysql_store_result(mysql);
+  DIE_UNLESS(res == NULL);
+
+  mysql_stmt_reset(stmt);
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  res = mysql_use_result(mysql);
+  DIE_UNLESS(res == NULL);
+
+  mysql_stmt_reset(stmt);
+
+  memset(bind, 0, sizeof(bind));
+  bind[0].buffer_type= MYSQL_TYPE_LONG;
+  bind[0].buffer= (char *)&int_data;
+  bind[0].is_null= &is_null[0];
+  bind[0].length= &length[0];
+  bind[0].error= &error[0];
+
+  bind[1].buffer_type= MYSQL_TYPE_STRING;
+  bind[1].buffer= (char *)str_data;
+  bind[1].buffer_length= sizeof(str_data);
+  bind[1].is_null= &is_null[1];
+  bind[1].length= &length[1];
+  bind[1].error= &error[1];
+
+  rc= mysql_stmt_bind_result(stmt, bind);
+  check_execute(stmt, rc);
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  rc= mysql_stmt_store_result(stmt);
+  check_execute(stmt, rc);
+
+  while (!(rc= mysql_stmt_fetch(stmt)))
+    ;
+
+  DIE_UNLESS(rc == MYSQL_NO_DATA);
+
+  mysql_stmt_reset(stmt);
+
+  memset(bind, 0, sizeof(bind));
+  bind[0].buffer_type= MYSQL_TYPE_LONG;
+  bind[0].buffer= (char *)&int_data;
+  bind[0].is_null= &is_null[0];
+  bind[0].length= &length[0];
+  bind[0].error= &error[0];
+
+  bind[1].buffer_type= MYSQL_TYPE_STRING;
+  bind[1].buffer= (char *)str_data;
+  bind[1].buffer_length= sizeof(str_data);
+  bind[1].is_null= &is_null[1];
+  bind[1].length= &length[1];
+  bind[1].error= &error[1];
+
+  rc= mysql_stmt_bind_result(stmt, bind);
+  check_execute(stmt, rc);
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  while (!(rc= mysql_stmt_fetch(stmt)))
+    ;
+
+  DIE_UNLESS(rc == MYSQL_NO_DATA);
+
+  mysql_stmt_close(stmt);
+
+  DBUG_VOID_RETURN;
+}
+
+
 /*
   Bug#49972: Crash in prepared statements.
 
@@ -19378,6 +19479,7 @@ static struct my_tests_st my_tests[]= {
   { "test_bug49972", test_bug49972 },
   { "test_bug42373", test_bug42373 },
   { "test_bug54041", test_bug54041 },
+  { "test_bug47485", test_bug47485 },
   { 0, 0 }
 };
 


Attachment: [text/bzr-bundle] bzr/bjorn.munch@oracle.com-20100910080658-nd277zupczgjnhfp.bundle
Thread
bzr commit into mysql-trunk-merge branch (bjorn.munch:3193) Bjorn Munch10 Sep