Skip to content

Commit c47e4aa

Browse files
committed
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().
1 parent 6a89f34 commit c47e4aa

File tree

11 files changed

+111
-10
lines changed

11 files changed

+111
-10
lines changed

mysql-test/r/default.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3089,8 +3089,8 @@ DROP TABLE t1;
30893089
#
30903090
# Collations
30913091
#
3092-
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin;
3093-
ERROR 22007: Encountered illegal value '�' when converting to koi8r
3092+
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin;
3093+
ERROR 22007: Encountered illegal value '�' when converting to koi8r
30943094
CREATE OR REPLACE TABLE t1 (a char(2) default concat('A') COLLATE utf8mb4_unicode_ci);
30953095
SHOW CREATE TABLE t1;
30963096
Table Create Table

mysql-test/suite/gcol/inc/gcol_ins_upd.inc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,3 +660,25 @@ INSERT IGNORE INTO t1 SELECT * FROM t1;
660660
DROP TABLE t1;
661661

662662
}
663+
664+
--echo #
665+
--echo # MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
666+
--echo #
667+
668+
CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
669+
INSERT INTO t1 VALUES (1,1,1);
670+
UPDATE t1 SET b=DEFAULT;
671+
SELECT * from t1;
672+
673+
REPLACE t1 VALUES(1,1,1);
674+
INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
675+
SELECT * from t1;
676+
677+
REPLACE t1 VALUES(1,1,1);
678+
CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
679+
INSERT INTO t2 VALUES (5,5,5);
680+
UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
681+
SELECT * from t1, t2;
682+
683+
DROP TABLE t1, t2;
684+

mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,28 @@ Warnings:
791791
Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored
792792
Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored
793793
DROP TABLE t1;
794+
#
795+
# MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
796+
#
797+
CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
798+
INSERT INTO t1 VALUES (1,1,1);
799+
UPDATE t1 SET b=DEFAULT;
800+
SELECT * from t1;
801+
a b c
802+
1 2 1
803+
REPLACE t1 VALUES(1,1,1);
804+
INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
805+
SELECT * from t1;
806+
a b c
807+
1 2 1
808+
REPLACE t1 VALUES(1,1,1);
809+
CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
810+
INSERT INTO t2 VALUES (5,5,5);
811+
UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
812+
SELECT * from t1, t2;
813+
a b c a b c
814+
1 2 1 5 6 5
815+
DROP TABLE t1, t2;
794816
DROP VIEW IF EXISTS v1,v2;
795817
DROP TABLE IF EXISTS t1,t2,t3;
796818
DROP PROCEDURE IF EXISTS p1;

mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,28 @@ Warnings:
713713
Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored
714714
Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored
715715
DROP TABLE t1;
716+
#
717+
# MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
718+
#
719+
CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
720+
INSERT INTO t1 VALUES (1,1,1);
721+
UPDATE t1 SET b=DEFAULT;
722+
SELECT * from t1;
723+
a b c
724+
1 2 1
725+
REPLACE t1 VALUES(1,1,1);
726+
INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
727+
SELECT * from t1;
728+
a b c
729+
1 2 1
730+
REPLACE t1 VALUES(1,1,1);
731+
CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
732+
INSERT INTO t2 VALUES (5,5,5);
733+
UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
734+
SELECT * from t1, t2;
735+
a b c a b c
736+
1 2 1 5 6 5
737+
DROP TABLE t1, t2;
716738
DROP VIEW IF EXISTS v1,v2;
717739
DROP TABLE IF EXISTS t1,t2,t3;
718740
DROP PROCEDURE IF EXISTS p1;

mysql-test/t/default.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1855,7 +1855,7 @@ DROP TABLE t1;
18551855
--echo #
18561856

18571857
--error ER_BAD_DATA
1858-
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin;
1858+
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin;
18591859
CREATE OR REPLACE TABLE t1 (a char(2) default concat('A') COLLATE utf8mb4_unicode_ci);
18601860
SHOW CREATE TABLE t1;
18611861
DROP TABLE t1;

sql/item.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9003,6 +9003,12 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
90039003
return TRUE;
90049004
}
90059005

9006+
bool Item_default_value::enchant_default_with_arg_processor(void *proc_arg)
9007+
{
9008+
if (!arg) arg= (Item *)proc_arg;
9009+
return 0;
9010+
}
9011+
90069012
void Item_default_value::cleanup()
90079013
{
90089014
delete cached_field; // Free cached blob data

sql/item.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,7 @@ class Item: public Value_source,
17131713
virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; }
17141714
virtual bool exists2in_processor(void *arg) { return 0; }
17151715
virtual bool find_selective_predicates_list_processor(void *arg) { return 0; }
1716+
virtual bool enchant_default_with_arg_processor(void *arg) { return 0; }
17161717
bool cleanup_is_expensive_cache_processor(void *arg)
17171718
{
17181719
is_expensive_cache= (int8)(-1);
@@ -5449,23 +5450,24 @@ class Cached_item_field :public Cached_item
54495450
class Item_default_value : public Item_field
54505451
{
54515452
void calculate();
5453+
protected:
5454+
Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
5455+
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
5456+
(const char *)NULL),
5457+
arg(a), cached_field(NULL) {}
54525458
public:
54535459
Item *arg;
54545460
Field *cached_field;
54555461
Item_default_value(THD *thd, Name_resolution_context *context_arg)
54565462
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
54575463
(const char *)NULL),
54585464
arg(NULL), cached_field(NULL) {}
5459-
Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
5460-
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
5461-
(const char *)NULL),
5462-
arg(a), cached_field(NULL) {}
54635465
Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a)
54645466
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
54655467
(const char *)NULL),
54665468
arg(NULL),cached_field(NULL) {}
54675469
enum Type type() const { return DEFAULT_VALUE_ITEM; }
5468-
bool vcol_assignment_allowed_value() const { return arg == NULL; }
5470+
bool vcol_assignment_allowed_value() const { return true; }
54695471
bool eq(const Item *item, bool binary_cmp) const;
54705472
bool fix_fields(THD *, Item **);
54715473
void cleanup();
@@ -5495,6 +5497,7 @@ class Item_default_value : public Item_field
54955497
Item_field *field_for_view_update() { return 0; }
54965498
bool update_vcol_processor(void *arg) { return 0; }
54975499
bool check_func_default_processor(void *arg) { return true; }
5500+
bool enchant_default_with_arg_processor(void *arg);
54985501

54995502
bool walk(Item_processor processor, bool walk_subquery, void *args)
55005503
{
@@ -5505,6 +5508,15 @@ class Item_default_value : public Item_field
55055508
Item *transform(THD *thd, Item_transformer transformer, uchar *args);
55065509
};
55075510

5511+
class Item_default_value_arg: public Item_default_value
5512+
{
5513+
public:
5514+
Item_default_value_arg(THD *thd, Name_resolution_context *context, Item *a)
5515+
:Item_default_value(thd, context, a) {}
5516+
5517+
bool vcol_assignment_allowed_value() const { return arg == NULL; }
5518+
};
5519+
55085520
/**
55095521
This class is used as bulk parameter INGNORE representation.
55105522

sql/sql_base.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7193,6 +7193,18 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
71937193
DBUG_RETURN(0);
71947194
}
71957195

7196+
/** Transforms b= F(DEFAULT) -> b= F(DEFAULT(b)) */
7197+
void setup_defaults(THD *thd, List<Item> &fields, List<Item> &values)
7198+
{
7199+
List_iterator<Item> fit(fields);
7200+
List_iterator<Item> vit(values);
7201+
7202+
for (Item *value= vit++, *f_item= fit++; value; value= vit++, f_item= fit++)
7203+
{
7204+
value->walk(&Item::enchant_default_with_arg_processor, false, f_item);
7205+
}
7206+
}
7207+
71967208
/****************************************************************************
71977209
** Check that all given fields exists and fill struct with current data
71987210
****************************************************************************/

sql/sql_base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
172172
List<Item> &item, enum_mark_columns mark_used_columns,
173173
List<Item> *sum_func_list, List<Item> *pre_fix,
174174
bool allow_sum_func);
175+
void setup_defaults(THD *thd, List<Item> &fields, List<Item> &values);
175176
void unfix_fields(List<Item> &items);
176177
bool fill_record(THD * thd, TABLE *table_arg, List<Item> &fields,
177178
List<Item> &values, bool ignore_errors, bool update);

sql/sql_update.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@ int mysql_update(THD *thd,
370370
DBUG_RETURN(1);
371371
}
372372

373+
setup_defaults(thd, fields, values);
374+
373375
#ifndef NO_EMBEDDED_ACCESS_CHECKS
374376
/* Check values */
375377
table_list->grant.want_privilege= table->grant.want_privilege=
@@ -1749,6 +1751,8 @@ int multi_update::prepare(List<Item> &not_used_values,
17491751
}
17501752
}
17511753

1754+
setup_defaults(thd, *fields, *values);
1755+
17521756
/*
17531757
We have to check values after setup_tables to get covering_keys right in
17541758
reference tables

0 commit comments

Comments
 (0)