mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-22779: Crash: Prepared Statement with a '?' parameter inside a re-used CTE
When a prepared statement parameter '?' is used in a CTE that is used multiple times, the following happens: - The CTE definition is re-parsed multiple times. - There are multiple Item_param objects referring to the same "?" in the original query. - Prepared_statement::param has a pointer to the first of them, the others are "clones". - When prepared statement parameter gets the value, it should be passed over to clones with param->sync_clones() call. This call is made in insert_params(), etc. It was not made in insert_params_with_log(). This would cause Item_param to not have any value which would confuse the query optimizer. Added the missing call.
This commit is contained in:
@ -903,6 +903,8 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
|
|||||||
|
|
||||||
if (param->convert_str_value(thd))
|
if (param->convert_str_value(thd))
|
||||||
DBUG_RETURN(1); /* out of memory */
|
DBUG_RETURN(1); /* out of memory */
|
||||||
|
|
||||||
|
param->sync_clones();
|
||||||
}
|
}
|
||||||
if (acc.finalize())
|
if (acc.finalize())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
@ -5997,6 +5997,7 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
|
|||||||
uint n_tables= my_count_bits(map);
|
uint n_tables= my_count_bits(map);
|
||||||
if (n_tables == 1) // Only one table
|
if (n_tables == 1) // Only one table
|
||||||
{
|
{
|
||||||
|
DBUG_ASSERT(!(map & PSEUDO_TABLE_BITS)); // Must be a real table
|
||||||
Table_map_iterator it(map);
|
Table_map_iterator it(map);
|
||||||
int tablenr= it.next_bit();
|
int tablenr= it.next_bit();
|
||||||
DBUG_ASSERT(tablenr != Table_map_iterator::BITMAP_END);
|
DBUG_ASSERT(tablenr != Table_map_iterator::BITMAP_END);
|
||||||
|
@ -19843,6 +19843,57 @@ static void test_bulk_replace()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void test_ps_params_in_ctes()
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
const char *query;
|
||||||
|
MYSQL_BIND ps_params[1];
|
||||||
|
int int_data[1];
|
||||||
|
MYSQL_STMT *stmt;
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "create table t1(a int, b int, key(a))");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "insert into t1 (a) values "
|
||||||
|
"(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
query=
|
||||||
|
"explain "
|
||||||
|
"with T as "
|
||||||
|
"( "
|
||||||
|
" select * from t1 where t1.a=? limit 2 "
|
||||||
|
") "
|
||||||
|
"select * from T as TA, T as TB;";
|
||||||
|
|
||||||
|
stmt= mysql_stmt_init(mysql);
|
||||||
|
check_stmt(stmt);
|
||||||
|
|
||||||
|
rc= mysql_stmt_prepare(stmt, query, (uint) strlen(query));
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
int_data[0]=2;
|
||||||
|
|
||||||
|
ps_params[0].buffer_type= MYSQL_TYPE_LONG;
|
||||||
|
ps_params[0].buffer= (char *) &int_data[0];
|
||||||
|
ps_params[0].length= 0;
|
||||||
|
ps_params[0].is_null= 0;
|
||||||
|
|
||||||
|
rc= mysql_stmt_bind_param(stmt, ps_params);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_stmt_store_result(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "drop table t1");
|
||||||
|
myquery(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct my_tests_st my_tests[]= {
|
static struct my_tests_st my_tests[]= {
|
||||||
{ "disable_query_logs", disable_query_logs },
|
{ "disable_query_logs", disable_query_logs },
|
||||||
{ "test_view_sp_list_fields", test_view_sp_list_fields },
|
{ "test_view_sp_list_fields", test_view_sp_list_fields },
|
||||||
@ -20127,6 +20178,7 @@ static struct my_tests_st my_tests[]= {
|
|||||||
{ "test_bulk_delete", test_bulk_delete },
|
{ "test_bulk_delete", test_bulk_delete },
|
||||||
{ "test_bulk_replace", test_bulk_replace },
|
{ "test_bulk_replace", test_bulk_replace },
|
||||||
#endif
|
#endif
|
||||||
|
{ "test_ps_params_in_ctes", test_ps_params_in_ctes },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user