maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #10118
MDEV-11360 Dynamic SQL: DEFAULT as a bind parameter
Hello Sanja,
Please review MDEV-11360.
Thanks!
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 5150ee6..ef8d36e 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -4649,3 +4649,65 @@ DROP TABLE t1;
#
# End of 10.2 tests
#
+#
+# MDEV-11360 Dynamic SQL: DEFAULT as a bind parameter
+#
+CREATE TABLE t1 (a INT DEFAULT 10, b INT DEFAULT NULL);
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?,?)' USING DEFAULT, DEFAULT;
+SELECT * FROM t1;
+a b
+10 NULL
+UPDATE t1 SET a=20, b=30;
+SELECT * FROM t1;
+a b
+20 30
+EXECUTE IMMEDIATE 'UPDATE t1 SET a=?,b=?' USING DEFAULT, DEFAULT;
+SELECT * FROM t1;
+a b
+10 NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a INT DEFAULT 10);
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?+1)' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (CONCAT(?,?))' USING DEFAULT, 'test';
+ERROR HY000: Default value is not supported for such parameter usage
+DROP TABLE t1;
+CREATE TABLE t1 (a INT DEFAULT 10);
+INSERT INTO t1 VALUES (20);
+EXECUTE IMMEDIATE 'UPDATE t1 SET a=?+1' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'UPDATE t1 SET a=CONCAT(?,?)' USING DEFAULT, 'test';
+ERROR HY000: Default value is not supported for such parameter usage
+DROP TABLE t1;
+EXECUTE IMMEDIATE 'SELECT CAST(? AS SIGNED)' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT CAST(? AS DOUBLE)' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT CAST(? AS CHAR)' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT CAST(? AS DECIMAL(10,1))' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT CAST(? AS TIME)' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT CAST(? AS DATE)' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT CAST(? AS DATETIME)' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT ?+1' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT CONCAT(?,?)' USING DEFAULT,'test';
+ERROR HY000: Default value is not supported for such parameter usage
+EXECUTE IMMEDIATE 'SELECT 1 LIMIT ?' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+CREATE TABLE t1 (a INT DEFAULT 10);
+INSERT INTO t1 VALUES (1),(2),(3);
+EXECUTE IMMEDIATE 'SELECT * FROM t1 LIMIT ?' USING DEFAULT;
+ERROR HY000: Default value is not supported for such parameter usage
+DROP TABLE t1;
+# The output of this query in 'Note' is a syntactically incorrect query.
+# But as it's never logged, it's ok. It should be human readable only.
+EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT ?' USING DEFAULT;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select default AS `?`
diff --git a/mysql-test/suite/binlog/r/binlog_stm_ps.result b/mysql-test/suite/binlog/r/binlog_stm_ps.result
index bca298d..0b7491e 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_ps.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_ps.result
@@ -129,3 +129,59 @@ master-bin.000003 # Gtid # # BEGIN GTID #-#-#
master-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (103)
master-bin.000003 # Query # # COMMIT
DROP TABLE t1;
+#
+# MDEV-11360 Dynamic SQL: DEFAULT as a bind parameter
+#
+FLUSH LOGS;
+CREATE TABLE t1 (a INT DEFAULT 10);
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (Default)';
+# The output of this query in 'Note' is a syntactically incorrect query.
+# But as it's never logged, it's ok. It should be human readable only.
+EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT ?' USING Default;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select default AS `?`
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING Default;
+CREATE PROCEDURE p1 ()
+BEGIN
+INSERT INTO t1 VALUES (Default);
+# EXPLAIN should not be logged
+EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT ?' USING Default;
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING Default;
+END;
+$$
+CALL p1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+DROP PROCEDURE p1;
+DROP TABLE t1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000004 # Binlog_checkpoint # # master-bin.000004
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; CREATE TABLE t1 (a INT DEFAULT 10)
+master-bin.000004 # Gtid # # BEGIN GTID #-#-#
+master-bin.000004 # Query # # use `test`; INSERT INTO t1 VALUES (Default)
+master-bin.000004 # Query # # COMMIT
+master-bin.000004 # Gtid # # BEGIN GTID #-#-#
+master-bin.000004 # Query # # use `test`; INSERT INTO t1 VALUES (DEFAULT)
+master-bin.000004 # Query # # COMMIT
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
+BEGIN
+INSERT INTO t1 VALUES (Default);
+# EXPLAIN should not be logged
+EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT ?' USING Default;
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING Default;
+END
+master-bin.000004 # Gtid # # BEGIN GTID #-#-#
+master-bin.000004 # Query # # use `test`; INSERT INTO t1 VALUES (Default)
+master-bin.000004 # Query # # COMMIT
+master-bin.000004 # Gtid # # BEGIN GTID #-#-#
+master-bin.000004 # Query # # use `test`; INSERT INTO t1 VALUES (DEFAULT)
+master-bin.000004 # Query # # COMMIT
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; DROP PROCEDURE p1
+master-bin.000004 # Gtid # # GTID #-#-#
+master-bin.000004 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
diff --git a/mysql-test/suite/binlog/t/binlog_stm_ps.test b/mysql-test/suite/binlog/t/binlog_stm_ps.test
index 38f1350..e6e5498 100644
--- a/mysql-test/suite/binlog/t/binlog_stm_ps.test
+++ b/mysql-test/suite/binlog/t/binlog_stm_ps.test
@@ -70,3 +70,32 @@ EXECUTE IMMEDIATE @stmt USING @a;
--let $binlog_file = LAST
source include/show_binlog_events.inc;
DROP TABLE t1;
+
+--echo #
+--echo # MDEV-11360 Dynamic SQL: DEFAULT as a bind parameter
+--echo #
+
+FLUSH LOGS;
+CREATE TABLE t1 (a INT DEFAULT 10);
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (Default)';
+--echo # The output of this query in 'Note' is a syntactically incorrect query.
+--echo # But as it's never logged, it's ok. It should be human readable only.
+EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT ?' USING Default;
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING Default;
+
+DELIMITER $$;
+CREATE PROCEDURE p1 ()
+BEGIN
+ INSERT INTO t1 VALUES (Default);
+ # EXPLAIN should not be logged
+ EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT ?' USING Default;
+ EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING Default;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index cd48309..39b8cb0 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -4188,3 +4188,75 @@ DROP TABLE t1;
--echo #
--echo # End of 10.2 tests
--echo #
+
+
+--echo #
+--echo # MDEV-11360 Dynamic SQL: DEFAULT as a bind parameter
+--echo #
+
+# Correct usage
+CREATE TABLE t1 (a INT DEFAULT 10, b INT DEFAULT NULL);
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?,?)' USING DEFAULT, DEFAULT;
+SELECT * FROM t1;
+UPDATE t1 SET a=20, b=30;
+SELECT * FROM t1;
+EXECUTE IMMEDIATE 'UPDATE t1 SET a=?,b=?' USING DEFAULT, DEFAULT;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Incorrect usage in a expression in INSERT..VALUES
+CREATE TABLE t1 (a INT DEFAULT 10);
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?+1)' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (CONCAT(?,?))' USING DEFAULT, 'test';
+DROP TABLE t1;
+
+# Incorrect usage in UPDATE..SET
+CREATE TABLE t1 (a INT DEFAULT 10);
+INSERT INTO t1 VALUES (20);
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'UPDATE t1 SET a=?+1' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'UPDATE t1 SET a=CONCAT(?,?)' USING DEFAULT, 'test';
+DROP TABLE t1;
+
+
+# Incorrect usage in not an UPDATE/INSERT query at all
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT CAST(? AS SIGNED)' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT CAST(? AS DOUBLE)' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT CAST(? AS CHAR)' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT CAST(? AS DECIMAL(10,1))' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT CAST(? AS TIME)' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT CAST(? AS DATE)' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT CAST(? AS DATETIME)' USING DEFAULT;
+
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT ?+1' USING DEFAULT;
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT CONCAT(?,?)' USING DEFAULT,'test';
+
+
+# Incorrect usage in the LIMIT clause
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT 1 LIMIT ?' USING DEFAULT;
+CREATE TABLE t1 (a INT DEFAULT 10);
+INSERT INTO t1 VALUES (1),(2),(3);
+--error ER_INVALID_DEFAULT_PARAM
+EXECUTE IMMEDIATE 'SELECT * FROM t1 LIMIT ?' USING DEFAULT;
+DROP TABLE t1;
+
+
+--echo # The output of this query in 'Note' is a syntactically incorrect query.
+--echo # But as it's never logged, it's ok. It should be human readable only.
+EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT ?' USING DEFAULT;
+
+#clone_item
+#eq
diff --git a/sql/item.cc b/sql/item.cc
index 70b7383..9d287e2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -43,6 +43,7 @@
#include "sql_expression_cache.h"
const String my_null_string("NULL", 4, default_charset_info);
+const String my_default_string("DEFAULT", 7, default_charset_info);
static int save_field_in_field(Field *, bool *, Field *, bool);
@@ -3606,13 +3607,20 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
top_table() !=
field->table->pos_in_table_list);
case NO_VALUE:
- default:
- DBUG_ASSERT(0);
+ break;
}
+ DBUG_ASSERT(0);
return 1;
}
+void Item_param::invalid_default_param() const
+{
+ my_message(ER_INVALID_DEFAULT_PARAM,
+ ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
+}
+
+
bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
{
if (state == TIME_VALUE)
@@ -3648,14 +3656,14 @@ double Item_param::val_real()
time value for the placeholder.
*/
return TIME_to_double(&value.time);
+ case DEFAULT_VALUE:
+ invalid_default_param();
case NULL_VALUE:
return 0.0;
- case DEFAULT_VALUE:
- my_message(ER_INVALID_DEFAULT_PARAM,
- ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
- default:
- DBUG_ASSERT(0);
+ case NO_VALUE:
+ break;
}
+ DBUG_ASSERT(0);
return 0.0;
}
@@ -3681,13 +3689,13 @@ longlong Item_param::val_int()
case TIME_VALUE:
return (longlong) TIME_to_ulonglong(&value.time);
case DEFAULT_VALUE:
- my_message(ER_INVALID_DEFAULT_PARAM,
- ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
+ invalid_default_param();
case NULL_VALUE:
return 0;
- default:
- DBUG_ASSERT(0);
+ case NO_VALUE:
+ break;
}
+ DBUG_ASSERT(0);
return 0;
}
@@ -3711,13 +3719,13 @@ my_decimal *Item_param::val_decimal(my_decimal *dec)
return TIME_to_my_decimal(&value.time, dec);
}
case DEFAULT_VALUE:
- my_message(ER_INVALID_DEFAULT_PARAM,
- ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
+ invalid_default_param();
case NULL_VALUE:
- return 0;
- default:
- DBUG_ASSERT(0);
+ return 0;
+ case NO_VALUE:
+ break;
}
+ DBUG_ASSERT(0);
return 0;
}
@@ -3749,14 +3757,14 @@ String *Item_param::val_str(String* str)
return str;
}
case DEFAULT_VALUE:
- my_message(ER_INVALID_DEFAULT_PARAM,
- ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
+ invalid_default_param();
case NULL_VALUE:
return NULL;
- default:
- DBUG_ASSERT(0);
+ case NO_VALUE:
+ break;
}
- return str;
+ DBUG_ASSERT(0);
+ return NULL;
}
/**
@@ -3775,15 +3783,15 @@ const String *Item_param::query_val_str(THD *thd, String* str) const
switch (state) {
case INT_VALUE:
str->set_int(value.integer, unsigned_flag, &my_charset_bin);
- break;
+ return str;
case REAL_VALUE:
str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
- break;
+ return str;
case DECIMAL_VALUE:
if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
0, 0, 0, str) > 1)
return &my_null_string;
- break;
+ return str;
case TIME_VALUE:
{
static const uint32 typelen= 9; // "TIMESTAMP" is the longest type name
@@ -3818,7 +3826,7 @@ const String *Item_param::query_val_str(THD *thd, String* str) const
ptr+= (uint) my_TIME_to_str(&value.time, ptr, decimals);
*ptr++= '\'';
str->length((uint32) (ptr - buf));
- break;
+ return str;
}
case STRING_VALUE:
case LONG_DATA_VALUE:
@@ -3827,17 +3835,17 @@ const String *Item_param::query_val_str(THD *thd, String* str) const
append_query_string(value.cs_info.character_set_client, str,
str_value.ptr(), str_value.length(),
thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES);
- break;
+ return str;
}
case DEFAULT_VALUE:
- my_message(ER_INVALID_DEFAULT_PARAM,
- ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
+ return &my_default_string;
case NULL_VALUE:
return &my_null_string;
- default:
- DBUG_ASSERT(0);
+ case NO_VALUE:
+ break;
}
- return str;
+ DBUG_ASSERT(0);
+ return NULL;
}
@@ -3883,8 +3891,7 @@ Item_param::clone_item(THD *thd)
MEM_ROOT *mem_root= thd->mem_root;
switch (state) {
case DEFAULT_VALUE:
- my_message(ER_INVALID_DEFAULT_PARAM,
- ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
+ invalid_default_param();
case NULL_VALUE:
return new (mem_root) Item_null(thd, name);
case INT_VALUE:
@@ -3894,6 +3901,8 @@ Item_param::clone_item(THD *thd)
case REAL_VALUE:
return new (mem_root) Item_float(thd, name, value.real, decimals,
max_length);
+ case DECIMAL_VALUE:
+ break; // Should create Item_decimal. See MDEV-11361.
case STRING_VALUE:
case LONG_DATA_VALUE:
return new (mem_root) Item_string(thd, name, str_value.c_ptr_quick(),
@@ -3903,7 +3912,6 @@ Item_param::clone_item(THD *thd)
case TIME_VALUE:
break;
case NO_VALUE:
- default:
DBUG_ASSERT(0);
};
return 0;
@@ -3918,8 +3926,7 @@ Item_param::eq(const Item *item, bool binary_cmp) const
switch (state) {
case DEFAULT_VALUE:
- my_message(ER_INVALID_DEFAULT_PARAM,
- ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
+ invalid_default_param();
case NULL_VALUE:
return null_eq(item);
case INT_VALUE:
@@ -4001,6 +4008,15 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
void Item_param::set_default()
{
state= DEFAULT_VALUE;
+ /*
+ When Item_param is set to DEFAULT_VALUE:
+ - its val_str() and val_decimal() return NULL
+ - get_date() returns true
+ It's important also to have null_value==true for DEFAULT_VALUE.
+ Otherwise the callers of val_xxx() and get_date(), e.g. Item::send(),
+ can misbehave (e.g. crash on asserts).
+ */
+ null_value= true;
}
/**
@@ -6198,6 +6214,12 @@ int Item::save_in_field(Field *field, bool no_conversions)
}
+bool Item::save_in_param(THD *thd, Item_param *param)
+{
+ return param->set_from_item(thd, this);
+}
+
+
int Item_string::save_in_field(Field *field, bool no_conversions)
{
String *result;
diff --git a/sql/item.h b/sql/item.h
index 7844b67..6d2445b 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -61,6 +61,7 @@ class Protocol;
struct TABLE_LIST;
void item_init(void); /* Init item functions */
class Item_field;
+class Item_param;
class user_var_entry;
class JOIN;
struct KEY_FIELD;
@@ -819,6 +820,7 @@ class Item: public Value_source,
/* Function returns 1 on overflow and -1 on fatal errors */
int save_in_field_no_warnings(Field *field, bool no_conversions);
virtual int save_in_field(Field *field, bool no_conversions);
+ virtual bool save_in_param(THD *thd, Item_param *param);
virtual void save_org_in_field(Field *field,
fast_field_copier data
__attribute__ ((__unused__)))
@@ -2959,6 +2961,8 @@ class Item_param :public Item_basic_value,
Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
private:
+ void invalid_default_param() const;
+
virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
virtual void set_out_param_info(Send_field *info);
@@ -5135,6 +5139,11 @@ class Item_default_value : public Item_field
bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate);
bool send(Protocol *protocol, String *buffer);
int save_in_field(Field *field_arg, bool no_conversions);
+ bool save_in_param(THD *thd, Item_param *param)
+ {
+ param->set_default();
+ return false;
+ }
table_map used_tables() const { return (table_map)0L; }
Item_field *field_for_view_update() { return 0; }
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 97a33a5..1e943ca 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1230,7 +1230,7 @@ insert_params_from_actual_params(Prepared_statement *stmt,
{
Item_param *param= *it;
Item *ps_param= param_it++;
- if (param->set_from_item(stmt->thd, ps_param) ||
+ if (ps_param->save_in_param(stmt->thd, param) ||
param->convert_str_value(stmt->thd))
DBUG_RETURN(1);
}
@@ -1273,7 +1273,7 @@ insert_params_from_actual_params_with_log(Prepared_statement *stmt,
(e.g. value.cs_info.character_set_client is used in the query_val_str()).
*/
setup_one_conversion_function(thd, param, param->field_type());
- if (param->set_from_item(thd, ps_param))
+ if (ps_param->save_in_param(thd, param))
DBUG_RETURN(1);
if (acc.append(param))
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 163322d..e0e0f6e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2280,7 +2280,7 @@ execute_var_list:
;
execute_var_ident:
- expr
+ expr_or_default
{
if (Lex->prepared_stmt_params.push_back($1, thd->mem_root))
MYSQL_YYABORT;
Follow ups