Commit ae91690d authored by Alexander Barkov's avatar Alexander Barkov

MDEV-11780 Crash with PREPARE + SP out parameter + literal

Before "MDEV-10709 Expressions as parameters to Dynamic SQL" only
user variables were syntactically allowed as EXECUTE parameters.
User variables were OK as both IN and OUT parameters.
When Item_param was bound to an actual parameter (a user variable),
it automatically meant that the bound Item was settable.
The DBUG_ASSERT() in Protocol_text::send_out_parameters() guarded that
the actual parameter is really settable.

After MDEV-10709, any kind of expressions are allowed as EXECUTE IN parameters.
But the patch for MDEV-10709 forgot to check that only descendants of
Settable_routine_parameter should be allowed as OUT parameters.
So an attempt to pass a non-settable parameter as an OUT parameter
made server crash on the above mentioned DBUG_ASSERT.

This patch changes Item_param::get_settable_routine_parameter(),
which previously always returned "this". Now, when Item_param is bound
to some Item, it caches if the bound Item is settable.
Item_param::get_settable_routine_parameter() now returns "this" only
if the bound actual parameter is settable, and returns NULL otherwise.
parent 83680449
......@@ -4747,3 +4747,26 @@ INSERT INTO t1 VALUES (1),(2),(3);
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT;
ERROR HY000: Default/ignore value is not supported for such parameter usage
DROP TABLE t1;
#
# MDEV-11780 Crash with PREPARE + SP out parameter + literal
#
CREATE OR REPLACE PROCEDURE p1(OUT a INT)
BEGIN
SET a=10;
END;
$$
PREPARE stmt FROM 'CALL p1(?)';
EXECUTE stmt USING 10;
ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger
EXECUTE stmt USING DEFAULT;
ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger
EXECUTE stmt USING IGNORE;
ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger
DEALLOCATE PREPARE stmt;
EXECUTE IMMEDIATE 'CALL p1(?)' USING 10;
ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger
EXECUTE IMMEDIATE 'CALL p1(?)' USING DEFAULT;
ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger
EXECUTE IMMEDIATE 'CALL p1(?)' USING IGNORE;
ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger
DROP PROCEDURE p1;
......@@ -4287,3 +4287,32 @@ INSERT INTO t1 VALUES (1),(2),(3);
--error ER_INVALID_DEFAULT_PARAM
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT;
DROP TABLE t1;
--echo #
--echo # MDEV-11780 Crash with PREPARE + SP out parameter + literal
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1(OUT a INT)
BEGIN
SET a=10;
END;
$$
DELIMITER ;$$
PREPARE stmt FROM 'CALL p1(?)';
--error ER_SP_NOT_VAR_ARG
EXECUTE stmt USING 10;
--error ER_SP_NOT_VAR_ARG
EXECUTE stmt USING DEFAULT;
--error ER_SP_NOT_VAR_ARG
EXECUTE stmt USING IGNORE;
DEALLOCATE PREPARE stmt;
--error ER_SP_NOT_VAR_ARG
EXECUTE IMMEDIATE 'CALL p1(?)' USING 10;
--error ER_SP_NOT_VAR_ARG
EXECUTE IMMEDIATE 'CALL p1(?)' USING DEFAULT;
--error ER_SP_NOT_VAR_ARG
EXECUTE IMMEDIATE 'CALL p1(?)' USING IGNORE;
DROP PROCEDURE p1;
......@@ -3313,7 +3313,15 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg):
item_type(PARAM_ITEM),
indicators(0), indicator(STMT_INDICATOR_NONE),
set_param_func(default_set_param_func),
m_out_param_info(NULL)
m_out_param_info(NULL),
/*
Set m_is_settable_routine_parameter to "true" by default.
This is needed for client-server protocol,
whose parameters are always settable.
For dynamic SQL, settability depends on the type of Item passed
as an actual parameter. See Item_param::set_from_item().
*/
m_is_settable_routine_parameter(true)
{
name= (char*) "?";
/*
......@@ -3557,6 +3565,7 @@ bool Item_param::CONVERSION_INFO::convert(THD *thd, String *str)
bool Item_param::set_from_item(THD *thd, Item *item)
{
DBUG_ENTER("Item_param::set_from_item");
m_is_settable_routine_parameter= item->get_settable_routine_parameter();
if (limit_clause_param)
{
longlong val= item->val_int();
......@@ -4132,6 +4141,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
void Item_param::set_default()
{
m_is_settable_routine_parameter= false;
state= DEFAULT_VALUE;
fixed= true;
/*
......@@ -4147,6 +4157,7 @@ void Item_param::set_default()
void Item_param::set_ignore()
{
m_is_settable_routine_parameter= false;
state= IGNORE_VALUE;
fixed= true;
null_value= true;
......
......@@ -2982,7 +2982,7 @@ class Item_param :public Item_basic_value,
Rewritable_query_parameter *get_rewritable_query_parameter()
{ return this; }
Settable_routine_parameter *get_settable_routine_parameter()
{ return this; }
{ return m_is_settable_routine_parameter ? this : NULL; }
bool append_for_log(THD *thd, String *str);
bool check_vcol_func_processor(void *int_arg) {return FALSE;}
......@@ -3002,6 +3002,7 @@ class Item_param :public Item_basic_value,
private:
Send_field *m_out_param_info;
bool m_is_settable_routine_parameter;
};
......
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