diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-03-05 12:54:43 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-03-05 12:54:43 +0200 |
commit | 10d544aa7b305210246a976ca47a7559f8b78f72 (patch) | |
tree | a6df2319a67afbc523be05789c77e9a28a49e29c /sql | |
parent | aa4f76bed715ec1016260f593e9cf4a8a1a4da36 (diff) | |
parent | fcc9f8b10cd2f497ff410b592808eedb3ee5f212 (diff) | |
download | mariadb-git-10d544aa7b305210246a976ca47a7559f8b78f72.tar.gz |
Merge 10.4 into 10.5
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_partition.cc | 1 | ||||
-rw-r--r-- | sql/handler.h | 6 | ||||
-rw-r--r-- | sql/item.cc | 53 | ||||
-rw-r--r-- | sql/item.h | 15 | ||||
-rw-r--r-- | sql/sql_admin.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 268 | ||||
-rw-r--r-- | sql/sql_parse.h | 1 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 16 | ||||
-rw-r--r-- | sql/sql_select.cc | 129 | ||||
-rw-r--r-- | sql/sql_truncate.cc | 9 | ||||
-rw-r--r-- | sql/sql_tvc.cc | 15 | ||||
-rw-r--r-- | sql/table.h | 6 |
12 files changed, 368 insertions, 153 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index cdfde2cc3ee..d52f44f9b95 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -9182,7 +9182,6 @@ int ha_partition::extra(enum ha_extra_function operation) case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN: case HA_EXTRA_BEGIN_ALTER_COPY: case HA_EXTRA_END_ALTER_COPY: - case HA_EXTRA_FAKE_START_STMT: DBUG_RETURN(loop_partitions(extra_cb, &operation)); default: { diff --git a/sql/handler.h b/sql/handler.h index b0a90f24494..b00643d0ace 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1799,6 +1799,12 @@ handlerton *ha_default_tmp_handlerton(THD *thd); */ #define HTON_TRANSACTIONAL_AND_NON_TRANSACTIONAL (1 << 17) +/* + Table requires and close and reopen after truncate + If the handler has HTON_CAN_RECREATE, this flag is not used +*/ +#define HTON_REQUIRES_CLOSE_AFTER_TRUNCATE (1 << 18) + class Ha_trx_info; struct THD_TRANS diff --git a/sql/item.cc b/sql/item.cc index f818a9f02e7..7caa9e41e2f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9372,7 +9372,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) def_field->reset_fields(); // If non-constant default value expression or a blob if (def_field->default_value && - (def_field->default_value->flags || def_field->flags & BLOB_FLAG)) + (def_field->default_value->flags || (def_field->flags & BLOB_FLAG))) { uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length()); if (!newptr) @@ -9476,11 +9476,60 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) return Item_field::save_in_field(field_arg, no_conversions); } +double Item_default_value::val_result() +{ + calculate(); + return Item_field::val_result(); +} + +longlong Item_default_value::val_int_result() +{ + calculate(); + return Item_field::val_int_result(); +} + +String *Item_default_value::str_result(String* tmp) +{ + calculate(); + return Item_field::str_result(tmp); +} + +bool Item_default_value::val_bool_result() +{ + calculate(); + return Item_field::val_bool_result(); +} + +bool Item_default_value::is_null_result() +{ + calculate(); + return Item_field::is_null_result(); +} + +my_decimal *Item_default_value::val_decimal_result(my_decimal *decimal_value) +{ + calculate(); + return Item_field::val_decimal_result(decimal_value); +} + +bool Item_default_value::get_date_result(THD *thd, MYSQL_TIME *ltime, + date_mode_t fuzzydate) +{ + calculate(); + return Item_field::get_date_result(thd, ltime, fuzzydate); +} + +bool Item_default_value::val_native_result(THD *thd, Native *to) +{ + calculate(); + return Item_field::val_native_result(thd, to); +} + table_map Item_default_value::used_tables() const { if (!field || !field->default_value) return static_cast<table_map>(0); - if (!field->default_value->expr) // not fully parsed field + if (!field->default_value->expr) // not fully parsed field return static_cast<table_map>(RAND_TABLE_BIT); return field->default_value->expr->used_tables(); } diff --git a/sql/item.h b/sql/item.h index 03c5ad06fa9..2a87081584d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2,7 +2,7 @@ #define SQL_ITEM_INCLUDED /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB Corporation. + Copyright (c) 2009, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -6428,6 +6428,17 @@ public: my_decimal *val_decimal(my_decimal *decimal_value); bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate); bool val_native(THD *thd, Native *to); + bool val_native_result(THD *thd, Native *to); + + /* Result variants */ + double val_result(); + longlong val_int_result(); + String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *val); + bool val_bool_result(); + bool is_null_result(); + bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); + bool send(Protocol *protocol, st_value *buffer); int save_in_field(Field *field_arg, bool no_conversions); bool save_in_param(THD *thd, Item_param *param) @@ -6456,6 +6467,8 @@ public: } Item *transform(THD *thd, Item_transformer transformer, uchar *args); + Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, + const Tmp_field_param *param); }; diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index ee7226afd0b..3f5b15715f9 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1395,7 +1395,9 @@ bool Sql_cmd_analyze_table::execute(THD *thd) /* Presumably, ANALYZE and binlog writing doesn't require synchronization */ + thd->get_stmt_da()->set_overwrite_status(true); res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + thd->get_stmt_da()->set_overwrite_status(false); } m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cb960a89cb6..e7fe0b39e3a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3346,6 +3346,146 @@ bool Sql_cmd_call::execute(THD *thd) /** + Check whether the SQL statement being processed is prepended by + SET STATEMENT clause and handle variables assignment if it is. + + @param thd thread handle + @param lex current lex + + @return false in case of success, true in case of error. +*/ + +bool run_set_statement_if_requested(THD *thd, LEX *lex) +{ + if (!lex->stmt_var_list.is_empty() && !thd->slave_thread) + { + Query_arena backup; + DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements)); + + lex->old_var_list.empty(); + List_iterator_fast<set_var_base> it(lex->stmt_var_list); + set_var_base *var; + + if (lex->set_arena_for_set_stmt(&backup)) + return true; + + MEM_ROOT *mem_root= thd->mem_root; + while ((var= it++)) + { + DBUG_ASSERT(var->is_system()); + set_var *o= NULL, *v= (set_var*)var; + if (!v->var->is_set_stmt_ok()) + { + my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str); + lex->reset_arena_for_set_stmt(&backup); + lex->old_var_list.empty(); + lex->free_arena_for_set_stmt(); + return true; + } + if (v->var->session_is_default(thd)) + o= new set_var(thd,v->type, v->var, &v->base, NULL); + else + { + switch (v->var->option.var_type & GET_TYPE_MASK) + { + case GET_BOOL: + case GET_INT: + case GET_LONG: + case GET_LL: + { + bool null_value; + longlong val= v->var->val_int(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_int(thd, val))); + } + break; + case GET_UINT: + case GET_ULONG: + case GET_ULL: + { + bool null_value; + ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_uint(thd, val))); + } + break; + case GET_DOUBLE: + { + bool null_value; + double val= v->var->val_real(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_float(thd, val, 1))); + } + break; + default: + case GET_NO_ARG: + case GET_DISABLED: + DBUG_ASSERT(0); + /* fall through */ + case 0: + case GET_FLAGSET: + case GET_ENUM: + case GET_SET: + case GET_STR: + case GET_STR_ALLOC: + { + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), v->var->charset(thd)),*val; + val= v->var->val_str(&tmp, thd, v->type, &v->base); + if (val) + { + Item_string *str= + new (mem_root) Item_string(thd, v->var->charset(thd), + val->ptr(), val->length()); + o= new set_var(thd, v->type, v->var, &v->base, str); + } + else + o= new set_var(thd, v->type, v->var, &v->base, + new (mem_root) Item_null(thd)); + } + break; + } + } + DBUG_ASSERT(o); + lex->old_var_list.push_back(o, thd->mem_root); + } + lex->reset_arena_for_set_stmt(&backup); + + if (lex->old_var_list.is_empty()) + lex->free_arena_for_set_stmt(); + + if (thd->is_error() || + sql_set_variables(thd, &lex->stmt_var_list, false)) + { + if (!thd->is_error()) + my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET"); + lex->restore_set_statement_var(); + return true; + } + /* + The value of last_insert_id is remembered in THD to be written to binlog + when it's used *the first time* in the statement. But SET STATEMENT + must read the old value of last_insert_id to be able to restore it at + the end. This should not count at "reading of last_insert_id" and + should not remember last_insert_id for binlog. That is, it should clear + stmt_depends_on_first_successful_insert_id_in_prev_stmt flag. + */ + if (!thd->in_sub_stmt) + { + thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; + } + } + return false; +} + + +/** Execute command saved in thd and lex->sql_command. @param thd Thread handle @@ -3631,127 +3771,13 @@ mysql_execute_command(THD *thd) thd->get_binlog_format(&orig_binlog_format, &orig_current_stmt_binlog_format); - if (!lex->stmt_var_list.is_empty() && !thd->slave_thread) - { - Query_arena backup; - DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements)); - - lex->old_var_list.empty(); - List_iterator_fast<set_var_base> it(lex->stmt_var_list); - set_var_base *var; - - if (lex->set_arena_for_set_stmt(&backup)) - goto error; - - MEM_ROOT *mem_root= thd->mem_root; - while ((var= it++)) - { - DBUG_ASSERT(var->is_system()); - set_var *o= NULL, *v= (set_var*)var; - if (!v->var->is_set_stmt_ok()) - { - my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str); - lex->reset_arena_for_set_stmt(&backup); - lex->old_var_list.empty(); - lex->free_arena_for_set_stmt(); - goto error; - } - if (v->var->session_is_default(thd)) - o= new set_var(thd,v->type, v->var, &v->base, NULL); - else - { - switch (v->var->option.var_type & GET_TYPE_MASK) - { - case GET_BOOL: - case GET_INT: - case GET_LONG: - case GET_LL: - { - bool null_value; - longlong val= v->var->val_int(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_int(thd, val))); - } - break; - case GET_UINT: - case GET_ULONG: - case GET_ULL: - { - bool null_value; - ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_uint(thd, val))); - } - break; - case GET_DOUBLE: - { - bool null_value; - double val= v->var->val_real(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_float(thd, val, 1))); - } - break; - default: - case GET_NO_ARG: - case GET_DISABLED: - DBUG_ASSERT(0); - /* fall through */ - case 0: - case GET_FLAGSET: - case GET_ENUM: - case GET_SET: - case GET_STR: - case GET_STR_ALLOC: - { - char buff[STRING_BUFFER_USUAL_SIZE]; - String tmp(buff, sizeof(buff), v->var->charset(thd)),*val; - val= v->var->val_str(&tmp, thd, v->type, &v->base); - if (val) - { - Item_string *str= new (mem_root) Item_string(thd, v->var->charset(thd), - val->ptr(), val->length()); - o= new set_var(thd, v->type, v->var, &v->base, str); - } - else - o= new set_var(thd, v->type, v->var, &v->base, - new (mem_root) Item_null(thd)); - } - break; - } - } - DBUG_ASSERT(o); - lex->old_var_list.push_back(o, thd->mem_root); - } - lex->reset_arena_for_set_stmt(&backup); - if (lex->old_var_list.is_empty()) - lex->free_arena_for_set_stmt(); - if (thd->is_error() || - (res= sql_set_variables(thd, &lex->stmt_var_list, false))) - { - if (!thd->is_error()) - my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET"); - lex->restore_set_statement_var(); - goto error; - } - /* - The value of last_insert_id is remembered in THD to be written to binlog - when it's used *the first time* in the statement. But SET STATEMENT - must read the old value of last_insert_id to be able to restore it at - the end. This should not count at "reading of last_insert_id" and - should not remember last_insert_id for binlog. That is, it should clear - stmt_depends_on_first_successful_insert_id_in_prev_stmt flag. - */ - if (!thd->in_sub_stmt) - { - thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; - } - } + /* + Assign system variables with values specified by the clause + SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement> + if they are any. + */ + if (run_set_statement_if_requested(thd, lex)) + goto error; if (thd->lex->mi.connection_name.str == NULL) thd->lex->mi.connection_name= thd->variables.default_master_connection; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 0e5cc7f4bad..ac5786dbaa0 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -100,6 +100,7 @@ void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void create_table_set_open_action_and_adjust_tables(LEX *lex); int bootstrap(MYSQL_FILE *file); +bool run_set_statement_if_requested(THD *thd, LEX *lex); int mysql_execute_command(THD *thd); bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 21c8f739dd2..33ced717ab9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4260,6 +4260,16 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) */ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); + /* + Set variables specified by + SET STATEMENT var1=value1 [, var2=value2, ...] FOR <statement> + clause for duration of prepare phase. Original values of variable + listed in the SET STATEMENT clause is restored right after return + from the function check_prepared_statement() + */ + if (likely(error == 0)) + error= run_set_statement_if_requested(thd, lex); + /* The only case where we should have items in the thd->free_list is after stmt->set_params_from_vars(), which may in some cases create @@ -4278,6 +4288,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE; } + /* + Restore original values of variables modified on handling + SET STATEMENT clause. + */ + thd->lex->restore_set_statement_var(); + /* The order is important */ lex->unit.cleanup(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2f88d4f9217..5443d60efe0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB Corporation. + Copyright (c) 2009, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4682,6 +4682,9 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, } else { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + /* When in EXPLAIN, delay deleting the joins so that they are still available when we're producing EXPLAIN EXTENDED warning text. @@ -14499,22 +14502,71 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables, DBUG_RETURN(0); } -/* - used only in JOIN::clear +/** + used only in JOIN::clear (always) and in do_select() + (if there where no matching rows) + + @param join JOIN + @param cleared_tables If not null, clear also const tables and mark all + cleared tables in the map. cleared_tables is only + set when called from do_select() when there is a + group function and there where no matching rows. */ -static void clear_tables(JOIN *join) + +static void clear_tables(JOIN *join, table_map *cleared_tables) { /* - must clear only the non-const tables, as const tables - are not re-calculated. + must clear only the non-const tables as const tables are not re-calculated. */ for (uint i= 0 ; i < join->table_count ; i++) { - if (!(join->table[i]->map & join->const_table_map)) - mark_as_null_row(join->table[i]); // All fields are NULL + TABLE *table= join->table[i]; + + if (table->null_row) + continue; // Nothing more to do + if (!(table->map & join->const_table_map) || cleared_tables) + { + if (cleared_tables) + { + (*cleared_tables)|= (((table_map) 1) << i); + if (table->s->null_bytes) + { + /* + Remember null bits for the record so that we can restore the + original const record in unclear_tables() + */ + memcpy(table->record[1], table->null_flags, table->s->null_bytes); + } + } + mark_as_null_row(table); // All fields are NULL + } + } +} + + +/** + Reverse null marking for tables and restore null bits. + + We have to do this because the tables may be re-used in a sub query + and the subquery will assume that the const tables contains the original + data before clear_tables(). +*/ + +static void unclear_tables(JOIN *join, table_map *cleared_tables) +{ + for (uint i= 0 ; i < join->table_count ; i++) + { + if ((*cleared_tables) & (((table_map) 1) << i)) + { + TABLE *table= join->table[i]; + if (table->s->null_bytes) + memcpy(table->null_flags, table->record[1], table->s->null_bytes); + unmark_as_null_row(table); + } } } + /***************************************************************************** Make som simple condition optimization: If there is a test 'field = const' change all refs to 'field' to 'const' @@ -17985,17 +18037,34 @@ Field *Item_field::create_tmp_field_ex(MEM_ROOT *root, TABLE *table, src->set_field(field); if (!(result= create_tmp_field_from_item_field(root, table, NULL, param))) return NULL; - /* - Fields that are used as arguments to the DEFAULT() function already have - their data pointers set to the default value during name resolution. See - Item_default_value::fix_fields. - */ - if (type() != Item::DEFAULT_VALUE_ITEM && field->eq_def(result)) + if (field->eq_def(result)) src->set_default_field(field); return result; } +Field *Item_default_value::create_tmp_field_ex(MEM_ROOT *root, TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + if (field->default_value && (field->flags & BLOB_FLAG)) + { + /* + We have to use a copy function when using a blob with default value + as the we have to calculate the default value before we can use it. + */ + get_tmp_field_src(src, param); + return tmp_table_field_from_field_type(root, table); + } + /* + Same code as in Item_field::create_tmp_field_ex, except no default field + handling + */ + src->set_field(field); + return create_tmp_field_from_item_field(root, table, nullptr, param); +} + + Field *Item_ref::create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) @@ -18097,7 +18166,13 @@ Field *Item_func_sp::create_tmp_field_ex(MEM_ROOT *root, TABLE *table, the record in the original table. If modify_item is 0 then fill_record() will update the temporary table - + @param table_cant_handle_bit_fields + Set to 1 if the temporary table cannot handle bit + fields. Only set for heap tables when the bit field + is part of an index. + @param make_copy_field + Set when using with rollup when we want to have + an exact copy of the field. @retval 0 on error @retval @@ -20162,6 +20237,7 @@ do_select(JOIN *join, Procedure *procedure) if (join->only_const_tables() && !join->need_tmp) { Next_select_func end_select= setup_end_select_func(join, NULL); + /* HAVING will be checked after processing aggregate functions, But WHERE should checked here (we alredy have read tables). @@ -20188,6 +20264,17 @@ do_select(JOIN *join, Procedure *procedure) } else if (join->send_row_on_empty_set()) { + table_map cleared_tables= (table_map) 0; + if (end_select == end_send_group) + { + /* + Was a grouping query but we did not find any rows. In this case + we clear all tables to get null in any referenced fields, + like in case of: + SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL + */ + clear_tables(join, &cleared_tables); + } if (!join->having || join->having->val_int()) { List<Item> *columns_list= (procedure ? &join->procedure_fields_list : @@ -20195,6 +20282,12 @@ do_select(JOIN *join, Procedure *procedure) rc= join->result->send_data_with_check(*columns_list, join->unit, 0) > 0; } + /* + We have to remove the null markings from the tables as this table + may be part of a sub query that is re-evaluated + */ + if (cleared_tables) + unclear_tables(join, &cleared_tables); } /* An error can happen when evaluating the conds @@ -21175,8 +21268,8 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos) if ((table->null_row= MY_TEST((*tab->on_expr_ref)->val_int() == 0))) mark_as_null_row(table); } - if (!table->null_row) - table->maybe_null=0; + if (!table->null_row && ! tab->join->mixed_implicit_grouping) + table->maybe_null= 0; { JOIN *join= tab->join; @@ -26334,7 +26427,7 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg, TABL void JOIN::clear() { - clear_tables(this); + clear_tables(this, 0); copy_fields(&tmp_table_param); if (sum_funcs) diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 2bf99993a50..e699869d644 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -477,6 +477,15 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) */ error= handler_truncate(thd, table_ref, FALSE); + if (error == TRUNCATE_OK && thd->locked_tables_mode && + (table_ref->table->file->ht->flags & + HTON_REQUIRES_CLOSE_AFTER_TRUNCATE)) + { + thd->locked_tables_list.mark_table_for_reopen(thd, table_ref->table); + if (unlikely(thd->locked_tables_list.reopen_tables(thd, true))) + thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + } + /* All effects of a TRUNCATE TABLE operation are committed even if truncation fails in the case of non transactional tables. Thus, the diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index b9bdd04eede..c48e40ad53a 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -679,7 +679,7 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl, st_select_lex *parent_select) { LEX *lex= thd->lex; - select_result *save_result= thd->lex->result; + select_result *save_result= lex->result; uint8 save_derived_tables= lex->derived_tables; thd->lex->result= NULL; @@ -760,13 +760,13 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl, if (arena) thd->restore_active_arena(arena, &backup); - thd->lex->result= save_result; + lex->result= save_result; return wrapper_sl; err: if (arena) thd->restore_active_arena(arena, &backup); - thd->lex->result= save_result; + lex->result= save_result; lex->derived_tables= save_derived_tables; return 0; } @@ -851,14 +851,9 @@ Item_subselect::wrap_tvc_into_select(THD *thd, st_select_lex *tvc_sl) { if (engine->engine_type() == subselect_engine::SINGLE_SELECT_ENGINE) ((subselect_single_select_engine *) engine)->change_select(wrapper_sl); - lex->current_select= wrapper_sl; - return wrapper_sl; - } - else - { - lex->current_select= parent_select; - return 0; } + lex->current_select= parent_select; + return wrapper_sl; } diff --git a/sql/table.h b/sql/table.h index 9eefd915844..58789dc3826 100644 --- a/sql/table.h +++ b/sql/table.h @@ -3202,6 +3202,12 @@ inline void mark_as_null_row(TABLE *table) bfill(table->null_flags,table->s->null_bytes,255); } +inline void unmark_as_null_row(TABLE *table) +{ + table->null_row=0; + table->status= STATUS_NO_RECORD; +} + bool is_simple_order(ORDER *order); class Open_tables_backup; |