From f5460983d3cd415796ebae3ec2b2622bb0178a53 Mon Sep 17 00:00:00 2001 From: Brandon Nesterenko Date: Fri, 6 Feb 2026 11:22:33 -0700 Subject: [PATCH] MDEV-38726 Assertion `table->default_field != dfield_ptr' failed in bool parse_vcol_defs(THD *, MEM_ROOT *, TABLE *, bool *, vcol_init_mode) A new assertion added by MDEV-36290 is correct in trying to identify default_fields that weren't correctly accounted in parse_vcol_defs. It caught a case for INSERT DELAYED on tables using TIMESTAMP and DATETIME types with ON UPDATE default values. That is, the insert delayed logic opens the table in one thread, and then copies the field info to another table in the user thread. This copy loses most flag metadata for these fields though. In this case, the flag ON_UPDATE_NOW_FLAG was dropped, and the parse_col_defs() logic was unable to properly account for that default field, and the assertion fired. This patch fixes this by restoring the ON_UPDATE_NOW_FLAG during the field copy. Also, a comment is added to Field::make_new_field() to explain the state of the returned field. Reviewed-by: Monty Signed-off-by: Brandon Nesterenko --- mysql-test/main/delayed.result | 8 ++++++++ mysql-test/main/delayed.test | 10 ++++++++++ sql/field.h | 8 ++++++++ sql/sql_insert.cc | 10 +++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/delayed.result b/mysql-test/main/delayed.result index 73e1ed40c6a..30d8fe99ccd 100644 --- a/mysql-test/main/delayed.result +++ b/mysql-test/main/delayed.result @@ -420,3 +420,11 @@ CREATE TABLE t1 (c0 INT,UNIQUE (c0) USING HASH) ENGINE=MYISAM; INSERT DELAYED INTO t1 VALUES (0); INSERT DELAYED INTO t1 VALUES (0); DROP TABLE t1; +# +# MDEV-38726: Assertion `table->default_field != dfield_ptr' failed in +# bool parse_vcol_defs(THD *, MEM_ROOT *, TABLE *, bool *, +# vcol_init_mode) +# +CREATE TABLE t_38726 (a TIMESTAMP ON UPDATE CURRENT_TIMESTAMP()) ENGINE=MYISAM; +INSERT DELAYED INTO t_38726 VALUES (); +DROP TABLE t_38726; diff --git a/mysql-test/main/delayed.test b/mysql-test/main/delayed.test index 0ed009825f7..a578a76dbd4 100644 --- a/mysql-test/main/delayed.test +++ b/mysql-test/main/delayed.test @@ -632,3 +632,13 @@ INSERT DELAYED INTO t1 VALUES (0); DROP TABLE t1; --enable_view_protocol + +--echo # +--echo # MDEV-38726: Assertion `table->default_field != dfield_ptr' failed in +--echo # bool parse_vcol_defs(THD *, MEM_ROOT *, TABLE *, bool *, +--echo # vcol_init_mode) +--echo # + +CREATE TABLE t_38726 (a TIMESTAMP ON UPDATE CURRENT_TIMESTAMP()) ENGINE=MYISAM; +INSERT DELAYED INTO t_38726 VALUES (); +DROP TABLE t_38726; diff --git a/sql/field.h b/sql/field.h index 7c8ebd67b26..cada0e2ceb3 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1608,6 +1608,14 @@ public: virtual void sort_string(uchar *buff,uint length)=0; virtual bool optimize_range(uint idx, uint part) const; virtual void free() {} + + /* + Creates a copy of this field which can be added to any table, and the + returned field is reset to a state respective of this. That is, any + information which is dependent on the original table is dropped (e.g. key + info, auto increment, etc). The information that is retained is that which + defines how to store, retrieve, or compare the field. + */ virtual Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 64a57f2f111..ea23c19d0bf 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3132,7 +3132,15 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) (*field)->invisible= (*org_field)->invisible; (*field)->orig_table= copy; // Remove connection (*field)->move_field_offset(adjust_ptrs); // Point at copy->record[0] - (*field)->flags|= ((*org_field)->flags & LONG_UNIQUE_HASH_FIELD); + + /* + The Field* produced by Field::make_new_field is reset to a barebones + state. Flags that are dependent on the original table need to be + restored. + */ + (*field)->flags|= + ((*org_field)->flags & (LONG_UNIQUE_HASH_FIELD | ON_UPDATE_NOW_FLAG)); + (*field)->invisible= (*org_field)->invisible; if (memdup_vcol(client_thd, (*field)->vcol_info)) goto error;