mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
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.
This commit is contained in:
@@ -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;
|
||||
|
||||
13
sql/item.cc
13
sql/item.cc
@@ -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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
private:
|
||||
Send_field *m_out_param_info;
|
||||
bool m_is_settable_routine_parameter;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user