mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MDEV-15703: Crash in EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT
This patch fixes the issue with passing the DEFAULT or IGNORE values to positional parameters for some kind of SQL statements to be executed as prepared statements. The main idea of the patch is to associate an actual value being passed by the USING clause with the positional parameter represented by the Item_param class. Such association must be performed on execution of UPDATE statement in PS/SP mode. Other corner cases that results in server crash is on handling CREATE TABLE when positional parameter placed after the DEFAULT clause or CALL statement and passing either the value DEFAULT or IGNORE as an actual value for the positional parameter. This case is fixed by checking whether an error is set in diagnostics area at the function pack_vcols() on return from the function pack_expression()
This commit is contained in:
parent
6b2cd78695
commit
e48bd474a2
16 changed files with 418 additions and 17 deletions
|
@ -5815,5 +5815,123 @@ GROUP_CONCAT(@x)
|
|||
0
|
||||
DROP TABLE t;
|
||||
#
|
||||
# MDEV-15703: Crash in EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT
|
||||
#
|
||||
PREPARE stmt FROM 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)';
|
||||
EXECUTE stmt USING DEFAULT;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
DEALLOCATE PREPARE stmt;
|
||||
PREPARE stmt FROM 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)';
|
||||
EXECUTE stmt USING IGNORE;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
DEALLOCATE PREPARE stmt;
|
||||
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING IGNORE;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'BEGIN NOT ATOMIC DECLARE a INT DEFAULT ?; END' USING DEFAULT;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'BEGIN NOT ATOMIC DECLARE a INT DEFAULT ?; END' USING IGNORE;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
CREATE PROCEDURE p1(a INT) SELECT 1;
|
||||
EXECUTE IMMEDIATE 'CALL p1(?)' USING DEFAULT;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'CALL p1(?)' USING IGNORE;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
DROP PROCEDURE p1;
|
||||
EXECUTE IMMEDIATE 'SELECT ? UNION SELECT 1' USING DEFAULT;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'SELECT ? UNION SELECT 1' USING IGNORE;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'SELECT * FROM (SELECT ? UNION ALL SELECT 1) AS derived' USING DEFAULT;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'SELECT * FROM (SELECT ? UNION ALL SELECT 1) AS derived' USING IGNORE;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'SELECT * FROM (SELECT ? UNION DISTINCT SELECT 1) AS derived' USING DEFAULT;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'SELECT * FROM (SELECT ? UNION DISTINCT SELECT 1) AS derived' USING IGNORE;
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
# multi-update and DEFAULT
|
||||
CREATE TABLE t1 (a INT, b INT DEFAULT a);
|
||||
INSERT into t1 VALUES (1,2),(2,3);
|
||||
CREATE TABLE t2 (a INT, b INT DEFAULT a);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
UPDATE t1,t2 SET t1.b = DEFAULT, t2.b = DEFAULT WHERE t1.a=t2.a;
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
SELECT * FROM t2;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
# re-check the case for Prepared Statement with parameters
|
||||
TRUNCATE TABLE t1;
|
||||
TRUNCATE TABLE t2;
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET t1.b = ?, t2.b = ? WHERE t1.a=t2.a' USING DEFAULT, DEFAULT;
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
SELECT * FROM t2;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
DROP TABLE t1, t2;
|
||||
# multi-update and IGNORE
|
||||
CREATE TABLE t1 (a INT, b INT default a);
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
CREATE TABLE t2 (a INT, b INT default a);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
UPDATE t1,t2 SET t1.b = IGNORE, t2.b = IGNORE WHERE t1.a=t2.a;
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
1 2
|
||||
2 3
|
||||
SELECT * FROM t2;
|
||||
a b
|
||||
1 NULL
|
||||
2 NULL
|
||||
# re-check the case for Prepared Statement with parameters
|
||||
TRUNCATE TABLE t1;
|
||||
TRUNCATE TABLE t2;
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET t1.b = ?, t2.b = ? WHERE t1.a=t2.a' USING IGNORE, IGNORE;
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
1 2
|
||||
2 3
|
||||
SELECT * FROM t2;
|
||||
a b
|
||||
1 10
|
||||
2 30
|
||||
DROP TABLE t1, t2;
|
||||
# multi-update and DEFAULT parameter (no default)
|
||||
CREATE TABLE t1 (a INT, b INT NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
CREATE TABLE t2 (a INT, b INT NOT NULL);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET t1.b = ?, t2.b = ? WHERE t1.a=t2.a' USING DEFAULT, DEFAULT;
|
||||
ERROR HY000: Field 'b' doesn't have a default value
|
||||
DROP TABLE t1, t2;
|
||||
# multi-update and IGNORE parameter (no default)
|
||||
CREATE TABLE t1 (a INT, b INT NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
CREATE TABLE t2 (a INT, b INT NOT NULL);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET t1.b = ?, t2.b = ? WHERE t1.a=t2.a' USING IGNORE, IGNORE;
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
1 2
|
||||
2 3
|
||||
SELECT * FROM t2;
|
||||
a b
|
||||
1 10
|
||||
2 30
|
||||
DROP TABLE t1, t2;
|
||||
#
|
||||
# End of 10.4 tests
|
||||
#
|
||||
|
|
|
@ -5243,6 +5243,125 @@ EXECUTE IMMEDIATE 'SELECT GROUP_CONCAT(@x) FROM t GROUP BY @x := f';
|
|||
|
||||
DROP TABLE t;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-15703: Crash in EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT
|
||||
--echo #
|
||||
|
||||
PREPARE stmt FROM 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)';
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE stmt USING DEFAULT;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
PREPARE stmt FROM 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)';
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE stmt USING IGNORE;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT;
|
||||
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING IGNORE;
|
||||
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'BEGIN NOT ATOMIC DECLARE a INT DEFAULT ?; END' USING DEFAULT;
|
||||
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'BEGIN NOT ATOMIC DECLARE a INT DEFAULT ?; END' USING IGNORE;
|
||||
|
||||
CREATE PROCEDURE p1(a INT) SELECT 1;
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'CALL p1(?)' USING DEFAULT;
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'CALL p1(?)' USING IGNORE;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'SELECT ? UNION SELECT 1' USING DEFAULT;
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'SELECT ? UNION SELECT 1' USING IGNORE;
|
||||
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'SELECT * FROM (SELECT ? UNION ALL SELECT 1) AS derived' USING DEFAULT;
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'SELECT * FROM (SELECT ? UNION ALL SELECT 1) AS derived' USING IGNORE;
|
||||
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'SELECT * FROM (SELECT ? UNION DISTINCT SELECT 1) AS derived' USING DEFAULT;
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'SELECT * FROM (SELECT ? UNION DISTINCT SELECT 1) AS derived' USING IGNORE;
|
||||
|
||||
--echo # multi-update and DEFAULT
|
||||
CREATE TABLE t1 (a INT, b INT DEFAULT a);
|
||||
INSERT into t1 VALUES (1,2),(2,3);
|
||||
CREATE TABLE t2 (a INT, b INT DEFAULT a);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
|
||||
UPDATE t1,t2 SET t1.b = DEFAULT, t2.b = DEFAULT WHERE t1.a=t2.a;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
|
||||
--echo # re-check the case for Prepared Statement with parameters
|
||||
TRUNCATE TABLE t1;
|
||||
TRUNCATE TABLE t2;
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
|
||||
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET t1.b = ?, t2.b = ? WHERE t1.a=t2.a' USING DEFAULT, DEFAULT;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
|
||||
# Cleanup
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--echo # multi-update and IGNORE
|
||||
CREATE TABLE t1 (a INT, b INT default a);
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
CREATE TABLE t2 (a INT, b INT default a);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
|
||||
UPDATE t1,t2 SET t1.b = IGNORE, t2.b = IGNORE WHERE t1.a=t2.a;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
|
||||
--echo # re-check the case for Prepared Statement with parameters
|
||||
TRUNCATE TABLE t1;
|
||||
TRUNCATE TABLE t2;
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
|
||||
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET t1.b = ?, t2.b = ? WHERE t1.a=t2.a' USING IGNORE, IGNORE;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
|
||||
# Cleanup
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--echo # multi-update and DEFAULT parameter (no default)
|
||||
CREATE TABLE t1 (a INT, b INT NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
CREATE TABLE t2 (a INT, b INT NOT NULL);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
|
||||
--error ER_NO_DEFAULT_FOR_FIELD
|
||||
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET t1.b = ?, t2.b = ? WHERE t1.a=t2.a' USING DEFAULT, DEFAULT;
|
||||
|
||||
# Cleanup
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--echo # multi-update and IGNORE parameter (no default)
|
||||
CREATE TABLE t1 (a INT, b INT NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,2),(2,3);
|
||||
CREATE TABLE t2 (a INT, b INT NOT NULL);
|
||||
INSERT INTO t2 VALUES (1,10),(2,30);
|
||||
|
||||
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET t1.b = ?, t2.b = ? WHERE t1.a=t2.a' USING IGNORE, IGNORE;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
|
||||
# Cleanup
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.4 tests
|
||||
--echo #
|
||||
|
|
|
@ -2594,9 +2594,9 @@ ERROR HY000: 'ignore' is not allowed in this context
|
|||
VALUES (DEFAULT);
|
||||
ERROR HY000: 'default' is not allowed in this context
|
||||
EXECUTE IMMEDIATE 'VALUES (?)' USING IGNORE;
|
||||
ERROR HY000: 'ignore' is not allowed in this context
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
EXECUTE IMMEDIATE 'VALUES (?)' USING DEFAULT;
|
||||
ERROR HY000: 'default' is not allowed in this context
|
||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||
#
|
||||
# MDEV-24675: TVC using subqueries
|
||||
#
|
||||
|
|
|
@ -1349,9 +1349,9 @@ DELIMITER ;$$
|
|||
VALUES (IGNORE);
|
||||
--error ER_UNKNOWN_ERROR
|
||||
VALUES (DEFAULT);
|
||||
--error ER_UNKNOWN_ERROR
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'VALUES (?)' USING IGNORE;
|
||||
--error ER_UNKNOWN_ERROR
|
||||
--error ER_INVALID_DEFAULT_PARAM
|
||||
EXECUTE IMMEDIATE 'VALUES (?)' USING DEFAULT;
|
||||
|
||||
--echo #
|
||||
|
|
27
sql/field.cc
27
sql/field.cc
|
@ -1353,6 +1353,9 @@ bool Field::sp_prepare_and_store_item(THD *thd, Item **value)
|
|||
if (!(expr_item= thd->sp_prepare_func_item(value, 1)))
|
||||
goto error;
|
||||
|
||||
if (expr_item->check_is_evaluable_expression_or_error())
|
||||
goto error;
|
||||
|
||||
/*
|
||||
expr_item is now fixed, it's safe to call cmp_type()
|
||||
*/
|
||||
|
@ -11424,6 +11427,30 @@ bool Field::validate_value_in_record_with_warn(THD *thd, const uchar *record)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Find which reaction should be for IGNORE value.
|
||||
*/
|
||||
|
||||
ignore_value_reaction find_ignore_reaction(THD *thd)
|
||||
{
|
||||
enum_sql_command com= thd->lex->sql_command;
|
||||
|
||||
// All insert-like commands
|
||||
if (com == SQLCOM_INSERT || com == SQLCOM_REPLACE ||
|
||||
com == SQLCOM_INSERT_SELECT || com == SQLCOM_REPLACE_SELECT ||
|
||||
com == SQLCOM_LOAD)
|
||||
{
|
||||
return IGNORE_MEANS_DEFAULT;
|
||||
}
|
||||
// Update commands
|
||||
if (com == SQLCOM_UPDATE || com == SQLCOM_UPDATE_MULTI)
|
||||
{
|
||||
return IGNORE_MEANS_FIELD_VALUE;
|
||||
}
|
||||
return IGNORE_MEANS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
bool Field::save_in_field_default_value(bool view_error_processing)
|
||||
{
|
||||
THD *thd= table->in_use;
|
||||
|
|
|
@ -60,6 +60,15 @@ enum enum_check_fields
|
|||
CHECK_FIELD_ERROR_FOR_NULL,
|
||||
};
|
||||
|
||||
enum ignore_value_reaction
|
||||
{
|
||||
IGNORE_MEANS_ERROR,
|
||||
IGNORE_MEANS_DEFAULT,
|
||||
IGNORE_MEANS_FIELD_VALUE
|
||||
};
|
||||
|
||||
ignore_value_reaction find_ignore_reaction(THD *thd);
|
||||
|
||||
/*
|
||||
Common declarations for Field and Item
|
||||
*/
|
||||
|
|
70
sql/item.cc
70
sql/item.cc
|
@ -3991,7 +3991,9 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg,
|
|||
as an actual parameter. See Item_param::set_from_item().
|
||||
*/
|
||||
m_is_settable_routine_parameter(true),
|
||||
m_clones(thd->mem_root)
|
||||
m_clones(thd->mem_root),
|
||||
m_associated_field(nullptr),
|
||||
m_default_field(nullptr)
|
||||
{
|
||||
name= *name_arg;
|
||||
/*
|
||||
|
@ -4398,10 +4400,29 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
|
|||
case NULL_VALUE:
|
||||
return set_field_to_null_with_conversions(field, no_conversions);
|
||||
case DEFAULT_VALUE:
|
||||
if (m_associated_field)
|
||||
return assign_default(field);
|
||||
return field->save_in_field_default_value(field->table->pos_in_table_list->
|
||||
top_table() !=
|
||||
field->table->pos_in_table_list);
|
||||
case IGNORE_VALUE:
|
||||
if (m_associated_field)
|
||||
{
|
||||
switch (find_ignore_reaction(field->table->in_use))
|
||||
{
|
||||
case IGNORE_MEANS_DEFAULT:
|
||||
DBUG_ASSERT(0); // impossible now, but fully working code if needed
|
||||
return assign_default(field);
|
||||
case IGNORE_MEANS_FIELD_VALUE:
|
||||
m_associated_field->save_val(field);
|
||||
return false;
|
||||
default:
|
||||
; // fall through to error
|
||||
}
|
||||
DBUG_ASSERT(0); //impossible
|
||||
my_error(ER_INVALID_DEFAULT_PARAM, MYF(0));
|
||||
return true;
|
||||
}
|
||||
return field->save_in_field_ignore_value(field->table->pos_in_table_list->
|
||||
top_table() !=
|
||||
field->table->pos_in_table_list);
|
||||
|
@ -5007,6 +5028,44 @@ static Field *make_default_field(THD *thd, Field *field_arg)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Assign a default value of a table column to the positional parameter that
|
||||
is performed on execution of a prepared statement with the clause
|
||||
'USING DEFAULT'
|
||||
|
||||
@param field a field that should be assigned an actual value of positional
|
||||
parameter passed via the clause 'USING DEFAULT'
|
||||
|
||||
@return false on success, true on failure
|
||||
*/
|
||||
|
||||
bool Item_param::assign_default(Field *field)
|
||||
{
|
||||
DBUG_ASSERT(m_associated_field);
|
||||
|
||||
if (m_associated_field->field->flags & NO_DEFAULT_VALUE_FLAG)
|
||||
{
|
||||
my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0),
|
||||
m_associated_field->field->field_name.str);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_default_field)
|
||||
{
|
||||
m_default_field= make_default_field(field->table->in_use,
|
||||
m_associated_field->field);
|
||||
|
||||
if (!m_default_field)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_default_field->default_value)
|
||||
m_default_field->set_default();
|
||||
|
||||
return field_conv(field, m_default_field);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Item_copy_string
|
||||
****************************************************************************/
|
||||
|
@ -9675,6 +9734,15 @@ Item *Item_default_value::transform(THD *thd, Item_transformer transformer,
|
|||
}
|
||||
|
||||
|
||||
bool Item_default_value::associate_with_target_field(THD *thd,
|
||||
Item_field *field)
|
||||
{
|
||||
m_associated= true;
|
||||
arg= field;
|
||||
return tie_field(thd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Call fix_fields for an item representing the default value, create
|
||||
an instance of Field for representing the default value and assign it
|
||||
|
|
40
sql/item.h
40
sql/item.h
|
@ -834,7 +834,7 @@ protected:
|
|||
const Tmp_field_param *param,
|
||||
bool is_explicit_null);
|
||||
|
||||
void raise_error_not_evaluable();
|
||||
virtual void raise_error_not_evaluable();
|
||||
void push_note_converted_to_negative_complement(THD *thd);
|
||||
void push_note_converted_to_positive_complement(THD *thd);
|
||||
|
||||
|
@ -2453,6 +2453,18 @@ public:
|
|||
Checks if this item consists in the left part of arg IN subquery predicate
|
||||
*/
|
||||
bool pushable_equality_checker_for_subquery(uchar *arg);
|
||||
|
||||
/**
|
||||
This method is to set relationship between a positional parameter
|
||||
represented by the '?' and an actual argument value passed to the
|
||||
call of PS/SP by the USING clause. The method is overridden in classes
|
||||
Item_param and Item_default_value.
|
||||
*/
|
||||
virtual bool associate_with_target_field(THD *, Item_field *)
|
||||
{
|
||||
DBUG_ASSERT(is_fixed());
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
MEM_ROOT *get_thd_memroot(THD *thd);
|
||||
|
@ -4192,6 +4204,10 @@ public:
|
|||
void sync_clones();
|
||||
bool register_clone(Item_param *i) { return m_clones.push_back(i); }
|
||||
|
||||
virtual void raise_error_not_evaluable()
|
||||
{
|
||||
invalid_default_param();
|
||||
}
|
||||
private:
|
||||
void invalid_default_param() const;
|
||||
|
||||
|
@ -4206,6 +4222,17 @@ public:
|
|||
|
||||
virtual void make_send_field(THD *thd, Send_field *field);
|
||||
|
||||
/**
|
||||
See comments on @see Item::associate_with_target_field for method
|
||||
description
|
||||
*/
|
||||
virtual bool associate_with_target_field(THD *, Item_field *field)
|
||||
{
|
||||
m_associated_field= field;
|
||||
return false;
|
||||
}
|
||||
bool assign_default(Field *field);
|
||||
|
||||
private:
|
||||
Send_field *m_out_param_info;
|
||||
bool m_is_settable_routine_parameter;
|
||||
|
@ -4215,6 +4242,8 @@ private:
|
|||
synchronize the actual value of the parameter with the values of the clones.
|
||||
*/
|
||||
Mem_root_array<Item_param *, true> m_clones;
|
||||
Item_field *m_associated_field;
|
||||
Field *m_default_field;
|
||||
};
|
||||
|
||||
|
||||
|
@ -6512,6 +6541,8 @@ public:
|
|||
class Item_default_value : public Item_field
|
||||
{
|
||||
bool vcol_assignment_ok;
|
||||
bool m_associated;
|
||||
|
||||
void calculate();
|
||||
public:
|
||||
Item *arg;
|
||||
|
@ -6519,6 +6550,7 @@ public:
|
|||
bool vcol_assignment_arg)
|
||||
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
|
||||
&null_clex_str), vcol_assignment_ok(vcol_assignment_arg),
|
||||
m_associated(false),
|
||||
arg(a) {}
|
||||
enum Type type() const { return DEFAULT_VALUE_ITEM; }
|
||||
bool eq(const Item *item, bool binary_cmp) const;
|
||||
|
@ -6581,6 +6613,12 @@ public:
|
|||
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
|
||||
const Tmp_field_param *param);
|
||||
|
||||
/**
|
||||
See comments on @see Item::associate_with_target_field for method
|
||||
description
|
||||
*/
|
||||
virtual bool associate_with_target_field(THD *thd, Item_field *field);
|
||||
|
||||
private:
|
||||
bool tie_field(THD *thd);
|
||||
};
|
||||
|
|
|
@ -8870,6 +8870,9 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
|
|||
@param values values to fill with
|
||||
@param ignore_errors TRUE if we should ignore errors
|
||||
@param use_value forces usage of value of the items instead of result
|
||||
@param check_for_computability whether to check for ability to invoke val_*()
|
||||
methods (val_int () etc) against supplied
|
||||
values
|
||||
|
||||
@details
|
||||
fill_record() may set table->auto_increment_field_not_null and a
|
||||
|
@ -8883,7 +8886,7 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
|
|||
|
||||
bool
|
||||
fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
|
||||
bool ignore_errors, bool use_value)
|
||||
bool ignore_errors, bool use_value, bool check_for_computability)
|
||||
{
|
||||
List_iterator_fast<Item> v(values);
|
||||
List<TABLE> tbl_list;
|
||||
|
@ -8921,6 +8924,10 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
|
|||
else
|
||||
value=v++;
|
||||
|
||||
if (check_for_computability &&
|
||||
value->check_is_evaluable_expression_or_error())
|
||||
goto err;
|
||||
|
||||
bool vers_sys_field= table->versioned() && field->vers_sys_field();
|
||||
|
||||
if (field->field_index == autoinc_index)
|
||||
|
@ -8995,7 +9002,7 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, Field **ptr,
|
|||
bool result;
|
||||
Table_triggers_list *triggers= table->triggers;
|
||||
|
||||
result= fill_record(thd, table, ptr, values, ignore_errors, FALSE);
|
||||
result= fill_record(thd, table, ptr, values, ignore_errors, false, false);
|
||||
|
||||
if (!result && triggers && *ptr)
|
||||
result= triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, TRUE) ||
|
||||
|
|
|
@ -184,7 +184,8 @@ void unfix_fields(List<Item> &items);
|
|||
bool fill_record(THD * thd, TABLE *table_arg, List<Item> &fields,
|
||||
List<Item> &values, bool ignore_errors, bool update);
|
||||
bool fill_record(THD *thd, TABLE *table, Field **field, List<Item> &values,
|
||||
bool ignore_errors, bool use_value);
|
||||
bool ignore_errors, bool use_value,
|
||||
bool check_for_evaluability);
|
||||
|
||||
Field *
|
||||
find_field_in_tables(THD *thd, Item_ident *item,
|
||||
|
|
|
@ -271,7 +271,8 @@ my_bool Expression_cache_tmptable::put_value(Item *value)
|
|||
}
|
||||
|
||||
*(items.head_ref())= value;
|
||||
fill_record(table_thd, cache_table, cache_table->field, items, TRUE, TRUE);
|
||||
fill_record(table_thd, cache_table, cache_table->field, items, true, true,
|
||||
true);
|
||||
if (unlikely(table_thd->is_error()))
|
||||
goto err;;
|
||||
|
||||
|
|
|
@ -12732,7 +12732,8 @@ end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||
if (item->is_null())
|
||||
DBUG_RETURN(NESTED_LOOP_OK);
|
||||
}
|
||||
fill_record(thd, table, table->field, sjm->sjm_table_cols, TRUE, FALSE);
|
||||
fill_record(thd, table, table->field, sjm->sjm_table_cols, true, false,
|
||||
true);
|
||||
if (unlikely(thd->is_error()))
|
||||
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
|
||||
if (unlikely((error= table->file->ha_write_tmp_row(table->record[0]))))
|
||||
|
|
|
@ -3066,7 +3066,7 @@ int select_result_explain_buffer::send_data(List<Item> &items)
|
|||
memory.
|
||||
*/
|
||||
set_current_thd(thd);
|
||||
fill_record(thd, dst_table, dst_table->field, items, TRUE, FALSE);
|
||||
fill_record(thd, dst_table, dst_table->field, items, true, false, false);
|
||||
res= dst_table->file->ha_write_tmp_row(dst_table->record[0]);
|
||||
set_current_thd(cur_thd);
|
||||
DBUG_RETURN(MY_TEST(res));
|
||||
|
|
|
@ -122,11 +122,11 @@ int select_unit::send_data(List<Item> &values)
|
|||
table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
|
||||
if (intersect_mark)
|
||||
{
|
||||
fill_record(thd, table, table->field + 1, values, TRUE, FALSE);
|
||||
fill_record(thd, table, table->field + 1, values, true, false, true);
|
||||
table->field[0]->store((ulonglong) curr_step, 1);
|
||||
}
|
||||
else
|
||||
fill_record(thd, table, table->field, values, TRUE, FALSE);
|
||||
fill_record(thd, table, table->field, values, true, false, true);
|
||||
if (unlikely(thd->is_error()))
|
||||
{
|
||||
rc= 1;
|
||||
|
@ -562,7 +562,7 @@ int select_union_direct::send_data(List<Item> &items)
|
|||
send_records++;
|
||||
}
|
||||
|
||||
fill_record(thd, table, table->field, items, true, false);
|
||||
fill_record(thd, table, table->field, items, true, false, true);
|
||||
if (unlikely(thd->is_error()))
|
||||
return true; /* purecov: inspected */
|
||||
|
||||
|
|
|
@ -2160,6 +2160,10 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||
{
|
||||
Item *value= value_it++;
|
||||
uint offset= item->field->table->pos_in_table_list->shared;
|
||||
|
||||
if (value->associate_with_target_field(thd, item))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
fields_for_table[offset]->push_back(item, thd->mem_root);
|
||||
values_for_table[offset]->push_back(value, thd->mem_root);
|
||||
}
|
||||
|
@ -2658,7 +2662,7 @@ int multi_update::send_data(List<Item> ¬_used_values)
|
|||
tmp_table_param[offset].func_count);
|
||||
fill_record(thd, tmp_table,
|
||||
tmp_table->field + 1 + unupdated_check_opt_tables.elements,
|
||||
*values_for_table[offset], TRUE, FALSE);
|
||||
*values_for_table[offset], true, false, false);
|
||||
|
||||
/* Write row, ignoring duplicated updates to a row */
|
||||
error= tmp_table->file->ha_write_tmp_row(tmp_table->record[0]);
|
||||
|
|
|
@ -649,7 +649,15 @@ static bool pack_vcols(THD *thd, String *buf, List<Create_field> &create_fields,
|
|||
? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL))
|
||||
return 1;
|
||||
if (field->has_default_expression() && !field->has_default_now_unireg_check())
|
||||
if (pack_expression(buf, field->default_value, field_nr, VCOL_DEFAULT))
|
||||
if (pack_expression(buf, field->default_value, field_nr, VCOL_DEFAULT) ||
|
||||
/*
|
||||
field->has_default_expression() can return error (e.g. because
|
||||
the method Item_param::basic_const_item invokes
|
||||
invalid_default_param()
|
||||
in case either DEFAULT_VALUE or IGNORE_VALUE is handled).
|
||||
Take this fact into account and return error in this case.
|
||||
*/
|
||||
thd->is_error())
|
||||
return 1;
|
||||
if (field->check_constraint)
|
||||
if (pack_expression(buf, field->check_constraint, field_nr,
|
||||
|
|
Loading…
Reference in a new issue