Commit c47e4aab authored by Nikita Malyavin's avatar Nikita Malyavin

MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT

The columns that are part of DEFAULT expression were not read-marked
in statements like UPDATE...SET b=DEFAULT.

The problem is `F(DEFAULT)` expression depends of the left-hand side of an
assignment. However, setup_fields accepts only right-hand side value.
Neither Item::fix_fields does.

Suchwise, b=DEFAULT(b) works fine, because Item_default_field has
information on what field it is default of:
    if (thd->mark_used_columns != MARK_COLUMNS_NONE)
      def_field->default_value->expr->update_used_tables();

in Item_default_value::fix_fields().

It is not reasonable to pass a left-hand side to Item:fix_fields, because
the case is rare, so the rewrite
  b= F(DEFAULT)  ->  b= F(DEFAULT(b))

is made instead.

Both UPDATE and multi-UPDATE are affected, however any form of INSERT
is not: it marks all the fields in DEFAULT expressions for read in
TABLE::mark_default_fields_for_write().
parent 6a89f346
......@@ -3089,8 +3089,8 @@ DROP TABLE t1;
#
# Collations
#
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('')) CHARACTER SET koi8r COLLATE koi8r_bin;
ERROR 22007: Encountered illegal value '' when converting to koi8r
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('')) CHARACTER SET koi8r COLLATE koi8r_bin;
ERROR 22007: Encountered illegal value '' when converting to koi8r
CREATE OR REPLACE TABLE t1 (a char(2) default concat('A') COLLATE utf8mb4_unicode_ci);
SHOW CREATE TABLE t1;
Table Create Table
......
......@@ -660,3 +660,25 @@ INSERT IGNORE INTO t1 SELECT * FROM t1;
DROP TABLE t1;
}
--echo #
--echo # MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
--echo #
CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
INSERT INTO t1 VALUES (1,1,1);
UPDATE t1 SET b=DEFAULT;
SELECT * from t1;
REPLACE t1 VALUES(1,1,1);
INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
SELECT * from t1;
REPLACE t1 VALUES(1,1,1);
CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
INSERT INTO t2 VALUES (5,5,5);
UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
SELECT * from t1, t2;
DROP TABLE t1, t2;
......@@ -791,6 +791,28 @@ Warnings:
Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored
Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored
DROP TABLE t1;
#
# MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
#
CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
INSERT INTO t1 VALUES (1,1,1);
UPDATE t1 SET b=DEFAULT;
SELECT * from t1;
a b c
1 2 1
REPLACE t1 VALUES(1,1,1);
INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
SELECT * from t1;
a b c
1 2 1
REPLACE t1 VALUES(1,1,1);
CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
INSERT INTO t2 VALUES (5,5,5);
UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
SELECT * from t1, t2;
a b c a b c
1 2 1 5 6 5
DROP TABLE t1, t2;
DROP VIEW IF EXISTS v1,v2;
DROP TABLE IF EXISTS t1,t2,t3;
DROP PROCEDURE IF EXISTS p1;
......
......@@ -713,6 +713,28 @@ Warnings:
Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored
Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored
DROP TABLE t1;
#
# MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
#
CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
INSERT INTO t1 VALUES (1,1,1);
UPDATE t1 SET b=DEFAULT;
SELECT * from t1;
a b c
1 2 1
REPLACE t1 VALUES(1,1,1);
INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
SELECT * from t1;
a b c
1 2 1
REPLACE t1 VALUES(1,1,1);
CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
INSERT INTO t2 VALUES (5,5,5);
UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
SELECT * from t1, t2;
a b c a b c
1 2 1 5 6 5
DROP TABLE t1, t2;
DROP VIEW IF EXISTS v1,v2;
DROP TABLE IF EXISTS t1,t2,t3;
DROP PROCEDURE IF EXISTS p1;
......
......@@ -1855,7 +1855,7 @@ DROP TABLE t1;
--echo #
--error ER_BAD_DATA
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('')) CHARACTER SET koi8r COLLATE koi8r_bin;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin;
CREATE OR REPLACE TABLE t1 (a char(2) default concat('A') COLLATE utf8mb4_unicode_ci);
SHOW CREATE TABLE t1;
DROP TABLE t1;
......
......@@ -9003,6 +9003,12 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
return TRUE;
}
bool Item_default_value::enchant_default_with_arg_processor(void *proc_arg)
{
if (!arg) arg= (Item *)proc_arg;
return 0;
}
void Item_default_value::cleanup()
{
delete cached_field; // Free cached blob data
......
......@@ -1713,6 +1713,7 @@ class Item: public Value_source,
virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; }
virtual bool exists2in_processor(void *arg) { return 0; }
virtual bool find_selective_predicates_list_processor(void *arg) { return 0; }
virtual bool enchant_default_with_arg_processor(void *arg) { return 0; }
bool cleanup_is_expensive_cache_processor(void *arg)
{
is_expensive_cache= (int8)(-1);
......@@ -5449,6 +5450,11 @@ class Cached_item_field :public Cached_item
class Item_default_value : public Item_field
{
void calculate();
protected:
Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
(const char *)NULL),
arg(a), cached_field(NULL) {}
public:
Item *arg;
Field *cached_field;
......@@ -5456,16 +5462,12 @@ class Item_default_value : public Item_field
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
(const char *)NULL),
arg(NULL), cached_field(NULL) {}
Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
(const char *)NULL),
arg(a), cached_field(NULL) {}
Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a)
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
(const char *)NULL),
arg(NULL),cached_field(NULL) {}
enum Type type() const { return DEFAULT_VALUE_ITEM; }
bool vcol_assignment_allowed_value() const { return arg == NULL; }
bool vcol_assignment_allowed_value() const { return true; }
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
void cleanup();
......@@ -5495,6 +5497,7 @@ class Item_default_value : public Item_field
Item_field *field_for_view_update() { return 0; }
bool update_vcol_processor(void *arg) { return 0; }
bool check_func_default_processor(void *arg) { return true; }
bool enchant_default_with_arg_processor(void *arg);
bool walk(Item_processor processor, bool walk_subquery, void *args)
{
......@@ -5505,6 +5508,15 @@ class Item_default_value : public Item_field
Item *transform(THD *thd, Item_transformer transformer, uchar *args);
};
class Item_default_value_arg: public Item_default_value
{
public:
Item_default_value_arg(THD *thd, Name_resolution_context *context, Item *a)
:Item_default_value(thd, context, a) {}
bool vcol_assignment_allowed_value() const { return arg == NULL; }
};
/**
This class is used as bulk parameter INGNORE representation.
......
......@@ -7193,6 +7193,18 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
DBUG_RETURN(0);
}
/** Transforms b= F(DEFAULT) -> b= F(DEFAULT(b)) */
void setup_defaults(THD *thd, List<Item> &fields, List<Item> &values)
{
List_iterator<Item> fit(fields);
List_iterator<Item> vit(values);
for (Item *value= vit++, *f_item= fit++; value; value= vit++, f_item= fit++)
{
value->walk(&Item::enchant_default_with_arg_processor, false, f_item);
}
}
/****************************************************************************
** Check that all given fields exists and fill struct with current data
****************************************************************************/
......
......@@ -172,6 +172,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &item, enum_mark_columns mark_used_columns,
List<Item> *sum_func_list, List<Item> *pre_fix,
bool allow_sum_func);
void setup_defaults(THD *thd, List<Item> &fields, List<Item> &values);
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);
......
......@@ -370,6 +370,8 @@ int mysql_update(THD *thd,
DBUG_RETURN(1);
}
setup_defaults(thd, fields, values);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Check values */
table_list->grant.want_privilege= table->grant.want_privilege=
......@@ -1749,6 +1751,8 @@ int multi_update::prepare(List<Item> &not_used_values,
}
}
setup_defaults(thd, *fields, *values);
/*
We have to check values after setup_tables to get covering_keys right in
reference tables
......
......@@ -9466,8 +9466,8 @@ column_default_non_parenthesized_expr:
Item_splocal *il= $3->get_item_splocal();
if (il)
my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str));
$$= new (thd->mem_root) Item_default_value(thd, Lex->current_context(),
$3);
$$= new (thd->mem_root) Item_default_value_arg(thd, Lex->current_context(),
$3);
if ($$ == NULL)
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