summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------libmariadb0
-rw-r--r--mysql-test/main/ps.result92
-rw-r--r--mysql-test/main/ps.test68
-rw-r--r--sql/item_cmpfunc.cc13
-rw-r--r--tests/mysql_client_test.c97
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 },