diff options
Diffstat (limited to 'sql/sql_handler.cc')
-rw-r--r-- | sql/sql_handler.cc | 262 |
1 files changed, 179 insertions, 83 deletions
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 4c98c9cefdb..69ea04a170c 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -52,7 +52,7 @@ cursor points at the first record). */ -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_handler.h" #include "sql_base.h" // close_thread_tables @@ -116,7 +116,7 @@ static char *mysql_ha_hash_get_key(SQL_HANDLER *table, size_t *key_len, my_bool first __attribute__((unused))) { *key_len= table->handler_name.length + 1 ; /* include '\0' in comparisons */ - return table->handler_name.str; + return (char*) table->handler_name.str; } @@ -139,6 +139,48 @@ static void mysql_ha_hash_free(SQL_HANDLER *table) delete table; } +static void mysql_ha_close_childs(THD *thd, TABLE_LIST *current_table_list, + TABLE_LIST **next_global) +{ + TABLE_LIST *table_list; + DBUG_ENTER("mysql_ha_close_childs"); + DBUG_PRINT("info",("current_table_list: %p", current_table_list)); + DBUG_PRINT("info",("next_global: %p", *next_global)); + for (table_list = *next_global; table_list; table_list = *next_global) + { + *next_global = table_list->next_global; + DBUG_PRINT("info",("table_name: %s.%s", table_list->table->s->db.str, + table_list->table->s->table_name.str)); + DBUG_PRINT("info",("parent_l: %p", table_list->parent_l)); + if (table_list->parent_l == current_table_list) + { + DBUG_PRINT("info",("found child")); + TABLE *table = table_list->table; + if (table) + { + table->open_by_handler= 0; + if (!table->s->tmp_table) + { + (void) close_thread_table(thd, &table); + thd->mdl_context.release_lock(table_list->mdl_request.ticket); + } + else + { + thd->mark_tmp_table_as_free_for_reuse(table); + } + } + mysql_ha_close_childs(thd, table_list, next_global); + } + else + { + /* the end of child tables */ + *next_global = table_list; + break; + } + } + DBUG_VOID_RETURN; +} + /** Close a HANDLER table. @@ -153,14 +195,19 @@ static void mysql_ha_hash_free(SQL_HANDLER *table) static void mysql_ha_close_table(SQL_HANDLER *handler) { + DBUG_ENTER("mysql_ha_close_table"); THD *thd= handler->thd; TABLE *table= handler->table; - DBUG_ENTER("mysql_ha_close_table"); + TABLE_LIST *current_table_list= NULL, *next_global; /* check if table was already closed */ if (!table) DBUG_VOID_RETURN; + if ((next_global= table->file->get_next_global_for_child())) + current_table_list= next_global->parent_l; + + table->open_by_handler= 0; if (!table->s->tmp_table) { /* Non temporary table. */ @@ -171,15 +218,17 @@ static void mysql_ha_close_table(SQL_HANDLER *handler) } table->file->ha_index_or_rnd_end(); - table->open_by_handler= 0; close_thread_table(thd, &table); + if (current_table_list) + mysql_ha_close_childs(thd, current_table_list, &next_global); thd->mdl_context.release_lock(handler->mdl_request.ticket); } else { /* Must be a temporary table */ table->file->ha_index_or_rnd_end(); - table->open_by_handler= 0; + if (current_table_list) + mysql_ha_close_childs(thd, current_table_list, &next_global); thd->mark_tmp_table_as_free_for_reuse(table); } my_free(handler->lock); @@ -219,7 +268,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) Query_arena backup_arena; DBUG_ENTER("mysql_ha_open"); DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d", - tables->db, tables->table_name, tables->alias, + tables->db.str, tables->table_name.str, tables->alias.str, reopen != 0)); if (thd->locked_tables_mode) @@ -251,12 +300,12 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) } else if (! reopen) /* Otherwise we have 'tables' already. */ { - if (my_hash_search(&thd->handler_tables_hash, (uchar*) tables->alias, - strlen(tables->alias) + 1)) + if (my_hash_search(&thd->handler_tables_hash, (uchar*) tables->alias.str, + tables->alias.length + 1)) { - DBUG_PRINT("info",("duplicate '%s'", tables->alias)); + DBUG_PRINT("info",("duplicate '%s'", tables->alias.str)); DBUG_PRINT("exit",("ERROR")); - my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias); + my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias.str); DBUG_RETURN(TRUE); } } @@ -283,12 +332,12 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) right from the start as open_tables() can't handle properly back-off for such locks. */ - tables->mdl_request.init(MDL_key::TABLE, tables->db, tables->table_name, + tables->mdl_request.init(MDL_key::TABLE, tables->db.str, tables->table_name.str, MDL_SHARED_READ, MDL_TRANSACTION); mdl_savepoint= thd->mdl_context.mdl_savepoint(); /* for now HANDLER can be used only for real TABLES */ - tables->required_type= FRMTYPE_TABLE; + tables->required_type= TABLE_TYPE_NORMAL; /* We use open_tables() here, rather than, say, @@ -298,7 +347,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) error= (thd->open_temporary_tables(tables) || open_tables(thd, &tables, &counter, 0)); - if (error) + if (unlikely(error)) goto err; table= tables->table; @@ -311,29 +360,39 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) goto err; } - if (tables->mdl_request.ticket && - thd->mdl_context.has_lock(mdl_savepoint, tables->mdl_request.ticket)) + DBUG_PRINT("info",("clone_tickets start")); + for (TABLE_LIST *table_list= tables; table_list; + table_list= table_list->next_global) + { + DBUG_PRINT("info",("table_list %s.%s", table_list->table->s->db.str, + table_list->table->s->table_name.str)); + if (table_list->mdl_request.ticket && + thd->mdl_context.has_lock(mdl_savepoint, table_list->mdl_request.ticket)) { + DBUG_PRINT("info",("clone_tickets")); /* The ticket returned is within a savepoint. Make a copy. */ - error= thd->mdl_context.clone_ticket(&tables->mdl_request); - tables->table->mdl_ticket= tables->mdl_request.ticket; - if (error) + error= thd->mdl_context.clone_ticket(&table_list->mdl_request); + table_list->table->mdl_ticket= table_list->mdl_request.ticket; + if (unlikely(error)) goto err; } + } + DBUG_PRINT("info",("clone_tickets end")); if (! reopen) { /* copy data to sql_handler */ if (!(sql_handler= new SQL_HANDLER(thd))) goto err; - init_alloc_root(&sql_handler->mem_root, 1024, 0, MYF(MY_THREAD_SPECIFIC)); + init_alloc_root(&sql_handler->mem_root, "sql_handler", 1024, 0, + MYF(MY_THREAD_SPECIFIC)); - sql_handler->db.length= strlen(tables->db); - sql_handler->table_name.length= strlen(tables->table_name); - sql_handler->handler_name.length= strlen(tables->alias); + sql_handler->db.length= tables->db.length; + sql_handler->table_name.length= tables->table_name.length; + sql_handler->handler_name.length= tables->alias.length; if (!(my_multi_malloc(MY_WME, - &sql_handler->db.str, + &sql_handler->base_data, (uint) sql_handler->db.length + 1, &sql_handler->table_name.str, (uint) sql_handler->table_name.length + 1, @@ -341,12 +400,12 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) (uint) sql_handler->handler_name.length + 1, NullS))) goto err; - sql_handler->base_data= sql_handler->db.str; // Free this - memcpy(sql_handler->db.str, tables->db, sql_handler->db.length +1); - memcpy(sql_handler->table_name.str, tables->table_name, - sql_handler->table_name.length+1); - memcpy(sql_handler->handler_name.str, tables->alias, - sql_handler->handler_name.length +1); + sql_handler->db.str= sql_handler->base_data; + memcpy((char*) sql_handler->db.str, tables->db.str, tables->db.length +1); + memcpy((char*) sql_handler->table_name.str, tables->table_name.str, + tables->table_name.length+1); + memcpy((char*) sql_handler->handler_name.str, tables->alias.str, + tables->alias.length +1); /* add to hash */ if (my_hash_insert(&thd->handler_tables_hash, (uchar*) sql_handler)) @@ -369,8 +428,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) thd->set_n_backup_active_arena(&sql_handler->arena, &backup_arena); error= table->fill_item_list(&sql_handler->fields); thd->restore_active_arena(&sql_handler->arena, &backup_arena); - - if (error) + if (unlikely(error)) goto err; /* Always read all columns */ @@ -380,26 +438,37 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) /* Restore the state. */ thd->set_open_tables(backup_open_tables); + DBUG_PRINT("info",("set_lock_duration start")); if (sql_handler->mdl_request.ticket) { thd->mdl_context.set_lock_duration(sql_handler->mdl_request.ticket, MDL_EXPLICIT); thd->mdl_context.set_needs_thr_lock_abort(TRUE); } + for (TABLE_LIST *table_list= tables->next_global; table_list; + table_list= table_list->next_global) + { + DBUG_PRINT("info",("table_list %s.%s", table_list->table->s->db.str, + table_list->table->s->table_name.str)); + if (table_list->mdl_request.ticket) + { + thd->mdl_context.set_lock_duration(table_list->mdl_request.ticket, + MDL_EXPLICIT); + thd->mdl_context.set_needs_thr_lock_abort(TRUE); + } + } + DBUG_PRINT("info",("set_lock_duration end")); /* - Assert that the above check prevents opening of views and merge tables. - For temporary tables, TABLE::next can be set even if only one table - was opened for HANDLER as it is used to link them together. - */ - DBUG_ASSERT(sql_handler->table->next == NULL || - sql_handler->table->s->tmp_table); - /* If it's a temp table, don't reset table->query_id as the table is being used by this handler. For non-temp tables we use this flag in asserts. */ - table->open_by_handler= 1; + for (TABLE_LIST *table_list= tables; table_list; + table_list= table_list->next_global) + { + table_list->table->open_by_handler= 1; + } /* Safety, cleanup the pointer to satisfy MDL assertions. */ tables->mdl_request.ticket= NULL; @@ -453,7 +522,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables) SQL_HANDLER *handler; DBUG_ENTER("mysql_ha_close"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", - tables->db, tables->table_name, tables->alias)); + tables->db.str, tables->table_name.str, tables->alias.str)); if (thd->locked_tables_mode) { @@ -462,15 +531,15 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables) } if ((my_hash_inited(&thd->handler_tables_hash)) && (handler= (SQL_HANDLER*) my_hash_search(&thd->handler_tables_hash, - (uchar*) tables->alias, - strlen(tables->alias) + 1))) + (const uchar*) tables->alias.str, + tables->alias.length + 1))) { mysql_ha_close_table(handler); my_hash_delete(&thd->handler_tables_hash, (uchar*) handler); } else { - my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER"); + my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias.str, "HANDLER"); DBUG_PRINT("exit",("ERROR")); DBUG_RETURN(TRUE); } @@ -497,13 +566,13 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables) @return handler */ -SQL_HANDLER *mysql_ha_find_handler(THD *thd, const char *name) +static SQL_HANDLER *mysql_ha_find_handler(THD *thd, const LEX_CSTRING *name) { SQL_HANDLER *handler; if ((my_hash_inited(&thd->handler_tables_hash)) && (handler= (SQL_HANDLER*) my_hash_search(&thd->handler_tables_hash, - (uchar*) name, - strlen(name) + 1))) + (const uchar*) name->str, + name->length + 1))) { DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' table: %p", handler->db.str, @@ -513,9 +582,8 @@ SQL_HANDLER *mysql_ha_find_handler(THD *thd, const char *name) { /* The handler table has been closed. Re-open it. */ TABLE_LIST tmp; - tmp.init_one_table(handler->db.str, handler->db.length, - handler->table_name.str, handler->table_name.length, - handler->handler_name.str, TL_READ); + tmp.init_one_table(&handler->db, &handler->table_name, + &handler->handler_name, TL_READ); if (mysql_ha_open(thd, &tmp, handler)) { @@ -526,7 +594,7 @@ SQL_HANDLER *mysql_ha_find_handler(THD *thd, const char *name) } else { - my_error(ER_UNKNOWN_TABLE, MYF(0), name, "HANDLER"); + my_error(ER_UNKNOWN_TABLE, MYF(0), name->str, "HANDLER"); return 0; } return handler; @@ -551,8 +619,8 @@ SQL_HANDLER *mysql_ha_find_handler(THD *thd, const char *name) static bool mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, - enum enum_ha_read_modes mode, char *keyname, - List<Item> *key_expr, + enum enum_ha_read_modes mode, const char *keyname, + List<Item> *key_expr, enum ha_rkey_function ha_rkey_mode, Item *cond, bool in_prepare) { THD *thd= handler->thd; @@ -562,8 +630,7 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, /* This can only be true for temp tables */ if (table->query_id != thd->query_id) cond->cleanup(); // File was reopened - if ((!cond->fixed && - cond->fix_fields(thd, &cond)) || cond->check_cols(1)) + if (cond->fix_fields_if_needed_for_bool(thd, &cond)) return 1; } @@ -573,7 +640,7 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, if (handler->keyno < 0 || my_strcasecmp(&my_charset_latin1, keyname, - table->s->key_info[handler->keyno].name)) + table->s->key_info[handler->keyno].name.str)) { if ((handler->keyno= find_type(keyname, &table->s->keynames, FIND_TYPE_NO_PREFIX) - 1) < 0) @@ -594,6 +661,18 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, Item *item; key_part_map keypart_map; uint key_len; + const KEY *c_key= table->s->key_info + handler->keyno; + + if ((c_key->flags & HA_SPATIAL) || + c_key->algorithm == HA_KEY_ALG_FULLTEXT || + (ha_rkey_mode != HA_READ_KEY_EXACT && + (table->file->index_flags(handler->keyno, 0, TRUE) & + (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE)) == 0)) + { + my_error(ER_KEY_DOESNT_SUPPORT, MYF(0), + table->file->index_type(handler->keyno), keyinfo->name); + return 1; + } if (key_expr->elements > keyinfo->user_defined_key_parts) { @@ -601,14 +680,23 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, keyinfo->user_defined_key_parts); return 1; } + + if (key_expr->elements < keyinfo->user_defined_key_parts && + (table->file->index_flags(handler->keyno, 0, TRUE) & + HA_ONLY_WHOLE_INDEX)) + { + my_error(ER_KEY_DOESNT_SUPPORT, MYF(0), + table->file->index_type(handler->keyno), keyinfo->name); + return 1; + } + for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++) { my_bitmap_map *old_map; /* note that 'item' can be changed by fix_fields() call */ - if ((!item->fixed && - item->fix_fields(thd, it_ke.ref())) || - (item= *it_ke.ref())->check_cols(1)) + if (item->fix_fields_if_needed_for_scalar(thd, it_ke.ref())) return 1; + item= *it_ke.ref(); if (item->used_tables() & ~(RAND_TABLE_BIT | PARAM_TABLE_BIT)) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"HANDLER ... READ"); @@ -673,7 +761,7 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, */ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, - enum enum_ha_read_modes mode, char *keyname, + enum enum_ha_read_modes mode, const char *keyname, List<Item> *key_expr, enum ha_rkey_function ha_rkey_mode, Item *cond, ha_rows select_limit_cnt, ha_rows offset_limit_cnt) @@ -689,7 +777,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, MDL_deadlock_and_lock_abort_error_handler sql_handler_lock_error; DBUG_ENTER("mysql_ha_read"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", - tables->db, tables->table_name, tables->alias)); + tables->db.str, tables->table_name.str, tables->alias.str)); if (thd->locked_tables_mode) { @@ -698,7 +786,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } retry: - if (!(handler= mysql_ha_find_handler(thd, tables->alias))) + if (!(handler= mysql_ha_find_handler(thd, &tables->alias))) goto err0; table= handler->table; @@ -709,8 +797,14 @@ retry: { int lock_error; - if (handler->lock->lock_count > 0) - handler->lock->locks[0]->type= handler->lock->locks[0]->org_type; + THR_LOCK_DATA **pos,**end; + for (pos= handler->lock->locks, + end= handler->lock->locks + handler->lock->lock_count; + pos < end; + pos++) + { + pos[0]->type= pos[0]->org_type; + } /* save open_tables state */ TABLE* backup_open_tables= thd->open_tables; @@ -765,11 +859,12 @@ retry: goto retry; } - if (lock_error) + if (unlikely(lock_error)) goto err0; // mysql_lock_tables() printed error message already } - if (mysql_ha_fix_cond_and_key(handler, mode, keyname, key_expr, cond, 0)) + if (mysql_ha_fix_cond_and_key(handler, mode, keyname, key_expr, + ha_rkey_mode, cond, 0)) goto err; mode= handler->mode; keyno= handler->keyno; @@ -807,14 +902,14 @@ retry: case RFIRST: if (keyname) { - if (!(error= table->file->ha_index_or_rnd_end()) && - !(error= table->file->ha_index_init(keyno, 1))) + if (likely(!(error= table->file->ha_index_or_rnd_end())) && + likely(!(error= table->file->ha_index_init(keyno, 1)))) error= table->file->ha_index_first(table->record[0]); } else { - if (!(error= table->file->ha_index_or_rnd_end()) && - !(error= table->file->ha_rnd_init(1))) + if (likely(!(error= table->file->ha_index_or_rnd_end())) && + likely(!(error= table->file->ha_rnd_init(1)))) error= table->file->ha_rnd_next(table->record[0]); } mode= RNEXT; @@ -833,8 +928,8 @@ retry: /* else fall through */ case RLAST: DBUG_ASSERT(keyname != 0); - if (!(error= table->file->ha_index_or_rnd_end()) && - !(error= table->file->ha_index_init(keyno, 1))) + if (likely(!(error= table->file->ha_index_or_rnd_end())) && + likely(!(error= table->file->ha_index_init(keyno, 1)))) error= table->file->ha_index_last(table->record[0]); mode=RPREV; break; @@ -848,13 +943,13 @@ retry: { DBUG_ASSERT(keyname != 0); - if (!(key= (uchar*) thd->calloc(ALIGN_SIZE(handler->key_len)))) + if (unlikely(!(key= (uchar*) thd->calloc(ALIGN_SIZE(handler->key_len))))) goto err; - if ((error= table->file->ha_index_or_rnd_end())) + if (unlikely((error= table->file->ha_index_or_rnd_end()))) break; key_copy(key, table->record[0], table->key_info + keyno, handler->key_len); - if (!(error= table->file->ha_index_init(keyno, 1))) + if (unlikely(!(error= table->file->ha_index_init(keyno, 1)))) error= table->file->ha_index_read_map(table->record[0], key, handler->keypart_map, ha_rkey_mode); @@ -867,17 +962,15 @@ retry: goto err; } - if (error) + if (unlikely(error)) { - if (error == HA_ERR_RECORD_DELETED) - continue; if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) { /* Don't give error in the log file for some expected problems */ if (error != HA_ERR_RECORD_CHANGED && error != HA_ERR_WRONG_COMMAND) sql_print_error("mysql_ha_read: Got error %d when reading " "table '%s'", - error, tables->table_name); + error, tables->table_name.str); table->file->print_error(error,MYF(0)); table->file->ha_index_or_rnd_end(); goto err; @@ -928,16 +1021,19 @@ err0: */ SQL_HANDLER *mysql_ha_read_prepare(THD *thd, TABLE_LIST *tables, - enum enum_ha_read_modes mode, char *keyname, - List<Item> *key_expr, Item *cond) + enum enum_ha_read_modes mode, + const char *keyname, + List<Item> *key_expr, enum ha_rkey_function ha_rkey_mode, + Item *cond) { SQL_HANDLER *handler; DBUG_ENTER("mysql_ha_read_prepare"); - if (!(handler= mysql_ha_find_handler(thd, tables->alias))) + if (!(handler= mysql_ha_find_handler(thd, &tables->alias))) DBUG_RETURN(0); tables->table= handler->table; // This is used by fix_fields handler->table->pos_in_table_list= tables; - if (mysql_ha_fix_cond_and_key(handler, mode, keyname, key_expr, cond, 1)) + if (mysql_ha_fix_cond_and_key(handler, mode, keyname, key_expr, + ha_rkey_mode, cond, 1)) DBUG_RETURN(0); DBUG_RETURN(handler); } @@ -970,7 +1066,7 @@ static SQL_HANDLER *mysql_ha_find_match(THD *thd, TABLE_LIST *tables) { if (tables->is_anonymous_derived_table()) continue; - if ((! *tables->db || + if ((! tables->db.str[0] || ! my_strcasecmp(&my_charset_latin1, hash_tables->db.str, tables->get_db_name())) && ! my_strcasecmp(&my_charset_latin1, hash_tables->table_name.str, |