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); ...@@ -4747,3 +4747,26 @@ INSERT INTO t1 VALUES (1),(2),(3);
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT; 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 ERROR HY000: Default/ignore value is not supported for such parameter usage
DROP TABLE t1; 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); ...@@ -4287,3 +4287,32 @@ INSERT INTO t1 VALUES (1),(2),(3);
--error ER_INVALID_DEFAULT_PARAM --error ER_INVALID_DEFAULT_PARAM
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT; EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT;
DROP TABLE t1; 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): ...@@ -3313,7 +3313,15 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg):
item_type(PARAM_ITEM), item_type(PARAM_ITEM),
indicators(0), indicator(STMT_INDICATOR_NONE), indicators(0), indicator(STMT_INDICATOR_NONE),
set_param_func(default_set_param_func), 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*) "?"; name= (char*) "?";
/* /*
...@@ -3557,6 +3565,7 @@ bool Item_param::CONVERSION_INFO::convert(THD *thd, String *str) ...@@ -3557,6 +3565,7 @@ bool Item_param::CONVERSION_INFO::convert(THD *thd, String *str)
bool Item_param::set_from_item(THD *thd, Item *item) bool Item_param::set_from_item(THD *thd, Item *item)
{ {
DBUG_ENTER("Item_param::set_from_item"); DBUG_ENTER("Item_param::set_from_item");
m_is_settable_routine_parameter= item->get_settable_routine_parameter();
if (limit_clause_param) if (limit_clause_param)
{ {
longlong val= item->val_int(); longlong val= item->val_int();
...@@ -4132,6 +4141,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src) ...@@ -4132,6 +4141,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
void Item_param::set_default() void Item_param::set_default()
{ {
m_is_settable_routine_parameter= false;
state= DEFAULT_VALUE; state= DEFAULT_VALUE;
fixed= true; fixed= true;
/* /*
...@@ -4147,6 +4157,7 @@ void Item_param::set_default() ...@@ -4147,6 +4157,7 @@ void Item_param::set_default()
void Item_param::set_ignore() void Item_param::set_ignore()
{ {
m_is_settable_routine_parameter= false;
state= IGNORE_VALUE; state= IGNORE_VALUE;
fixed= true; fixed= true;
null_value= true; null_value= true;
......
...@@ -2982,7 +2982,7 @@ class Item_param :public Item_basic_value, ...@@ -2982,7 +2982,7 @@ class Item_param :public Item_basic_value,
Rewritable_query_parameter *get_rewritable_query_parameter() Rewritable_query_parameter *get_rewritable_query_parameter()
{ return this; } { return this; }
Settable_routine_parameter *get_settable_routine_parameter() 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 append_for_log(THD *thd, String *str);
bool check_vcol_func_processor(void *int_arg) {return FALSE;} bool check_vcol_func_processor(void *int_arg) {return FALSE;}
...@@ -3002,6 +3002,7 @@ class Item_param :public Item_basic_value, ...@@ -3002,6 +3002,7 @@ class Item_param :public Item_basic_value,
private: private:
Send_field *m_out_param_info; 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