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

MDEV-11360 Dynamic SQL: DEFAULT as a bind parameter

This patch adds DEFAULT as a possible dynamic SQL parameter, e.g.:
  EXECUTE IMMEDIATE 'INSERT INTO t1 (column) VALUES(?)' USING DEFAULT;
  EXECUTE IMMEDIATE 'UPDATE t1 SET column=?' USING DEFAULT;
and for similar PREPARE..EXECUTE queries.

This is done for symmetry with the STMT_INDICATOR_DEFAULT indicator in
the client-server PS protocol.

The changes include:
- Allowing DEFAULT as a possible option in execute USING clause (sql_yacc.yy)
- Adding "virtual bool Item::save_in_param(THD *thd, Item_param *param)",
  because "normal" items (that have real values) and Item_default_value
  have now different actions when assigning itself as an Item_param value.
- Fixing switch() statements in a few Item_param methods not to have "default",
  because it was easy to forget to add a new "case" when adding a new XXX_VALUE
  value into the enum Item_param::enum_item_param_state.
  This is important, as we'll be adding new values soon, e.g. for MDEV-11359.
  Removing "default" helped to find and report bugs MDEV-11361 and MDEV-11362,
  because DECIMAL_VALUE is obviously not properly handled in some cases.
parent 1d0f1741
......@@ -4649,3 +4649,70 @@ 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 `?`
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT;
ERROR HY000: Default value is not supported for such parameter usage
DROP TABLE t1;
......@@ -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 */
......@@ -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;
......@@ -4188,3 +4188,80 @@ 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;
# This tests Item_param::eq() for DEFAULT as a bound value
CREATE TABLE t1 (a INT);
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;
......@@ -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);
......@@ -3585,6 +3586,11 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
{
field->set_notnull();
/*
There's no "default" intentionally, to make compiler complain
when adding a new XXX_VALUE value.
Garbage (e.g. in case of a memory overrun) is handled after the switch.
*/
switch (state) {
case INT_VALUE:
return field->store(value.integer, unsigned_flag);
......@@ -3606,13 +3612,21 @@ 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);
DBUG_ASSERT(0); // Should not be possible
return true;
}
DBUG_ASSERT(0); // Garbage
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)
......@@ -3626,6 +3640,7 @@ bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
double Item_param::val_real()
{
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
case REAL_VALUE:
return value.real;
......@@ -3648,20 +3663,23 @@ double Item_param::val_real()
time value for the placeholder.
*/
return TIME_to_double(&value.time);
case DEFAULT_VALUE:
invalid_default_param();
// fall through
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:
DBUG_ASSERT(0); // Should not be possible
return 0.0;
}
DBUG_ASSERT(0); // Garbage
return 0.0;
}
longlong Item_param::val_int()
{
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
case REAL_VALUE:
return (longlong) rint(value.real);
......@@ -3681,19 +3699,22 @@ 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();
// fall through
case NULL_VALUE:
return 0;
default:
DBUG_ASSERT(0);
case NO_VALUE:
DBUG_ASSERT(0); // Should not be possible
return 0;
}
DBUG_ASSERT(0); // Garbage
return 0;
}
my_decimal *Item_param::val_decimal(my_decimal *dec)
{
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
case DECIMAL_VALUE:
return &decimal_value;
......@@ -3711,19 +3732,22 @@ 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();
// fall through
case NULL_VALUE:
return 0;
default:
DBUG_ASSERT(0);
return 0;
case NO_VALUE:
DBUG_ASSERT(0); // Should not be possible
return 0;
}
DBUG_ASSERT(0); // Gabrage
return 0;
}
String *Item_param::val_str(String* str)
{
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
case STRING_VALUE:
case LONG_DATA_VALUE:
......@@ -3749,14 +3773,16 @@ 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();
// fall through
case NULL_VALUE:
return NULL;
default:
DBUG_ASSERT(0);
case NO_VALUE:
DBUG_ASSERT(0); // Should not be possible
return NULL;
}
return str;
DBUG_ASSERT(0); // Garbage
return NULL;
}
/**
......@@ -3772,18 +3798,19 @@ String *Item_param::val_str(String* str)
const String *Item_param::query_val_str(THD *thd, String* str) const
{
// There's no "default". See comments in Item_param::save_in_field().
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 +3845,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 +3854,18 @@ 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:
DBUG_ASSERT(0); // Should not be possible
return NULL;
}
return str;
DBUG_ASSERT(0); // Garbage
return NULL;
}
......@@ -3881,10 +3909,11 @@ Item *
Item_param::clone_item(THD *thd)
{
MEM_ROOT *mem_root= thd->mem_root;
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
case DEFAULT_VALUE:
my_message(ER_INVALID_DEFAULT_PARAM,
ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
invalid_default_param();
// fall through
case NULL_VALUE:
return new (mem_root) Item_null(thd, name);
case INT_VALUE:
......@@ -3894,6 +3923,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:
return 0; // 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(),
......@@ -3901,11 +3932,11 @@ Item_param::clone_item(THD *thd)
collation.derivation,
collation.repertoire);
case TIME_VALUE:
break;
return 0;
case NO_VALUE:
default:
DBUG_ASSERT(0);
};
return 0;
}
DBUG_ASSERT(0); // Garbage
return 0;
}
......@@ -3916,10 +3947,11 @@ Item_param::eq(const Item *item, bool binary_cmp) const
if (!basic_const_item())
return FALSE;
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
case DEFAULT_VALUE:
my_message(ER_INVALID_DEFAULT_PARAM,
ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
invalid_default_param();
return false;
case NULL_VALUE:
return null_eq(item);
case INT_VALUE:
......@@ -3929,9 +3961,12 @@ Item_param::eq(const Item *item, bool binary_cmp) const
case STRING_VALUE:
case LONG_DATA_VALUE:
return str_eq(&str_value, item, binary_cmp);
default:
break;
case DECIMAL_VALUE:
case TIME_VALUE:
case NO_VALUE:
return false;
}
DBUG_ASSERT(0); // Garbage
return FALSE;
}
......@@ -4001,6 +4036,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 +6242,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;
......
......@@ -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);
......@@ -5143,6 +5147,13 @@ 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)
{
// It should not be possible to have "EXECUTE .. USING DEFAULT(a)"
DBUG_ASSERT(arg == NULL);
param->set_default();
return false;
}
table_map used_tables() const { return (table_map)0L; }
Item_field *field_for_view_update() { return 0; }
......
......@@ -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))
......
......@@ -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;
......
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