1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

Merge 10.7 into 10.8

This commit is contained in:
Marko Mäkelä
2022-04-27 10:43:00 +03:00
301 changed files with 9772 additions and 8644 deletions

View File

@@ -88,10 +88,8 @@ struct extra2_fields
{ bzero((void*)this, sizeof(*this)); }
};
static Virtual_column_info * unpack_vcol_info_from_frm(THD *, MEM_ROOT *,
static Virtual_column_info * unpack_vcol_info_from_frm(THD *,
TABLE *, String *, Virtual_column_info **, bool *);
static bool check_vcol_forward_refs(Field *, Virtual_column_info *,
bool check_constraint);
/* INFORMATION_SCHEMA name */
LEX_CSTRING INFORMATION_SCHEMA_NAME= {STRING_WITH_LEN("information_schema")};
@@ -1119,9 +1117,6 @@ static void mysql57_calculate_null_position(TABLE_SHARE *share,
}
}
static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
Virtual_column_info *vcol);
/** Parse TABLE_SHARE::vcol_defs
unpack_vcol_info_from_frm
@@ -1147,6 +1142,31 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
bool *error_reported, vcol_init_mode mode)
{
struct check_vcol_forward_refs
{
static bool check(Field *field, Virtual_column_info *vcol)
{
return vcol &&
vcol->expr->walk(&Item::check_field_expression_processor, 0, field);
}
static bool check_constraint(Field *field, Virtual_column_info *vcol)
{
uint32 flags= field->flags;
/* Check constraints can refer it itself */
field->flags|= NO_DEFAULT_VALUE_FLAG;
const bool res= check(field, vcol);
field->flags= flags;
return res;
}
static bool check(Field *field)
{
if (check(field, field->vcol_info) ||
check_constraint(field, field->check_constraint) ||
check(field, field->default_value))
return true;
return false;
}
};
CHARSET_INFO *save_character_set_client= thd->variables.character_set_client;
CHARSET_INFO *save_collation= thd->variables.collation_connection;
Query_arena *backup_stmt_arena_ptr= thd->stmt_arena;
@@ -1221,7 +1241,7 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
switch (type) {
case VCOL_GENERATED_VIRTUAL:
case VCOL_GENERATED_STORED:
vcol= unpack_vcol_info_from_frm(thd, mem_root, table, &expr_str,
vcol= unpack_vcol_info_from_frm(thd, table, &expr_str,
&((*field_ptr)->vcol_info), error_reported);
*(vfield_ptr++)= *field_ptr;
DBUG_ASSERT(table->map == 0);
@@ -1241,7 +1261,7 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
table->map= 0;
break;
case VCOL_DEFAULT:
vcol= unpack_vcol_info_from_frm(thd, mem_root, table, &expr_str,
vcol= unpack_vcol_info_from_frm(thd, table, &expr_str,
&((*field_ptr)->default_value),
error_reported);
*(dfield_ptr++)= *field_ptr;
@@ -1249,13 +1269,13 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
table->s->non_determinstic_insert= true;
break;
case VCOL_CHECK_FIELD:
vcol= unpack_vcol_info_from_frm(thd, mem_root, table, &expr_str,
vcol= unpack_vcol_info_from_frm(thd, table, &expr_str,
&((*field_ptr)->check_constraint),
error_reported);
*check_constraint_ptr++= (*field_ptr)->check_constraint;
break;
case VCOL_CHECK_TABLE:
vcol= unpack_vcol_info_from_frm(thd, mem_root, table, &expr_str,
vcol= unpack_vcol_info_from_frm(thd, table, &expr_str,
check_constraint_ptr, error_reported);
check_constraint_ptr++;
break;
@@ -1307,7 +1327,7 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
field->vcol_info= v;
field->vcol_info->expr= hash_item;
field->vcol_info->set_vcol_type(VCOL_USING_HASH);
if (fix_and_check_vcol_expr(thd, table, v))
if (v->fix_and_check_expr(thd, table))
goto end;
key->user_defined_key_parts= key->ext_key_parts= key->usable_key_parts= 1;
key->key_part+= parts;
@@ -1325,7 +1345,7 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
expr_str.append(STRING_WITH_LEN("current_timestamp("));
expr_str.append_ulonglong(field->decimals());
expr_str.append(')');
vcol= unpack_vcol_info_from_frm(thd, mem_root, table, &expr_str,
vcol= unpack_vcol_info_from_frm(thd, table, &expr_str,
&((*field_ptr)->default_value),
error_reported);
*(dfield_ptr++)= *field_ptr;
@@ -1347,16 +1367,11 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
/* Check that expressions aren't referring to not yet initialized fields */
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
Field *field= *field_ptr;
if (check_vcol_forward_refs(field, field->vcol_info, 0) ||
check_vcol_forward_refs(field, field->check_constraint, 1) ||
check_vcol_forward_refs(field, field->default_value, 0))
if (check_vcol_forward_refs::check(*field_ptr))
{
*error_reported= true;
goto end;
}
}
table->find_constraint_correlated_indexes();
@@ -3594,21 +3609,21 @@ void TABLE_SHARE::free_frm_image(const uchar *frm)
}
static bool fix_vcol_expr(THD *thd, Virtual_column_info *vcol)
bool Virtual_column_info::fix_expr(THD *thd)
{
DBUG_ENTER("fix_vcol_expr");
const enum enum_column_usage saved_column_usage= thd->column_usage;
thd->column_usage= COLUMNS_WRITE;
int error= vcol->expr->fix_fields(thd, &vcol->expr);
int error= expr->fix_fields(thd, &expr);
thd->column_usage= saved_column_usage;
if (unlikely(error))
{
StringBuffer<MAX_FIELD_WIDTH> str;
vcol->print(&str);
print(&str);
my_error(ER_ERROR_EVALUATING_EXPRESSION, MYF(0), str.c_ptr_safe());
DBUG_RETURN(1);
}
@@ -3621,36 +3636,129 @@ static bool fix_vcol_expr(THD *thd, Virtual_column_info *vcol)
@note this is done for all vcols for INSERT/UPDATE/DELETE,
and only as needed for SELECTs.
*/
bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol)
bool Virtual_column_info::fix_session_expr(THD *thd)
{
DBUG_ENTER("fix_session_vcol_expr");
if (!(vcol->flags & (VCOL_TIME_FUNC|VCOL_SESSION_FUNC)))
DBUG_RETURN(0);
if (!need_refix())
return false;
vcol->expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0);
DBUG_ASSERT(!vcol->expr->fixed());
DBUG_RETURN(fix_vcol_expr(thd, vcol));
DBUG_ASSERT(!expr->fixed());
return fix_expr(thd);
}
/** invoke fix_session_vcol_expr for a vcol
@note this is called for generated column or a DEFAULT expression from
their corresponding fix_fields on SELECT.
*/
bool fix_session_vcol_expr_for_read(THD *thd, Field *field,
Virtual_column_info *vcol)
bool Virtual_column_info::cleanup_session_expr()
{
DBUG_ENTER("fix_session_vcol_expr_for_read");
TABLE_LIST *tl= field->table->pos_in_table_list;
if (!tl || tl->lock_type >= TL_FIRST_WRITE)
DBUG_RETURN(0);
Security_context *save_security_ctx= thd->security_ctx;
if (tl->security_ctx)
DBUG_ASSERT(need_refix());
return expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0);
}
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;
bool res= fix_session_vcol_expr(thd, vcol);
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;
}
@@ -3675,28 +3783,25 @@ bool fix_session_vcol_expr_for_read(THD *thd, Field *field,
FALSE Otherwise
*/
static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
Virtual_column_info *vcol)
bool Virtual_column_info::fix_and_check_expr(THD *thd, TABLE *table)
{
Item* func_expr= vcol->expr;
DBUG_ENTER("fix_and_check_vcol_expr");
DBUG_PRINT("info", ("vcol: %p", vcol));
DBUG_ASSERT(func_expr);
DBUG_ENTER("Virtual_column_info::fix_and_check_expr");
DBUG_PRINT("info", ("vcol: %p", this));
DBUG_ASSERT(expr);
if (func_expr->fixed())
/* NOTE: constants are fixed when constructed */
if (expr->fixed())
DBUG_RETURN(0); // nothing to do
if (fix_vcol_expr(thd, vcol))
if (fix_expr(thd))
DBUG_RETURN(1);
if (vcol->flags)
if (flags)
DBUG_RETURN(0); // already checked, no need to do it again
/* fix_fields could've changed the expression */
func_expr= vcol->expr;
/* this was checked in check_expression(), but the frm could be mangled... */
if (unlikely(func_expr->result_type() == ROW_RESULT))
if (unlikely(expr->result_type() == ROW_RESULT))
{
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
DBUG_RETURN(1);
@@ -3708,12 +3813,12 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
*/
Item::vcol_func_processor_result res;
int error= func_expr->walk(&Item::check_vcol_func_processor, 0, &res);
int error= expr->walk(&Item::check_vcol_func_processor, 0, &res);
if (unlikely(error || (res.errors & VCOL_IMPOSSIBLE)))
{
// this can only happen if the frm was corrupted
my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), res.name,
vcol->get_vcol_type_name(), vcol->name.str);
get_vcol_type_name(), name.str);
DBUG_RETURN(1);
}
else if (unlikely(res.errors & VCOL_AUTO_INC))
@@ -3728,14 +3833,14 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
*/
myf warn= table->s->frm_version < FRM_VER_EXPRESSSIONS ? ME_WARNING : 0;
my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(warn),
"AUTO_INCREMENT", vcol->get_vcol_type_name(), res.name);
"AUTO_INCREMENT", get_vcol_type_name(), res.name);
if (!warn)
DBUG_RETURN(1);
}
vcol->flags= res.errors;
flags= res.errors;
if (vcol->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);
}
@@ -3773,7 +3878,7 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
*/
static Virtual_column_info *
unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table,
unpack_vcol_info_from_frm(THD *thd, TABLE *table,
String *expr_str, Virtual_column_info **vcol_ptr,
bool *error_reported)
{
@@ -3812,7 +3917,7 @@ unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table,
vcol_storage.vcol_info->stored_in_db= vcol->stored_in_db;
vcol_storage.vcol_info->name= vcol->name;
vcol_storage.vcol_info->utf8= vcol->utf8;
if (!fix_and_check_vcol_expr(thd, table, vcol_storage.vcol_info))
if (!vcol_storage.vcol_info->fix_and_check_expr(thd, table))
{
*vcol_ptr= vcol_info= vcol_storage.vcol_info; // Expression ok
DBUG_ASSERT(vcol_info->expr);
@@ -3826,22 +3931,6 @@ end:
DBUG_RETURN(vcol_info);
}
static bool check_vcol_forward_refs(Field *field, Virtual_column_info *vcol,
bool check_constraint)
{
bool res;
uint32 flags= field->flags;
if (check_constraint)
{
/* Check constraints can refer it itself */
field->flags|= NO_DEFAULT_VALUE_FLAG;
}
res= (vcol &&
vcol->expr->walk(&Item::check_field_expression_processor, 0, field));
field->flags= flags;
return res;
}
#ifndef DBUG_OFF
static void print_long_unique_table(TABLE *table)
{
@@ -4042,6 +4131,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
goto err;
outparam->alias.set(tmp_alias, alias->length, table_alias_charset);
outparam->vcol_refix_list.empty();
/* Allocate handler */
outparam->file= 0;
@@ -8688,7 +8778,16 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
if (h->keyread_enabled())
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):
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 */
@@ -8759,10 +8858,12 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
if (update)
{
int field_error __attribute__((unused)) = 0;
/* Compute the actual value of the virtual fields */
DBUG_FIX_WRITE_SET(vf);
field_error= vcol_info->expr->save_in_field(vf, 0);
# ifndef DBUG_OFF
int field_error=
# endif
vcol_info->expr->save_in_field(vf, 0);
DBUG_RESTORE_WRITE_SET(vf);
DBUG_PRINT("info", ("field '%s' - updated error: %d",
vf->field_name.str, field_error));
@@ -8796,6 +8897,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);
@@ -8836,6 +8942,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 */