mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
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>
This commit is contained in:
@@ -94,6 +94,97 @@ create table t1 (a int, v_a int generated always as (a));
|
|||||||
update t1 as x set a = 1;
|
update t1 as x set a = 1;
|
||||||
alter table t1 force;
|
alter table t1 force;
|
||||||
drop table t1;
|
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;
|
||||||
|
@@ -77,7 +77,88 @@ update t1 as x set a = 1;
|
|||||||
alter table t1 force;
|
alter table t1 force;
|
||||||
drop table t1;
|
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 #
|
||||||
--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 #
|
--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;
|
||||||
|
@@ -610,6 +610,8 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
|
|||||||
|
|
||||||
*table= tables.table;
|
*table= tables.table;
|
||||||
tables.table->use_all_columns();
|
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))
|
if (table_intact.check(*table, &event_table_def))
|
||||||
{
|
{
|
||||||
|
@@ -2416,6 +2416,11 @@ int Field::set_default()
|
|||||||
if (default_value)
|
if (default_value)
|
||||||
{
|
{
|
||||||
Query_arena backup_arena;
|
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);
|
table->in_use->set_n_backup_active_arena(table->expr_arena, &backup_arena);
|
||||||
int rc= default_value->expr->save_in_field(this, 0);
|
int rc= default_value->expr->save_in_field(this, 0);
|
||||||
table->in_use->restore_active_arena(table->expr_arena, &backup_arena);
|
table->in_use->restore_active_arena(table->expr_arena, &backup_arena);
|
||||||
|
@@ -616,9 +616,13 @@ public:
|
|||||||
{
|
{
|
||||||
in_partitioning_expr= TRUE;
|
in_partitioning_expr= TRUE;
|
||||||
}
|
}
|
||||||
|
bool need_refix() const
|
||||||
|
{
|
||||||
|
return flags & VCOL_SESSION_FUNC;
|
||||||
|
}
|
||||||
bool fix_expr(THD *thd);
|
bool fix_expr(THD *thd);
|
||||||
bool fix_session_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);
|
bool fix_and_check_expr(THD *thd, TABLE *table);
|
||||||
inline bool is_equal(const Virtual_column_info* vcol) const;
|
inline bool is_equal(const Virtual_column_info* vcol) const;
|
||||||
inline void print(String*);
|
inline void print(String*);
|
||||||
|
10
sql/item.cc
10
sql/item.cc
@@ -835,7 +835,6 @@ bool Item_ident::remove_dependence_processor(void * arg)
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_ident::collect_outer_ref_processor(void *param)
|
bool Item_ident::collect_outer_ref_processor(void *param)
|
||||||
{
|
{
|
||||||
Collect_deps_prm *prm= (Collect_deps_prm *)param;
|
Collect_deps_prm *prm= (Collect_deps_prm *)param;
|
||||||
@@ -6376,9 +6375,6 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
fixed= 1;
|
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 &&
|
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
|
||||||
!outer_fixed && !thd->lex->in_sum_func &&
|
!outer_fixed && !thd->lex->in_sum_func &&
|
||||||
select &&
|
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());
|
uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length());
|
||||||
if (!newptr)
|
if (!newptr)
|
||||||
goto error;
|
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))
|
if (should_mark_column(thd->column_usage))
|
||||||
def_field->default_value->expr->update_used_tables();
|
def_field->default_value->expr->update_used_tables();
|
||||||
def_field->move_field(newptr+1, def_field->maybe_null() ? newptr : 0, 1);
|
def_field->move_field(newptr+1, def_field->maybe_null() ? newptr : 0, 1);
|
||||||
|
@@ -2925,10 +2925,8 @@ public:
|
|||||||
const char *table_name;
|
const char *table_name;
|
||||||
LEX_CSTRING field_name;
|
LEX_CSTRING field_name;
|
||||||
/*
|
/*
|
||||||
NOTE: came from TABLE::alias_name_used and this is only a hint! It works
|
NOTE: came from TABLE::alias_name_used and this is only a hint!
|
||||||
only in need_correct_ident() condition. On other cases it is FALSE even if
|
See comment for TABLE::alias_name_used.
|
||||||
table_name is alias! It cannot be TRUE in these cases, lots of spaghetti
|
|
||||||
logic depends on that.
|
|
||||||
*/
|
*/
|
||||||
bool alias_name_used; /* true if item was resolved against alias */
|
bool alias_name_used; /* true if item was resolved against alias */
|
||||||
/*
|
/*
|
||||||
|
@@ -749,6 +749,8 @@ void close_thread_tables(THD *thd)
|
|||||||
/* Table might be in use by some outer statement. */
|
/* Table might be in use by some outer statement. */
|
||||||
DBUG_PRINT("tcache", ("table: '%s' query_id: %lu",
|
DBUG_PRINT("tcache", ("table: '%s' query_id: %lu",
|
||||||
table->s->table_name.str, (ulong) table->query_id));
|
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 ||
|
if (thd->locked_tables_mode <= LTM_LOCK_TABLES ||
|
||||||
table->query_id == thd->query_id)
|
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->db.str,
|
||||||
table->s->table_name.str,
|
table->s->table_name.str,
|
||||||
MDL_SHARED));
|
MDL_SHARED));
|
||||||
|
|
||||||
|
table->vcol_cleanup_expr(thd);
|
||||||
table->mdl_ticket= NULL;
|
table->mdl_ticket= NULL;
|
||||||
|
|
||||||
if (table->file)
|
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;
|
MDL_ticket *mdl_ticket;
|
||||||
TABLE_SHARE *share;
|
TABLE_SHARE *share;
|
||||||
uint gts_flags;
|
uint gts_flags;
|
||||||
|
bool from_share= false;
|
||||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
int part_names_error=0;
|
int part_names_error=0;
|
||||||
#endif
|
#endif
|
||||||
@@ -2021,6 +2026,7 @@ retry_share:
|
|||||||
|
|
||||||
/* Add table to the share's used tables list. */
|
/* Add table to the share's used tables list. */
|
||||||
tc_add_table(thd, table);
|
tc_add_table(thd, table);
|
||||||
|
from_share= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
table->mdl_ticket= mdl_ticket;
|
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->updatable= 1; // It is not derived table nor non-updatable VIEW
|
||||||
table_list->table= table;
|
table_list->table= table;
|
||||||
|
|
||||||
if (table->vcol_fix_exprs(thd))
|
if (!from_share && table->vcol_fix_expr(thd))
|
||||||
goto err_lock;
|
goto err_lock;
|
||||||
|
|
||||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
#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.
|
Lock all tables in a list.
|
||||||
|
165
sql/table.cc
165
sql/table.cc
@@ -2990,33 +2990,131 @@ bool Virtual_column_info::fix_expr(THD *thd)
|
|||||||
*/
|
*/
|
||||||
bool Virtual_column_info::fix_session_expr(THD *thd)
|
bool Virtual_column_info::fix_session_expr(THD *thd)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("fix_session_vcol_expr");
|
if (!need_refix())
|
||||||
if (!(flags & (VCOL_TIME_FUNC|VCOL_SESSION_FUNC)))
|
return false;
|
||||||
DBUG_RETURN(0);
|
|
||||||
|
|
||||||
expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0);
|
|
||||||
DBUG_ASSERT(!expr->fixed);
|
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()
|
||||||
|
|
||||||
@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)
|
|
||||||
{
|
{
|
||||||
DBUG_ENTER("fix_session_vcol_expr_for_read");
|
DBUG_ASSERT(need_refix());
|
||||||
TABLE_LIST *tl= field->table->pos_in_table_list;
|
if (expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0))
|
||||||
if (!tl || tl->lock_type >= TL_WRITE_ALLOW_WRITE)
|
return true;
|
||||||
DBUG_RETURN(0);
|
return false;
|
||||||
Security_context *save_security_ctx= thd->security_ctx;
|
}
|
||||||
if (tl->security_ctx)
|
|
||||||
|
|
||||||
|
|
||||||
|
class Vcol_expr_context
|
||||||
|
{
|
||||||
|
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;
|
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;
|
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_PRINT("info", ("vcol: %p", this));
|
||||||
DBUG_ASSERT(expr);
|
DBUG_ASSERT(expr);
|
||||||
|
|
||||||
|
/* NOTE: constants are fixed when constructed */
|
||||||
if (expr->fixed)
|
if (expr->fixed)
|
||||||
DBUG_RETURN(0); // nothing to do
|
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;
|
flags= res.errors;
|
||||||
|
|
||||||
if (flags & VCOL_SESSION_FUNC)
|
if (!table->s->tmp_table && need_refix())
|
||||||
table->s->vcols_need_refixing= true;
|
table->vcol_refix_list.push_back(this, &table->mem_root);
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
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->covering_keys.init();
|
||||||
outparam->intersect_keys.init();
|
outparam->intersect_keys.init();
|
||||||
outparam->keys_in_use_for_query.init();
|
outparam->keys_in_use_for_query.init();
|
||||||
|
outparam->vcol_refix_list.empty();
|
||||||
|
|
||||||
/* Allocate handler */
|
/* Allocate handler */
|
||||||
outparam->file= 0;
|
outparam->file= 0;
|
||||||
@@ -7961,14 +8061,21 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
|
|||||||
Field **vfield_ptr, *vf;
|
Field **vfield_ptr, *vf;
|
||||||
Query_arena backup_arena;
|
Query_arena backup_arena;
|
||||||
Turn_errors_to_warnings_handler Suppress_errors;
|
Turn_errors_to_warnings_handler Suppress_errors;
|
||||||
int error;
|
|
||||||
bool handler_pushed= 0, update_all_columns= 1;
|
bool handler_pushed= 0, update_all_columns= 1;
|
||||||
DBUG_ASSERT(vfield);
|
DBUG_ASSERT(vfield);
|
||||||
|
|
||||||
if (h->keyread_enabled())
|
if (h->keyread_enabled())
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(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):
|
||||||
|
|
||||||
error= 0;
|
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);
|
in_use->set_n_backup_active_arena(expr_arena, &backup_arena);
|
||||||
|
|
||||||
/* When reading or deleting row, ignore errors from virtual columns */
|
/* 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;
|
int field_error __attribute__((unused)) = 0;
|
||||||
/* Compute the actual value of the virtual fields */
|
/* Compute the actual value of the virtual fields */
|
||||||
if (vcol_info->expr->save_in_field(vf, 0))
|
if (vcol_info->expr->save_in_field(vf, 0))
|
||||||
field_error= error= 1;
|
field_error= 1;
|
||||||
DBUG_PRINT("info", ("field '%s' - updated error: %d",
|
DBUG_PRINT("info", ("field '%s' - updated error: %d",
|
||||||
vf->field_name.str, field_error));
|
vf->field_name.str, field_error));
|
||||||
if (swap_values && (vf->flags & BLOB_FLAG))
|
if (swap_values && (vf->flags & BLOB_FLAG))
|
||||||
@@ -8075,6 +8182,11 @@ int TABLE::update_virtual_field(Field *vf)
|
|||||||
Query_arena backup_arena;
|
Query_arena backup_arena;
|
||||||
Counting_error_handler count_errors;
|
Counting_error_handler count_errors;
|
||||||
in_use->push_internal_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);
|
in_use->set_n_backup_active_arena(expr_arena, &backup_arena);
|
||||||
bitmap_clear_all(&tmp_set);
|
bitmap_clear_all(&tmp_set);
|
||||||
vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &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_ENTER("TABLE::update_default_fields");
|
||||||
DBUG_ASSERT(default_field);
|
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);
|
in_use->set_n_backup_active_arena(expr_arena, &backup_arena);
|
||||||
|
|
||||||
/* Iterate over fields with default functions in the table */
|
/* Iterate over fields with default functions in the table */
|
||||||
|
11
sql/table.h
11
sql/table.h
@@ -822,7 +822,6 @@ struct TABLE_SHARE
|
|||||||
/* This is set for temporary tables where CREATE was binary logged */
|
/* This is set for temporary tables where CREATE was binary logged */
|
||||||
bool table_creation_was_logged;
|
bool table_creation_was_logged;
|
||||||
bool non_determinstic_insert;
|
bool non_determinstic_insert;
|
||||||
bool vcols_need_refixing;
|
|
||||||
bool has_update_default_function;
|
bool has_update_default_function;
|
||||||
bool can_do_row_logging; /* 1 if table supports RBR */
|
bool can_do_row_logging; /* 1 if table supports RBR */
|
||||||
ulong table_map_id; /* for row-based replication */
|
ulong table_map_id; /* for row-based replication */
|
||||||
@@ -1406,12 +1405,13 @@ public:
|
|||||||
bool insert_or_update; /* Can be used by the handler */
|
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()
|
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!
|
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).
|
E.g. in update t1 as x set a = 1
|
||||||
*/
|
*/
|
||||||
bool alias_name_used; /* true if table_name is alias */
|
bool alias_name_used; /* true if table_name is alias */
|
||||||
bool get_fields_in_item_tree; /* Signal to fix_field */
|
bool get_fields_in_item_tree; /* Signal to fix_field */
|
||||||
|
List<Virtual_column_info> vcol_refix_list;
|
||||||
private:
|
private:
|
||||||
bool m_needs_reopen;
|
bool m_needs_reopen;
|
||||||
bool created; /* For tmp tables. TRUE <=> tmp table was actually created.*/
|
bool created; /* For tmp tables. TRUE <=> tmp table was actually created.*/
|
||||||
@@ -1613,7 +1613,8 @@ public:
|
|||||||
TABLE *tmp_table,
|
TABLE *tmp_table,
|
||||||
TMP_TABLE_PARAM *tmp_table_param,
|
TMP_TABLE_PARAM *tmp_table_param,
|
||||||
bool with_cleanup);
|
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;
|
Field *find_field_by_name(LEX_CSTRING *str) const;
|
||||||
bool export_structure(THD *thd, class Row_definition_list *defs);
|
bool export_structure(THD *thd, class Row_definition_list *defs);
|
||||||
bool is_splittable() { return spl_opt_info != NULL; }
|
bool is_splittable() { return spl_opt_info != NULL; }
|
||||||
|
Reference in New Issue
Block a user