diff options
author | Monty <monty@mariadb.org> | 2017-12-22 14:56:09 +0200 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2017-12-22 14:56:58 +0200 |
commit | 9cc7789e9084e7d59a43f9560870e496843535f9 (patch) | |
tree | 71f18d4ae038bb59019a7812b22778500b6a8c0c /sql | |
parent | 5b4c8469d5e1988f6f7408fa6c7cc54f9bb1f290 (diff) | |
download | mariadb-git-9cc7789e9084e7d59a43f9560870e496843535f9.tar.gz |
MDEV 13679 Enabled sequences to be used in DEFAULT
Other changes done to get this to work:
- Added 'internal_tables' to TABLE object to list which sequence tables
is needed to use the table.
- Mark any expression using DEFAULT() with LEX->default_used.
This is needed when deciding if we should open internal sequence
tables when a table is opened (we don't need to open sequence tables
if the main table is only used with SELECT).
- Create_and_open_temporary_table() can now also open all internal
sequence tables.
- Added option MYSQL_LOCK_USE_MALLOC to mysql_lock_tables()
to force memory allocation to be used with malloc instead of
memroot.
- Added flag to MYSQL_LOCK to remember if allocation was done with
malloc or memroot (makes code simpler and safer).
- init_one_table_for_prelocking() now takes argument for what lock to
use instead of it's a routine or something else.
- Renamed prelocking placeholders to make them more understandable as
they are now used in more code.
- Changed test in check_lock_and_start_stmt() if found table has correct
locks. The old test didn't work for tables that has lock
TL_WRITE_ALLOW_WRITE, which is what sequence tables are using.
- Added VCOL_NOT_VIRTUAL option to ensure that sequence functions can't
be used with virtual columns
- More sequence tests
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item_func.cc | 40 | ||||
-rw-r--r-- | sql/item_func.h | 32 | ||||
-rw-r--r-- | sql/lock.cc | 10 | ||||
-rw-r--r-- | sql/sp_head.cc | 3 | ||||
-rw-r--r-- | sql/sql_base.cc | 126 | ||||
-rw-r--r-- | sql/sql_base.h | 2 | ||||
-rw-r--r-- | sql/sql_class.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.h | 6 | ||||
-rw-r--r-- | sql/sql_lex.cc | 6 | ||||
-rw-r--r-- | sql/sql_lex.h | 1 | ||||
-rw-r--r-- | sql/sql_table.cc | 12 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 1 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 1 | ||||
-rw-r--r-- | sql/table.cc | 8 | ||||
-rw-r--r-- | sql/table.h | 17 | ||||
-rw-r--r-- | sql/temporary_tables.cc | 12 |
16 files changed, 230 insertions, 51 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index 55d141b9968..ac7ed75e7f9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6686,14 +6686,22 @@ longlong Item_func_nextval::val_int() longlong value; int error; const char *key; - TABLE *table= table_list->table; uint length= get_table_def_key(table_list, &key); - THD *thd= table->in_use; + THD *thd; SEQUENCE_LAST_VALUE *entry; char buff[80]; String key_buff(buff,sizeof(buff), &my_charset_bin); - DBUG_ASSERT(table && table->s->sequence); DBUG_ENTER("Item_func_nextval::val_int"); + update_table(); + DBUG_ASSERT(table && table->s->sequence); + thd= table->in_use; + + if (thd->count_cuted_fields == CHECK_FIELD_EXPRESSION) + { + /* Alter table checking if function works */ + null_value= 0; + DBUG_RETURN(0); + } if (table->s->tmp_table != NO_TMP_TABLE) { @@ -6745,7 +6753,7 @@ void Item_func_nextval::print(String *str, enum_query_type query_type) char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME]; const char *d_name= table_list->db, *t_name= table_list->table_name; bool use_db_name= d_name && d_name[0]; - THD *thd= current_thd; + THD *thd= current_thd; // Don't trust 'table' str->append(func_name()); str->append('('); @@ -6785,12 +6793,14 @@ longlong Item_func_lastval::val_int() const char *key; SEQUENCE_LAST_VALUE *entry; uint length= get_table_def_key(table_list, &key); - THD *thd= table_list->table->in_use; + THD *thd; char buff[80]; String key_buff(buff,sizeof(buff), &my_charset_bin); DBUG_ENTER("Item_func_lastval::val_int"); + update_table(); + thd= table->in_use; - if (table_list->table->s->tmp_table != NO_TMP_TABLE) + if (table->s->tmp_table != NO_TMP_TABLE) { /* Temporary tables has an extra \0 at end to distinguish it from @@ -6809,7 +6819,7 @@ longlong Item_func_lastval::val_int() null_value= 1; DBUG_RETURN(0); } - if (entry->check_version(table_list->table)) + if (entry->check_version(table)) { /* Table droped and re-created, remove current version */ my_hash_delete(&thd->sequences, (uchar*) entry); @@ -6834,10 +6844,20 @@ longlong Item_func_setval::val_int() { longlong value; int error; - TABLE *table= table_list->table; - DBUG_ASSERT(table && table->s->sequence); + THD *thd; DBUG_ENTER("Item_func_setval::val_int"); + update_table(); + DBUG_ASSERT(table && table->s->sequence); + thd= table->in_use; + + if (thd->count_cuted_fields == CHECK_FIELD_EXPRESSION) + { + /* Alter table checking if function works */ + null_value= 0; + DBUG_RETURN(0); + } + value= nextval; error= table->s->sequence->set_value(table, nextval, round, is_used); if (error) @@ -6856,7 +6876,7 @@ void Item_func_setval::print(String *str, enum_query_type query_type) char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME]; const char *d_name= table_list->db, *t_name= table_list->table_name; bool use_db_name= d_name && d_name[0]; - THD *thd= table_list->table->in_use; + THD *thd= current_thd; // Don't trust 'table' str->append(func_name()); str->append('('); diff --git a/sql/item_func.h b/sql/item_func.h index 07c6b5bb8d3..86924384d74 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2981,9 +2981,10 @@ class Item_func_nextval :public Item_longlong_func { protected: TABLE_LIST *table_list; + TABLE *table; public: - Item_func_nextval(THD *thd, TABLE_LIST *table): - Item_longlong_func(thd), table_list(table) {} + Item_func_nextval(THD *thd, TABLE_LIST *table_list_arg): + Item_longlong_func(thd), table_list(table_list_arg) {} longlong val_int(); const char *func_name() const { return "nextval"; } void fix_length_and_dec() @@ -2992,6 +2993,22 @@ public: max_length= MAX_BIGINT_WIDTH; maybe_null= 1; /* In case of errors */ } + /* + update_table() function must be called during the value function + as in case of DEFAULT the sequence table may not yet be open + while fix_fields() are called + */ + void update_table() + { + if (!(table= table_list->table)) + { + /* + If nextval was used in DEFAULT then next_local points to + the table_list used by to open the sequence table + */ + table= table_list->next_local->table; + } + } bool const_item() const { return 0; } Item *get_copy(THD *thd) { return get_item_copy<Item_func_nextval>(thd, this); } @@ -2999,7 +3016,8 @@ public: bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), "()", arg, - VCOL_NON_DETERMINISTIC); + (VCOL_NON_DETERMINISTIC | + VCOL_NOT_VIRTUAL)); } }; @@ -3009,8 +3027,8 @@ public: class Item_func_lastval :public Item_func_nextval { public: - Item_func_lastval(THD *thd, TABLE_LIST *table): - Item_func_nextval(thd, table) {} + Item_func_lastval(THD *thd, TABLE_LIST *table_list_arg): + Item_func_nextval(thd, table_list_arg) {} longlong val_int(); const char *func_name() const { return "lastval"; } Item *get_copy(THD *thd) @@ -3026,9 +3044,9 @@ class Item_func_setval :public Item_func_nextval ulonglong round; bool is_used; public: - Item_func_setval(THD *thd, TABLE_LIST *table, longlong nextval_arg, + Item_func_setval(THD *thd, TABLE_LIST *table_list_arg, longlong nextval_arg, ulonglong round_arg, bool is_used_arg) - : Item_func_nextval(thd, table), + : Item_func_nextval(thd, table_list_arg), nextval(nextval_arg), round(round_arg), is_used(is_used_arg) {} longlong val_int(); diff --git a/sql/lock.cc b/sql/lock.cc index 8e43001e742..f4fc09d35bf 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -294,7 +294,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) if (lock_tables_check(thd, tables, count, flags)) DBUG_RETURN(NULL); - if (!(thd->variables.option_bits & OPTION_TABLE_LOCK)) + if (!(thd->variables.option_bits & OPTION_TABLE_LOCK) && + !(flags & MYSQL_LOCK_USE_MALLOC)) gld_flags|= GET_LOCK_ON_THD; if (! (sql_lock= get_lock_data(thd, tables, count, gld_flags))) @@ -415,7 +416,8 @@ static int lock_external(THD *thd, TABLE **tables, uint count) void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock) { mysql_unlock_tables(thd, sql_lock, - thd->variables.option_bits & OPTION_TABLE_LOCK); + (thd->variables.option_bits & OPTION_TABLE_LOCK) || + !(sql_lock->flags & GET_LOCK_ON_THD)); } @@ -433,7 +435,10 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock) if (sql_lock->lock_count) thr_multi_unlock(sql_lock->locks, sql_lock->lock_count, 0); if (free_lock) + { + DBUG_ASSERT(!(sql_lock->flags & GET_LOCK_ON_THD)); my_free(sql_lock); + } if (!errors) thd->clear_error(); THD_STAGE_INFO(thd, org_stage); @@ -782,6 +787,7 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags) locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1); to= table_buf= sql_lock->table= (TABLE**) (locks + lock_count * 2); sql_lock->table_count= table_count; + sql_lock->flags= flags; for (i=0 ; i < count ; i++) { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index a0f0fb271ef..bcdef10506f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -4654,7 +4654,8 @@ sp_head::add_used_tables_to_table_list(THD *thd, table->init_one_table_for_prelocking(key_buff, stab->db_length, key_buff + stab->db_length + 1, stab->table_name_length, key_buff + stab->db_length + stab->table_name_length + 2, - stab->lock_type, true, belong_to_view, stab->trg_event_map, + stab->lock_type, TABLE_LIST::PRELOCK_ROUTINE, belong_to_view, + stab->trg_event_map, query_tables_last_ptr); tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST)); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b493b7d2b9e..31cb973551f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3528,7 +3528,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, */ if (thd->locked_tables_mode <= LTM_LOCK_TABLES && ! has_prelocking_list && - tables->lock_type >= TL_WRITE_ALLOW_WRITE) + (tables->lock_type >= TL_WRITE_ALLOW_WRITE || thd->lex->default_used)) { bool need_prelocking= FALSE; TABLE_LIST **save_query_tables_last= lex->query_tables_last; @@ -4234,7 +4234,7 @@ static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db, for (; tl; tl= tl->next_global ) { if (tl->lock_type >= lock_type && - tl->prelocking_placeholder == TABLE_LIST::FK && + tl->prelocking_placeholder == TABLE_LIST::PRELOCK_FK && strcmp(tl->db, db->str) == 0 && strcmp(tl->table_name, table->str) == 0) return true; @@ -4243,6 +4243,34 @@ static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db, } +static bool +add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx, + TABLE_LIST *global_table_list, TABLE_LIST *tables) +{ + do + { + TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); + if (!tl) + return TRUE; + tl->init_one_table_for_prelocking(tables->db, + strlen(tables->db), + tables->table_name, + strlen(tables->table_name), + NULL, tables->lock_type, + TABLE_LIST::PRELOCK_NONE, + 0, 0, + &prelocking_ctx->query_tables_last); + /* + Store link to the new table_list that will be used by open so that + Item_func_nextval() can find it + */ + tables->next_local= tl; + } while ((tables= tables->next_global)); + return FALSE; +} + + + /** Defines how prelocking algorithm for DML statements should handle table list elements: @@ -4269,21 +4297,23 @@ bool DML_prelocking_strategy:: handle_table(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) { + TABLE *table= table_list->table; /* We rely on a caller to check that table is going to be changed. */ - DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE); + DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE || + thd->lex->default_used); if (table_list->trg_event_map) { - if (table_list->table->triggers) + if (table->triggers) { *need_prelocking= TRUE; - if (table_list->table->triggers-> + if (table->triggers-> add_tables_and_routines_for_triggers(thd, prelocking_ctx, table_list)) return TRUE; } - if (table_list->table->file->referenced_by_foreign_key()) + if (table->file->referenced_by_foreign_key()) { List <FOREIGN_KEY_INFO> fk_list; List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list); @@ -4292,7 +4322,7 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, arena= thd->activate_stmt_arena_if_needed(&backup); - table_list->table->file->get_parent_foreign_key_list(thd, &fk_list); + table->file->get_parent_foreign_key_list(thd, &fk_list); if (thd->is_error()) { if (arena) @@ -4321,21 +4351,88 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, continue; TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); - tl->init_one_table_for_prelocking(fk->foreign_db->str, fk->foreign_db->length, - fk->foreign_table->str, fk->foreign_table->length, - NULL, lock_type, false, table_list->belong_to_view, - op, &prelocking_ctx->query_tables_last); + tl->init_one_table_for_prelocking(fk->foreign_db->str, + fk->foreign_db->length, + fk->foreign_table->str, + fk->foreign_table->length, + NULL, lock_type, + TABLE_LIST::PRELOCK_FK, + table_list->belong_to_view, op, + &prelocking_ctx->query_tables_last); } if (arena) thd->restore_active_arena(arena, &backup); } } + /* Open any tables used by DEFAULT (like sequence tables) */ + if (table->internal_tables && + ((sql_command_flags[thd->lex->sql_command] & CF_INSERTS_DATA) || + thd->lex->default_used) && + add_internal_tables(thd, prelocking_ctx, table_list, + table->internal_tables)) + { + *need_prelocking= TRUE; + return TRUE; + } return FALSE; } /** + Open all tables used by DEFAULT functions. + + This is different from normal open_and_lock_tables() as we may + already have other tables opened and locked and we have to merge the + new table with the old ones. +*/ + +bool open_and_lock_internal_tables(TABLE *table, bool lock_table) +{ + THD *thd= table->in_use; + TABLE_LIST *tl; + MYSQL_LOCK *save_lock,*new_lock; + DBUG_ENTER("open_internal_tables"); + + /* remove pointer to old select_lex which is already destroyed */ + for (tl= table->internal_tables ; tl ; tl= tl->next_global) + tl->select_lex= 0; + + uint counter; + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); + TABLE_LIST *tmp= table->internal_tables; + DML_prelocking_strategy prelocking_strategy; + + if (open_tables(thd, thd->lex->create_info, &tmp, &counter, 0, + &prelocking_strategy)) + goto err; + + if (lock_table) + { + save_lock= thd->lock; + thd->lock= 0; + if (lock_tables(thd, table->internal_tables, counter, + MYSQL_LOCK_USE_MALLOC)) + goto err; + + if (!(new_lock= mysql_lock_merge(save_lock, thd->lock))) + { + thd->lock= save_lock; + mysql_unlock_tables(thd, save_lock, 1); + /* We don't have to close tables as caller will do that */ + goto err; + } + thd->lock= new_lock; + } + DBUG_RETURN(0); + +err: + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + DBUG_RETURN(1); +} + + +/** Defines how prelocking algorithm for DML statements should handle view - all view routines should be added to the prelocking set. @@ -4486,7 +4583,7 @@ static bool check_lock_and_start_stmt(THD *thd, Prelocking placeholder is not set for TABLE_LIST that are directly used by TOP level statement. */ - DBUG_ASSERT(table_list->prelocking_placeholder == false); + DBUG_ASSERT(table_list->prelocking_placeholder == TABLE_LIST::PRELOCK_NONE); /* TL_WRITE_DEFAULT and TL_READ_DEFAULT are supposed to be parser only @@ -4499,7 +4596,6 @@ static bool check_lock_and_start_stmt(THD *thd, Last argument routine_modifies_data for read_lock_type_for_table() is ignored, as prelocking placeholder will never be set here. */ - DBUG_ASSERT(table_list->prelocking_placeholder == false); if (table_list->lock_type == TL_WRITE_DEFAULT) lock_type= thd->update_lock_default; else if (table_list->lock_type == TL_READ_DEFAULT) @@ -4507,8 +4603,8 @@ static bool check_lock_and_start_stmt(THD *thd, else lock_type= table_list->lock_type; - if ((int) lock_type > (int) TL_WRITE_ALLOW_WRITE && - (int) table_list->table->reginfo.lock_type <= (int) TL_WRITE_ALLOW_WRITE) + if ((int) lock_type >= (int) TL_WRITE_ALLOW_WRITE && + (int) table_list->table->reginfo.lock_type < (int) TL_WRITE_ALLOW_WRITE) { my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->table->alias.c_ptr()); diff --git a/sql/sql_base.h b/sql/sql_base.h index bb33af66590..bf140cb5d17 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -100,6 +100,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update, */ #define MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK 0x1000 #define MYSQL_LOCK_NOT_TEMPORARY 0x2000 +#define MYSQL_LOCK_USE_MALLOC 0x4000 /** Only check THD::killed if waits happen (e.g. wait on MDL, wait on table flush, wait on thr_lock.c locks) while opening and locking table. @@ -257,6 +258,7 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags, uint dt_phases); bool open_tables_only_view_structure(THD *thd, TABLE_LIST *tables, bool can_deadlock); +bool open_and_lock_internal_tables(TABLE *table, bool lock); bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags); int decide_logging_format(THD *thd, TABLE_LIST *tables); void close_thread_table(THD *thd, TABLE **table_ptr); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d0aa0818e99..40cf0f2557f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4688,7 +4688,7 @@ TABLE *find_fk_open_table(THD *thd, const char *db, size_t db_len, { if (t->s->db.length == db_len && t->s->table_name.length == table_len && !strcmp(t->s->db.str, db) && !strcmp(t->s->table_name.str, table) && - t->pos_in_table_list->prelocking_placeholder == TABLE_LIST::FK) + t->pos_in_table_list->prelocking_placeholder == TABLE_LIST::PRELOCK_FK) return t; } return NULL; @@ -6081,7 +6081,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) replicated_tables_count++; if (table->lock_type <= TL_READ_NO_INSERT && - table->prelocking_placeholder != TABLE_LIST::FK) + table->prelocking_placeholder != TABLE_LIST::PRELOCK_FK) has_read_tables= true; else if (table->table->found_next_number_field && (table->lock_type >= TL_WRITE_ALLOW_WRITE)) diff --git a/sql/sql_class.h b/sql/sql_class.h index f78c181fdd5..de56206df4b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -373,8 +373,9 @@ public: typedef struct st_mysql_lock { TABLE **table; - uint table_count,lock_count; THR_LOCK_DATA **locks; + uint table_count,lock_count; + uint flags; } MYSQL_LOCK; @@ -4406,7 +4407,8 @@ public: const char *path, const char *db, const char *table_name, - bool open_in_engine); + bool open_in_engine, + bool open_internal_tables); TABLE *find_temporary_table(const char *db, const char *table_name); TABLE *find_temporary_table(const TABLE_LIST *tl); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6cb065c3985..b40a44b7541 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -196,8 +196,9 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) lex_start(thd); context->init(); if ((!(table_ident= new Table_ident(thd, + &table->s->db, &table->s->table_name, - &table->s->db, TRUE))) || + TRUE))) || (!(table_list= select_lex->add_table_to_list(thd, table_ident, NULL, @@ -737,6 +738,7 @@ void LEX::start(THD *thd_arg) spcont= NULL; proc_list.first= 0; escape_used= FALSE; + default_used= FALSE; query_tables= 0; reset_query_tables_list(FALSE); expr_allows_subselect= TRUE; @@ -3025,7 +3027,7 @@ LEX::LEX() : explain(NULL), result(0), arena_for_set_stmt(0), mem_root_for_set_stmt(0), option_type(OPT_DEFAULT), context_analysis_only(0), sphead(0), - is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX) + default_used(0), is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX) { init_dynamic_array2(&plugins, sizeof(plugin_ref), plugins_static_buffer, diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 92e6dd6c4a2..fac06233592 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2937,6 +2937,7 @@ public: st_alter_tablespace *alter_tablespace_info; bool escape_used; + bool default_used; /* using default() function */ bool is_lex_started; /* If lex_start() did run. For debugging. */ /* diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5bb8d792be5..3f49d094cf0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4894,7 +4894,8 @@ int create_table_impl(THD *thd, if (!frm_only && create_info->tmp_table()) { TABLE *table= thd->create_and_open_tmp_table(create_info->db_type, frm, - path, db, table_name, true); + path, db, table_name, true, + false); if (!table) { @@ -9296,7 +9297,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name, thd->create_and_open_tmp_table(new_db_type, &frm, alter_ctx.get_tmp_path(), alter_ctx.new_db, alter_ctx.tmp_name, - false))) + false, true))) goto err_new_table_cleanup; /* Set markers for fields in TABLE object for altered table. */ @@ -9441,7 +9442,8 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name, } // It's now safe to take the table level lock. - if (lock_tables(thd, table_list, alter_ctx.tables_opened, 0)) + if (lock_tables(thd, table_list, alter_ctx.tables_opened, + MYSQL_LOCK_USE_MALLOC)) goto err_new_table_cleanup; if (ha_create_table(thd, alter_ctx.get_tmp_path(), @@ -9458,7 +9460,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name, thd->create_and_open_tmp_table(new_db_type, &frm, alter_ctx.get_tmp_path(), alter_ctx.new_db, alter_ctx.tmp_name, - true); + true, true); if (!tmp_table) { goto err_new_table_cleanup; @@ -9492,7 +9494,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name, thd->create_and_open_tmp_table(new_db_type, &frm, alter_ctx.get_tmp_path(), alter_ctx.new_db, alter_ctx.tmp_name, - true); + true, true); } if (!new_table) goto err_new_table_cleanup; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bd1b05c2fd1..158c09dded1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9670,6 +9670,7 @@ column_default_non_parenthesized_expr: $3); if ($$ == NULL) MYSQL_YYABORT; + Lex->default_used= TRUE; } | VALUE_SYM '(' simple_ident_nospvar ')' { diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 1de303baf08..2dcfa018dce 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -9500,6 +9500,7 @@ column_default_non_parenthesized_expr: $3); if ($$ == NULL) MYSQL_YYABORT; + Lex->default_used= TRUE; } | VALUE_SYM '(' simple_ident_nospvar ')' { diff --git a/sql/table.cc b/sql/table.cc index f65d7fa123d..112b1c5ab5c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2965,6 +2965,14 @@ unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table, if (error) goto end; + if (lex.current_select->table_list.first[0].next_global) + { + /* We are using NEXT VALUE FOR sequence. Remember table name for open */ + TABLE_LIST *sequence= lex.current_select->table_list.first[0].next_global; + sequence->next_global= table->internal_tables; + table->internal_tables= sequence; + } + vcol_storage.vcol_info->set_vcol_type(vcol->get_vcol_type()); vcol_storage.vcol_info->stored_in_db= vcol->stored_in_db; vcol_storage.vcol_info->name= vcol->name; diff --git a/sql/table.h b/sql/table.h index 72e70bf0312..8d66521b9ef 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1097,6 +1097,8 @@ public: TABLE_LIST *pos_in_table_list;/* Element referring to this table */ /* Position in thd->locked_table_list under LOCK TABLES */ TABLE_LIST *pos_in_locked_tables; + /* Tables used in DEFAULT and CHECK CONSTRAINT (normally sequence tables) */ + TABLE_LIST *internal_tables; /* Not-null for temporary tables only. Non-null values means this table is @@ -1748,6 +1750,11 @@ struct TABLE_LIST { TABLE_LIST() {} /* Remove gcc warning */ + enum prelocking_types + { + PRELOCK_NONE, PRELOCK_ROUTINE, PRELOCK_FK + }; + /** Prepare TABLE_LIST that consists of one table instance to use in open_and_lock_tables @@ -1778,7 +1785,7 @@ struct TABLE_LIST size_t table_name_length_arg, const char *alias_arg, enum thr_lock_type lock_type_arg, - bool routine, + prelocking_types prelocking_type, TABLE_LIST *belong_to_view_arg, uint8 trg_event_map_arg, TABLE_LIST ***last_ptr) @@ -1786,8 +1793,10 @@ struct TABLE_LIST init_one_table(db_name_arg, db_length_arg, table_name_arg, table_name_length_arg, alias_arg, lock_type_arg); cacheable_table= 1; - prelocking_placeholder= routine ? ROUTINE : FK; - open_type= routine ? OT_TEMPORARY_OR_BASE : OT_BASE_ONLY; + prelocking_placeholder= prelocking_type; + open_type= (prelocking_type == PRELOCK_ROUTINE ? + OT_TEMPORARY_OR_BASE : + OT_BASE_ONLY); belong_to_view= belong_to_view_arg; trg_event_map= trg_event_map_arg; @@ -2076,7 +2085,7 @@ struct TABLE_LIST This TABLE_LIST object is just placeholder for prelocking, it will be used for implicit LOCK TABLES only and won't be used in real statement. */ - enum { USER, ROUTINE, FK } prelocking_placeholder; + prelocking_types prelocking_placeholder; /** Indicates that if TABLE_LIST object corresponds to the table/view which requires special handling. diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 2c3cd0fe24e..a5088a012ae 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -65,7 +65,8 @@ TABLE *THD::create_and_open_tmp_table(handlerton *hton, const char *path, const char *db, const char *table_name, - bool open_in_engine) + bool open_in_engine, + bool open_internal_tables) { DBUG_ENTER("THD::create_and_open_tmp_table"); @@ -90,6 +91,15 @@ TABLE *THD::create_and_open_tmp_table(handlerton *hton, /* Free the TMP_TABLE_SHARE. */ free_tmp_table_share(share, false); + DBUG_RETURN(0); + } + + /* Open any related tables */ + if (open_internal_tables && table->internal_tables && + open_and_lock_internal_tables(table, open_in_engine)) + { + drop_temporary_table(table, NULL, false); + DBUG_RETURN(0); } } |