diff options
author | Aleksey Midenkov <midenok@gmail.com> | 2022-04-18 12:44:27 +0300 |
---|---|---|
committer | Aleksey Midenkov <midenok@gmail.com> | 2022-04-18 12:44:27 +0300 |
commit | 08c7ab404f69d9c4ca6ca7a9cf7eec74c804f917 (patch) | |
tree | 6e2009151bc6fb68dd4ebb1632f5d7fd09e5a919 | |
parent | c02ebf3510850ba78a106be9974c94c3b97d8585 (diff) | |
download | mariadb-git-08c7ab404f69d9c4ca6ca7a9cf7eec74c804f917.tar.gz |
MDEV-24176 Server crashes after insert in the table with virtual
column generated using date_format() and if()
vcol_info->expr is allocated on expr_arena at parsing stage. Since
expr item is allocated on expr_arena all its containee items must be
allocated on expr_arena too. Otherwise fix_session_expr() will
encounter prematurely freed item.
When table is reopened from cache vcol_info contains stale
expression. We refresh expression via TABLE::vcol_fix_exprs() but
first we must prepare a proper context (Vcol_expr_context) which meets
some requirements:
1. As noted above expr update must be done on expr_arena as there may
be new items created. It was a bug in fix_session_expr_for_read() and
was just not reproduced because of no second refix. Now refix is done
for more cases so it does reproduce. Tests affected: vcol.binlog
2. Also name resolution context must be narrowed to the single table.
Tested by: vcol.update main.default vcol.vcol_syntax gcol.gcol_bugfixes
3. sql_mode must be clean and not fail expr update.
sql_mode such as MODE_NO_BACKSLASH_ESCAPES, MODE_NO_ZERO_IN_DATE, etc
must not affect vcol expression update. If the table was created
successfully any further evaluation must not fail. Tests affected:
main.func_like
Reviewed by: Sergei Golubchik <serg@mariadb.org>
-rw-r--r-- | mysql-test/suite/vcol/r/vcol_syntax.result | 93 | ||||
-rw-r--r-- | mysql-test/suite/vcol/t/vcol_syntax.test | 83 | ||||
-rw-r--r-- | sql/event_db_repository.cc | 2 | ||||
-rw-r--r-- | sql/field.cc | 5 | ||||
-rw-r--r-- | sql/field.h | 6 | ||||
-rw-r--r-- | sql/item.cc | 10 | ||||
-rw-r--r-- | sql/item.h | 6 | ||||
-rw-r--r-- | sql/sql_base.cc | 48 | ||||
-rw-r--r-- | sql/table.cc | 165 | ||||
-rw-r--r-- | sql/table.h | 11 |
10 files changed, 342 insertions, 87 deletions
diff --git a/mysql-test/suite/vcol/r/vcol_syntax.result b/mysql-test/suite/vcol/r/vcol_syntax.result index 0063f38ea36..5e7ebcda287 100644 --- a/mysql-test/suite/vcol/r/vcol_syntax.result +++ b/mysql-test/suite/vcol/r/vcol_syntax.result @@ -94,6 +94,97 @@ create table t1 (a int, v_a int generated always as (a)); update t1 as x set a = 1; alter table t1 force; drop table t1; +create table t1 ( +id int not null auto_increment primary key, +order_date_time datetime not null, +order_date date generated always as (convert(order_date_time, date)), +language_id binary(16) null +); +update t1 as tx set order_date= null; +alter table t1 modify column language_id binary(16) not null; +drop table t1; # -# End of 10.2 tests +# MDEV-24176 Server crashes after insert in the table with virtual column generated using date_format() and if() # +create table t1 (d1 date not null, d2 date not null, +gd text as (concat(d1,if(d1 <> d2, date_format(d2, 'to %y-%m-%d '), ''))) ); +insert into t1(d1,d2) values +('2020-09-01','2020-09-01'),('2020-05-01','2020-09-01'); +select * from t1; +d1 d2 gd +2020-09-01 2020-09-01 2020-09-01 +2020-05-01 2020-09-01 2020-05-01to 20-09-01 +drop table t1; +# MDEV-25772 (duplicate) and LOCK TABLES case +create table t1 (d1 datetime , v_d1 tinyint(1) as (d1 < curdate())); +insert into t1 (d1) values ('2021-09-11 08:38:23'), ('2021-09-01 08:38:23'); +lock tables t1 write; +select * from t1 where v_d1=1; +d1 v_d1 +2021-09-11 08:38:23 1 +2021-09-01 08:38:23 1 +select * from t1; +d1 v_d1 +2021-09-11 08:38:23 1 +2021-09-01 08:38:23 1 +unlock tables; +drop table t1; +# MDEV-26432 (duplicate) +create table t1 (v2 int, v1 int as ((user() like 'x'))) ; +select 1 from t1 where v1=1 ; +1 +select * from t1; +v2 v1 +drop table t1; +create table t1 (v2 int as ( user () like 'x')); +select 1 from t1 order by v2 ; +1 +alter table t1 add i int; +drop table t1; +# MDEV-26437 (duplicate) +create table v0 (v2 int not null, +v1 bigint as (case 'x' when current_user() then v2 end)); +select v2 as v3 from v0 where v1 like 'x' escape 'x'; +v3 +insert into v0 (v2) values (-128); +drop table v0; +create table t1 (vi int as (case 'x' when current_user() then 1 end)); +select 1 from t1 where vi=1; +1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `vi` int(11) GENERATED ALWAYS AS (case 'x' when current_user() then 1 end) VIRTUAL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (vi int as (case 'x' when current_user() then 1 end)); +select 1 from t1 where vi=1; +1 +select 1 from t1 where vi=1; +1 +drop table t1; +# MDEV-28092 (duplicate) +create table t1 (b timestamp, a int as (1 in (dayofmonth (b between 'x' and current_user) = b))); +insert into t1(b) values ('2022-03-17 14:55:37'); +select 1 from t1 x natural join t1; +1 +1 +Warnings: +Warning 1292 Incorrect datetime value: 'x' +Warning 1292 Incorrect datetime value: 'root@localhost' +Warning 1292 Incorrect datetime value: 'x' +Warning 1292 Incorrect datetime value: 'root@localhost' +drop table t1; +# MDEV-28089 (duplicate) +create table t1 (a int , b date as (1 in ('x' ,(database () = 'x' is null) ))) ; +select b from t1; +b +select a from t1 order by 'x' = b; +a +drop table t1; +create table t1 (a int , b date as (1 in ('x' ,(database ()) ))) ; +select b from t1; +b +select a from t1 order by 'x' = b; +a +drop table t1; diff --git a/mysql-test/suite/vcol/t/vcol_syntax.test b/mysql-test/suite/vcol/t/vcol_syntax.test index 3c8a50a7f36..198d61a13aa 100644 --- a/mysql-test/suite/vcol/t/vcol_syntax.test +++ b/mysql-test/suite/vcol/t/vcol_syntax.test @@ -77,7 +77,88 @@ update t1 as x set a = 1; alter table t1 force; drop table t1; +create table t1 ( + id int not null auto_increment primary key, + order_date_time datetime not null, + order_date date generated always as (convert(order_date_time, date)), + language_id binary(16) null +); + +update t1 as tx set order_date= null; +alter table t1 modify column language_id binary(16) not null; +# Cleanup +drop table t1; --echo # ---echo # End of 10.2 tests +--echo # MDEV-24176 Server crashes after insert in the table with virtual column generated using date_format() and if() --echo # +create table t1 (d1 date not null, d2 date not null, + gd text as (concat(d1,if(d1 <> d2, date_format(d2, 'to %y-%m-%d '), ''))) ); + +insert into t1(d1,d2) values + ('2020-09-01','2020-09-01'),('2020-05-01','2020-09-01'); +select * from t1; + +drop table t1; + +--echo # MDEV-25772 (duplicate) and LOCK TABLES case +create table t1 (d1 datetime , v_d1 tinyint(1) as (d1 < curdate())); +insert into t1 (d1) values ('2021-09-11 08:38:23'), ('2021-09-01 08:38:23'); + +lock tables t1 write; +select * from t1 where v_d1=1; +select * from t1; +unlock tables; + +drop table t1; + +--echo # MDEV-26432 (duplicate) +create table t1 (v2 int, v1 int as ((user() like 'x'))) ; +select 1 from t1 where v1=1 ; +select * from t1; + +drop table t1; + +create table t1 (v2 int as ( user () like 'x')); +select 1 from t1 order by v2 ; +alter table t1 add i int; +drop table t1; + +--echo # MDEV-26437 (duplicate) +create table v0 (v2 int not null, + v1 bigint as (case 'x' when current_user() then v2 end)); + +select v2 as v3 from v0 where v1 like 'x' escape 'x'; +insert into v0 (v2) values (-128); + +drop table v0; + +create table t1 (vi int as (case 'x' when current_user() then 1 end)); +select 1 from t1 where vi=1; +show create table t1; + +drop table t1; + +create table t1 (vi int as (case 'x' when current_user() then 1 end)); +select 1 from t1 where vi=1; +select 1 from t1 where vi=1; + +drop table t1; + +--echo # MDEV-28092 (duplicate) +create table t1 (b timestamp, a int as (1 in (dayofmonth (b between 'x' and current_user) = b))); +insert into t1(b) values ('2022-03-17 14:55:37'); + +select 1 from t1 x natural join t1; +drop table t1; + +--echo # MDEV-28089 (duplicate) +create table t1 (a int , b date as (1 in ('x' ,(database () = 'x' is null) ))) ; +select b from t1; +select a from t1 order by 'x' = b; +drop table t1; + +create table t1 (a int , b date as (1 in ('x' ,(database ()) ))) ; +select b from t1; +select a from t1 order by 'x' = b; +drop table t1; diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 399a19b4112..fe2214a2210 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -610,6 +610,8 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type, *table= tables.table; tables.table->use_all_columns(); + /* NOTE: &tables pointer will be invalid after return */ + tables.table->pos_in_table_list= NULL; if (table_intact.check(*table, &event_table_def)) { diff --git a/sql/field.cc b/sql/field.cc index f18fb25ebe3..be9c10a3bae 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2416,6 +2416,11 @@ int Field::set_default() if (default_value) { Query_arena backup_arena; + /* + TODO: this may impose memory leak until table flush. + See comment in + TABLE::update_virtual_fields(handler *, enum_vcol_update_mode). + */ table->in_use->set_n_backup_active_arena(table->expr_arena, &backup_arena); int rc= default_value->expr->save_in_field(this, 0); table->in_use->restore_active_arena(table->expr_arena, &backup_arena); diff --git a/sql/field.h b/sql/field.h index b4ea6da01a7..41bed111f50 100644 --- a/sql/field.h +++ b/sql/field.h @@ -616,9 +616,13 @@ public: { in_partitioning_expr= TRUE; } + bool need_refix() const + { + return flags & VCOL_SESSION_FUNC; + } bool fix_expr(THD *thd); bool fix_session_expr(THD *thd); - bool fix_session_expr_for_read(THD *thd, Field *field); + bool cleanup_session_expr(); bool fix_and_check_expr(THD *thd, TABLE *table); inline bool is_equal(const Virtual_column_info* vcol) const; inline void print(String*); diff --git a/sql/item.cc b/sql/item.cc index 860d2e4a554..da4b67d576d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -835,7 +835,6 @@ bool Item_ident::remove_dependence_processor(void * arg) DBUG_RETURN(0); } - bool Item_ident::collect_outer_ref_processor(void *param) { Collect_deps_prm *prm= (Collect_deps_prm *)param; @@ -6376,9 +6375,6 @@ bool Item_field::fix_fields(THD *thd, Item **reference) } #endif fixed= 1; - if (field->vcol_info && - field->vcol_info->fix_session_expr_for_read(thd, field)) - goto error; if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !outer_fixed && !thd->lex->in_sum_func && select && @@ -9500,12 +9496,6 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length()); if (!newptr) goto error; - /* - Even if DEFAULT() do not read tables fields, the default value - expression can do it. - */ - if (def_field->default_value->fix_session_expr_for_read(thd, def_field)) - goto error; if (should_mark_column(thd->column_usage)) def_field->default_value->expr->update_used_tables(); def_field->move_field(newptr+1, def_field->maybe_null() ? newptr : 0, 1); diff --git a/sql/item.h b/sql/item.h index ba2ddf299fc..d6a15f2ffbd 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2925,10 +2925,8 @@ public: const char *table_name; LEX_CSTRING field_name; /* - NOTE: came from TABLE::alias_name_used and this is only a hint! It works - only in need_correct_ident() condition. On other cases it is FALSE even if - table_name is alias! It cannot be TRUE in these cases, lots of spaghetti - logic depends on that. + NOTE: came from TABLE::alias_name_used and this is only a hint! + See comment for TABLE::alias_name_used. */ bool alias_name_used; /* true if item was resolved against alias */ /* diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b16461ac436..dc41d7faa18 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -749,6 +749,8 @@ void close_thread_tables(THD *thd) /* Table might be in use by some outer statement. */ DBUG_PRINT("tcache", ("table: '%s' query_id: %lu", table->s->table_name.str, (ulong) table->query_id)); + if (thd->locked_tables_mode) + table->vcol_cleanup_expr(thd); if (thd->locked_tables_mode <= LTM_LOCK_TABLES || table->query_id == thd->query_id) { @@ -884,6 +886,8 @@ void close_thread_table(THD *thd, TABLE **table_ptr) table->s->db.str, table->s->table_name.str, MDL_SHARED)); + + table->vcol_cleanup_expr(thd); table->mdl_ticket= NULL; if (table->file) @@ -1610,6 +1614,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) MDL_ticket *mdl_ticket; TABLE_SHARE *share; uint gts_flags; + bool from_share= false; #ifdef WITH_PARTITION_STORAGE_ENGINE int part_names_error=0; #endif @@ -2021,6 +2026,7 @@ retry_share: /* Add table to the share's used tables list. */ tc_add_table(thd, table); + from_share= true; } table->mdl_ticket= mdl_ticket; @@ -2040,7 +2046,7 @@ retry_share: table_list->updatable= 1; // It is not derived table nor non-updatable VIEW table_list->table= table; - if (table->vcol_fix_exprs(thd)) + if (!from_share && table->vcol_fix_expr(thd)) goto err_lock; #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -5293,46 +5299,6 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list) } } -bool TABLE::vcol_fix_exprs(THD *thd) -{ - if (pos_in_table_list->placeholder() || !s->vcols_need_refixing || - pos_in_table_list->lock_type < TL_WRITE_ALLOW_WRITE) - return false; - - DBUG_ASSERT(pos_in_table_list != thd->lex->first_not_own_table()); - - bool result= true; - Security_context *save_security_ctx= thd->security_ctx; - Query_arena *stmt_backup= thd->stmt_arena; - if (thd->stmt_arena->is_conventional()) - thd->stmt_arena= expr_arena; - - if (pos_in_table_list->security_ctx) - thd->security_ctx= pos_in_table_list->security_ctx; - - - for (Field **vf= vfield; vf && *vf; vf++) - if ((*vf)->vcol_info->fix_session_expr(thd)) - goto end; - - for (Field **df= default_field; df && *df; df++) - if ((*df)->default_value && - (*df)->default_value->fix_session_expr(thd)) - goto end; - - for (Virtual_column_info **cc= check_constraints; cc && *cc; cc++) - if ((*cc)->fix_session_expr(thd)) - goto end; - - result= false; - -end: - thd->security_ctx= save_security_ctx; - thd->stmt_arena= stmt_backup; - - return result; -} - /** Lock all tables in a list. diff --git a/sql/table.cc b/sql/table.cc index d22266ff8d6..ebe9ccb762b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2990,33 +2990,131 @@ bool Virtual_column_info::fix_expr(THD *thd) */ bool Virtual_column_info::fix_session_expr(THD *thd) { - DBUG_ENTER("fix_session_vcol_expr"); - if (!(flags & (VCOL_TIME_FUNC|VCOL_SESSION_FUNC))) - DBUG_RETURN(0); + if (!need_refix()) + return false; - expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0); DBUG_ASSERT(!expr->fixed); - DBUG_RETURN(fix_expr(thd)); + if (fix_expr(thd)) + return true; + return false; } -/** invoke fix_session_vcol_expr for a vcol +bool Virtual_column_info::cleanup_session_expr() +{ + DBUG_ASSERT(need_refix()); + if (expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0)) + return true; + return false; +} - @note this is called for generated column or a DEFAULT expression from - their corresponding fix_fields on SELECT. -*/ -bool Virtual_column_info::fix_session_expr_for_read(THD *thd, Field *field) + + +class Vcol_expr_context { - DBUG_ENTER("fix_session_vcol_expr_for_read"); - TABLE_LIST *tl= field->table->pos_in_table_list; - if (!tl || tl->lock_type >= TL_WRITE_ALLOW_WRITE) - DBUG_RETURN(0); - Security_context *save_security_ctx= thd->security_ctx; - if (tl->security_ctx) + bool inited; + THD *thd; + TABLE *table; + LEX *old_lex; + LEX lex; + table_map old_map; + Security_context *save_security_ctx; + sql_mode_t save_sql_mode; + +public: + Vcol_expr_context(THD *_thd, TABLE *_table) : + inited(false), + thd(_thd), + table(_table), + old_lex(thd->lex), + old_map(table->map), + save_security_ctx(thd->security_ctx), + save_sql_mode(thd->variables.sql_mode) {} + bool init(); + + ~Vcol_expr_context(); +}; + + +bool Vcol_expr_context::init() +{ + /* + As this is vcol expression we must narrow down name resolution to + single table. + */ + if (init_lex_with_single_table(thd, table, &lex)) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + table->map= old_map; + return true; + } + + lex.sql_command= old_lex->sql_command; + thd->variables.sql_mode= 0; + + TABLE_LIST const *tl= table->pos_in_table_list; + DBUG_ASSERT(table->pos_in_table_list); + + if (table->pos_in_table_list->security_ctx) thd->security_ctx= tl->security_ctx; - bool res= fix_session_expr(thd); + + inited= true; + return false; +} + +Vcol_expr_context::~Vcol_expr_context() +{ + if (!inited) + return; + end_lex_with_single_table(thd, table, old_lex); + table->map= old_map; thd->security_ctx= save_security_ctx; - DBUG_RETURN(res); + thd->variables.sql_mode= save_sql_mode; +} + + +bool TABLE::vcol_fix_expr(THD *thd) +{ + if (pos_in_table_list->placeholder() || vcol_refix_list.is_empty()) + return false; + + if (!thd->stmt_arena->is_conventional() && + vcol_refix_list.head()->expr->fixed) + { + /* NOTE: Under trigger we already have fixed expressions */ + return false; + } + + Vcol_expr_context expr_ctx(thd, this); + if (expr_ctx.init()) + return true; + + List_iterator_fast<Virtual_column_info> it(vcol_refix_list); + while (Virtual_column_info *vcol= it++) + if (vcol->fix_session_expr(thd)) + goto error; + + return false; + +error: + DBUG_ASSERT(thd->get_stmt_da()->is_error()); + return true; +} + + +bool TABLE::vcol_cleanup_expr(THD *thd) +{ + if (vcol_refix_list.is_empty()) + return false; + + List_iterator<Virtual_column_info> it(vcol_refix_list); + bool result= false; + + while (Virtual_column_info *vcol= it++) + result|= vcol->cleanup_session_expr(); + + DBUG_ASSERT(!result || thd->get_stmt_da()->is_error()); + return result; } @@ -3047,6 +3145,7 @@ bool Virtual_column_info::fix_and_check_expr(THD *thd, TABLE *table) DBUG_PRINT("info", ("vcol: %p", this)); DBUG_ASSERT(expr); + /* NOTE: constants are fixed when constructed */ if (expr->fixed) DBUG_RETURN(0); // nothing to do @@ -3097,8 +3196,8 @@ bool Virtual_column_info::fix_and_check_expr(THD *thd, TABLE *table) } flags= res.errors; - if (flags & VCOL_SESSION_FUNC) - table->s->vcols_need_refixing= true; + if (!table->s->tmp_table && need_refix()) + table->vcol_refix_list.push_back(this, &table->mem_root); DBUG_RETURN(0); } @@ -3263,6 +3362,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, outparam->covering_keys.init(); outparam->intersect_keys.init(); outparam->keys_in_use_for_query.init(); + outparam->vcol_refix_list.empty(); /* Allocate handler */ outparam->file= 0; @@ -7961,14 +8061,21 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) Field **vfield_ptr, *vf; Query_arena backup_arena; Turn_errors_to_warnings_handler Suppress_errors; - int error; bool handler_pushed= 0, update_all_columns= 1; DBUG_ASSERT(vfield); if (h->keyread_enabled()) DBUG_RETURN(0); - - error= 0; + /* + TODO: this imposes memory leak until table flush when save_in_field() + does expr_arena allocation. F.ex. case in + gcol.gcol_supported_sql_funcs_innodb (see CONVERT_TZ): + + create table t1 ( + a datetime, b datetime generated always as + (convert_tz(a, 'MET', 'UTC')) virtual); + insert into t1 values ('2008-08-31', default); + */ in_use->set_n_backup_active_arena(expr_arena, &backup_arena); /* When reading or deleting row, ignore errors from virtual columns */ @@ -8042,7 +8149,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) int field_error __attribute__((unused)) = 0; /* Compute the actual value of the virtual fields */ if (vcol_info->expr->save_in_field(vf, 0)) - field_error= error= 1; + field_error= 1; DBUG_PRINT("info", ("field '%s' - updated error: %d", vf->field_name.str, field_error)); if (swap_values && (vf->flags & BLOB_FLAG)) @@ -8075,6 +8182,11 @@ int TABLE::update_virtual_field(Field *vf) Query_arena backup_arena; Counting_error_handler count_errors; in_use->push_internal_handler(&count_errors); + /* + TODO: this may impose memory leak until table flush. + See comment in + TABLE::update_virtual_fields(handler *, enum_vcol_update_mode). + */ in_use->set_n_backup_active_arena(expr_arena, &backup_arena); bitmap_clear_all(&tmp_set); vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &tmp_set); @@ -8113,6 +8225,11 @@ int TABLE::update_default_fields(bool ignore_errors) DBUG_ENTER("TABLE::update_default_fields"); DBUG_ASSERT(default_field); + /* + TODO: this may impose memory leak until table flush. + See comment in + TABLE::update_virtual_fields(handler *, enum_vcol_update_mode). + */ in_use->set_n_backup_active_arena(expr_arena, &backup_arena); /* Iterate over fields with default functions in the table */ diff --git a/sql/table.h b/sql/table.h index 66d4bd31435..34de21a39d5 100644 --- a/sql/table.h +++ b/sql/table.h @@ -822,7 +822,6 @@ struct TABLE_SHARE /* This is set for temporary tables where CREATE was binary logged */ bool table_creation_was_logged; bool non_determinstic_insert; - bool vcols_need_refixing; bool has_update_default_function; bool can_do_row_logging; /* 1 if table supports RBR */ ulong table_map_id; /* for row-based replication */ @@ -1406,12 +1405,13 @@ public: bool insert_or_update; /* Can be used by the handler */ /* NOTE: alias_name_used is only a hint! It works only in need_correct_ident() - condition. On other cases it is FALSE even if table_name is alias! - It cannot be TRUE in these cases, lots of spaghetti logic depends on that - (TODO). + condition. On other cases it is FALSE even if table_name is alias. + + E.g. in update t1 as x set a = 1 */ bool alias_name_used; /* true if table_name is alias */ bool get_fields_in_item_tree; /* Signal to fix_field */ + List<Virtual_column_info> vcol_refix_list; private: bool m_needs_reopen; bool created; /* For tmp tables. TRUE <=> tmp table was actually created.*/ @@ -1613,7 +1613,8 @@ public: TABLE *tmp_table, TMP_TABLE_PARAM *tmp_table_param, bool with_cleanup); - bool vcol_fix_exprs(THD *thd); + bool vcol_fix_expr(THD *thd); + bool vcol_cleanup_expr(THD *thd); Field *find_field_by_name(LEX_CSTRING *str) const; bool export_structure(THD *thd, class Row_definition_list *defs); bool is_splittable() { return spl_opt_info != NULL; } |