Commit 9f209681 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-20261 NULL passed to String::eq, SEGV, server crash, regression in 10.4

Type_handler_xxx::Item_const_eq() can handle only non-NULL values.
The code in Item_basic_value::eq() did not take this into account.

Adding a test to detect three different combinations:
- Both values are NULLs, return true.
- Only one value is NULL, return false.
- Both values are not NULL, call Type_handler::Item_const_eq()
  to check equality.
parent db537a83
...@@ -3477,8 +3477,20 @@ bool Item_basic_value::eq(const Item *item, bool binary_cmp) const ...@@ -3477,8 +3477,20 @@ bool Item_basic_value::eq(const Item *item, bool binary_cmp) const
(h0= type_handler())->type_handler_for_comparison() == (h0= type_handler())->type_handler_for_comparison() ==
(h1= item->type_handler())->type_handler_for_comparison() && (h1= item->type_handler())->type_handler_for_comparison() &&
h0->cast_to_int_type_handler()->type_handler_for_comparison() == h0->cast_to_int_type_handler()->type_handler_for_comparison() ==
h1->cast_to_int_type_handler()->type_handler_for_comparison() && h1->cast_to_int_type_handler()->type_handler_for_comparison();
h0->Item_const_eq(c0, c1, binary_cmp); if (res)
{
switch (c0->const_is_null() + c1->const_is_null()) {
case 2: // Two NULLs
res= true;
break;
case 1: // NULL and non-NULL
res= false;
break;
case 0: // Two non-NULLs
res= h0->Item_const_eq(c0, c1, binary_cmp);
}
}
DBUG_EXECUTE_IF("Item_basic_value", DBUG_EXECUTE_IF("Item_basic_value",
push_warning_printf(current_thd, push_warning_printf(current_thd,
Sql_condition::WARN_LEVEL_NOTE, Sql_condition::WARN_LEVEL_NOTE,
......
...@@ -20886,6 +20886,53 @@ static void test_explain_meta() ...@@ -20886,6 +20886,53 @@ static void test_explain_meta()
mct_close_log(); mct_close_log();
} }
/*
MDEV-20261 NULL passed to String::eq, SEGV, server crash, regression in 10.4
*/
static void test_mdev20261()
{
int rc;
MYSQL_STMT *stmt;
MYSQL_BIND param[1];
const char *query= "SELECT * FROM t1 WHERE f = ? OR f = 'foo'";
char val[]= "";
my_bool is_null= TRUE;
myheader("test_mdev20261");
rc= mysql_query(mysql, "CREATE OR REPLACE TABLE t1 (f varchar(64)) ENGINE=MyISAM");
myquery(rc);
stmt= mysql_stmt_init(mysql);
check_stmt(stmt);
rc= mysql_stmt_prepare(stmt, query, strlen(query));
check_execute(stmt, rc);
verify_param_count(stmt, 1);
bzero((char*) param, sizeof(param));
param[0].buffer= &val;
param[0].buffer_type= MYSQL_TYPE_STRING;
param[0].is_null= &is_null;
rc= mysql_stmt_bind_param(stmt, param);
check_execute(stmt, rc);
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
rc= mysql_stmt_store_result(stmt);
check_execute(stmt, rc);
mysql_stmt_close(stmt);
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 },
...@@ -21179,6 +21226,7 @@ static struct my_tests_st my_tests[]= { ...@@ -21179,6 +21226,7 @@ static struct my_tests_st my_tests[]= {
#endif #endif
{ "test_explain_meta", test_explain_meta }, { "test_explain_meta", test_explain_meta },
{ "test_mdev18408", test_mdev18408 }, { "test_mdev18408", test_mdev18408 },
{ "test_mdev20261", test_mdev20261 },
{ 0, 0 } { 0, 0 }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment