diff options
m--------- | libmariadb | 0 | ||||
-rw-r--r-- | mysql-test/main/ps.result | 92 | ||||
-rw-r--r-- | mysql-test/main/ps.test | 68 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 13 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 97 |
5 files changed, 268 insertions, 2 deletions
diff --git a/libmariadb b/libmariadb -Subproject 7fdb3eab66384a355475704332d11cc1ab82499 +Subproject ab7a81e79e4be4324a2d09d19d4f5249801ef66 diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index e3180175eac..7b9ccf303c8 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -5602,3 +5602,95 @@ a.a a.b 10 20 DEALLOCATE PREPARE stmt; DROP PROCEDURE p1; +# +# MDEV-16128: Server crash in Item_func::print_op on 2nd execution of PS +# +CREATE TABLE t1 (a varchar(10)); +CREATE TABLE t2 (b varchar(10) CHARACTER SET utf8 ); +CREATE TABLE t3 (c varchar(10) CHARACTER SET utf8); +INSERT INTO t1 VALUES ('b'); +INSERT INTO t2 VALUES ('b'); +INSERT INTO t3 VALUES ('b'); +PREPARE stmt FROM "SELECT t1.* FROM (t1 JOIN t2 ON (t2.b = t1.a)) WHERE (EXISTS (SELECT 1 FROM t3 WHERE t3.c = t1.a))"; +EXECUTE stmt; +a +b +# Without the patch second execution of the prepared statement +# would lead to server crash. +EXECUTE stmt; +a +b +# Clean up +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2, t3; +CREATE TABLE t1 (a varchar(10)); +CREATE TABLE t2 (b varchar(10) CHARACTER SET utf8); +INSERT INTO t1 VALUES ('b'); +INSERT INTO t2 VALUES ('b'); +PREPARE stmt FROM 'SELECT STRAIGHT_JOIN 1 FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a)'; +EXECUTE stmt; +1 +1 +# Without the patch second execution of the prepared statement +# would lead to server crash. +EXECUTE stmt; +1 +1 +# Clean up +DEALLOCATE PREPARE stmt; +# Check that EXECUTE USING is run correctly +PREPARE stmt FROM 'SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t2 WHERE t2.b = ?)'; +EXECUTE stmt USING 'b'; +300 +300 +EXECUTE stmt USING 'b'; +300 +300 +EXECUTE stmt USING 'd'; +300 +EXECUTE stmt USING 'd'; +300 +EXECUTE stmt USING _binary 'b'; +300 +300 +EXECUTE stmt USING _binary 'b'; +300 +300 +EXECUTE stmt USING _binary 'd'; +300 +EXECUTE stmt USING _binary 'd'; +300 +EXECUTE stmt USING _ucs2 'b'; +300 +300 +EXECUTE stmt USING _ucs2 'b'; +300 +300 +EXECUTE stmt USING _ucs2 'd'; +300 +EXECUTE stmt USING _ucs2 'd'; +300 +EXECUTE stmt USING _latin1 'b'; +300 +300 +EXECUTE stmt USING _latin1 'b'; +300 +300 +EXECUTE stmt USING _latin1 'd'; +300 +EXECUTE stmt USING _latin1 'd'; +300 +CREATE TABLE t3 (c VARCHAR(10) CHARACTER SET ucs2); +INSERT INTO t3 VALUES ('b'); +PREPARE stmt FROM 'SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t3 WHERE t3.c = ?)'; +EXECUTE stmt USING 'b'; +300 +300 +EXECUTE stmt USING 'b'; +300 +300 +EXECUTE stmt USING 'd'; +300 +EXECUTE stmt USING 'd'; +300 +DROP TABLE t1, t2, t3; diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index 8c59f1e0840..4041e855799 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -5045,3 +5045,71 @@ EXECUTE stmt; DEALLOCATE PREPARE stmt; DROP PROCEDURE p1; + +--echo # +--echo # MDEV-16128: Server crash in Item_func::print_op on 2nd execution of PS +--echo # + +CREATE TABLE t1 (a varchar(10)); +CREATE TABLE t2 (b varchar(10) CHARACTER SET utf8 ); +CREATE TABLE t3 (c varchar(10) CHARACTER SET utf8); +INSERT INTO t1 VALUES ('b'); +INSERT INTO t2 VALUES ('b'); +INSERT INTO t3 VALUES ('b'); + +PREPARE stmt FROM "SELECT t1.* FROM (t1 JOIN t2 ON (t2.b = t1.a)) WHERE (EXISTS (SELECT 1 FROM t3 WHERE t3.c = t1.a))"; +EXECUTE stmt; +--echo # Without the patch second execution of the prepared statement +--echo # would lead to server crash. +EXECUTE stmt; +--echo # Clean up +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2, t3; + +CREATE TABLE t1 (a varchar(10)); +CREATE TABLE t2 (b varchar(10) CHARACTER SET utf8); +INSERT INTO t1 VALUES ('b'); +INSERT INTO t2 VALUES ('b'); +PREPARE stmt FROM 'SELECT STRAIGHT_JOIN 1 FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a)'; +EXECUTE stmt; +--echo # Without the patch second execution of the prepared statement +--echo # would lead to server crash. +EXECUTE stmt; + +--echo # Clean up +DEALLOCATE PREPARE stmt; + +--echo # Check that EXECUTE USING is run correctly +PREPARE stmt FROM 'SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t2 WHERE t2.b = ?)'; +EXECUTE stmt USING 'b'; +EXECUTE stmt USING 'b'; + +EXECUTE stmt USING 'd'; +EXECUTE stmt USING 'd'; + +EXECUTE stmt USING _binary 'b'; +EXECUTE stmt USING _binary 'b'; + +EXECUTE stmt USING _binary 'd'; +EXECUTE stmt USING _binary 'd'; + +EXECUTE stmt USING _ucs2 'b'; +EXECUTE stmt USING _ucs2 'b'; + +EXECUTE stmt USING _ucs2 'd'; +EXECUTE stmt USING _ucs2 'd'; + +EXECUTE stmt USING _latin1 'b'; +EXECUTE stmt USING _latin1 'b'; + +EXECUTE stmt USING _latin1 'd'; +EXECUTE stmt USING _latin1 'd'; + +CREATE TABLE t3 (c VARCHAR(10) CHARACTER SET ucs2); +INSERT INTO t3 VALUES ('b'); +PREPARE stmt FROM 'SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t3 WHERE t3.c = ?)'; +EXECUTE stmt USING 'b'; +EXECUTE stmt USING 'b'; +EXECUTE stmt USING 'd'; +EXECUTE stmt USING 'd'; +DROP TABLE t1, t2, t3; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index fe6b8feb4de..b7b0c981c2d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -442,9 +442,18 @@ bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp) if (args[0]->cmp_type() == STRING_RESULT && args[1]->cmp_type() == STRING_RESULT) { + Query_arena *arena, backup; + arena= thd->activate_stmt_arena_if_needed(&backup); + DTCollation tmp; - if (agg_arg_charsets_for_comparison(tmp, args, 2)) - return true; + bool ret= agg_arg_charsets_for_comparison(tmp, args, 2); + + if (arena) + thd->restore_active_arena(arena, &backup); + + if (ret) + return ret; + cmp->m_compare_collation= tmp.collation; } // Convert constants when compared to int/year field diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 482bb106af7..fd94e580647 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -21018,6 +21018,102 @@ static void test_explain_meta() } +static void test_mdev_16128() +{ + int rc, res; + MYSQL_STMT *stmt; + MYSQL_BIND bind, bind_res; + char bind_arg_1[]="d", bind_arg_2[]="b"; + ulong length= 0; + const char *query= + "SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t2 WHERE t2.b = ?)"; + + myheader("test_mdev_16128"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a VARCHAR(10))"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2 (b VARCHAR(10) CHARACTER SET utf8)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES('b')"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t2 VALUES('d')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + memset(&bind, 0, sizeof(bind)); + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer_length= strlen(bind_arg_1); + bind.buffer= bind_arg_1; + + rc= mysql_stmt_bind_param(stmt, &bind); + DIE_UNLESS(rc == 0); + + memset(&bind_res, 0, sizeof(bind_res)); + bind_res.buffer_type= MYSQL_TYPE_LONG; + bind_res.buffer= &res; + bind_res.is_null= NULL; + bind_res.length= &length; + + rc= mysql_stmt_bind_result(stmt, &bind_res); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + + /** + It's expected that the query + SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t2 WHERE t2.b = ?)" + executed in PS-mode and bound with the value 'd' returns exactly + one row containing the value (300). + */ + DIE_UNLESS(rc == 0); + DIE_UNLESS(bind_res.buffer_type == MYSQL_TYPE_LONG); + DIE_UNLESS(*((long *) bind_res.buffer) == 300); + + memset(&bind, 0, sizeof(bind)); + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer_length= strlen(bind_arg_2); + bind.buffer= bind_arg_2; + + rc= mysql_stmt_bind_param(stmt, &bind); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + /** + It's expected that the query + SELECT 300 FROM t1 WHERE EXISTS (SELECT 100 FROM t2 WHERE t2.b = ?)" + executed in PS-mode and bound with the value 'd' returns empty result set. + */ + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} + + #ifndef EMBEDDED_LIBRARY #define MDEV19838_MAX_PARAM_COUNT 32 #define MDEV19838_FIELDS_COUNT 17 @@ -21169,6 +21265,7 @@ static void test_mdev19838() static struct my_tests_st my_tests[]= { + { "test_mdev_16128", test_mdev_16128 }, { "test_mdev_20516", test_mdev_20516 }, { "test_mdev24827", test_mdev24827 }, { "test_mdev_26145", test_mdev_26145 }, |