From e3a821543047dc773ee4a4f53b439f0957110be5 Mon Sep 17 00:00:00 2001 From: "malff/marcsql@weblab.(none)" <> Date: Mon, 23 Jul 2007 16:23:35 -0600 Subject: Bug#29959 (Non-standard bison syntax in sql_yacc.yy) In sql/sql_yacc.yy, use the %prec construct at the end of rule join_table --- sql/sql_yacc.yy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6fbd521e302..d71e756e91c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5567,7 +5567,7 @@ join_table: so that [INNER | CROSS] JOIN is properly nested as other left-associative joins. */ - table_ref %prec TABLE_REF_PRIORITY normal_join table_ref + table_ref normal_join table_ref %prec TABLE_REF_PRIORITY { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); } | table_ref STRAIGHT_JOIN table_factor { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=1; } -- cgit v1.2.1 From 20e7e9870ad8cab26071cdad80bbfa162b489fc3 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@ibm." <> Date: Wed, 25 Jul 2007 18:38:52 +0400 Subject: Allow mysql.proc to have extra (unknown) fields. This allows 5.0 to work with 5.1 databases. --- sql/sp.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sp.cc b/sql/sp.cc index c0e7d5e2271..75d6fa4618f 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -273,7 +273,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK) goto done; - if (table->s->fields != MYSQL_PROC_FIELD_COUNT) + if (table->s->fields < MYSQL_PROC_FIELD_COUNT) { ret= SP_GET_FIELD_FAILED; goto done; @@ -523,7 +523,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) strxmov(definer, thd->lex->definer->user.str, "@", thd->lex->definer->host.str, NullS); - if (table->s->fields != MYSQL_PROC_FIELD_COUNT) + if (table->s->fields < MYSQL_PROC_FIELD_COUNT) { ret= SP_GET_FIELD_FAILED; goto done; -- cgit v1.2.1 From 11c57540f73aa42099c3036498644bb41def1dbd Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Fri, 27 Jul 2007 16:37:29 +0400 Subject: A fix and a test case for Bug#24918 drop table and lock / inconsistent between perm and temp tables. Review fixes. The original bug report complains that if we locked a temporary table with LOCK TABLES statement, we would not leave LOCK TABLES mode when this temporary table is dropped. Additionally, the bug was escalated when it was discovered than when a temporary transactional table that was previously locked with LOCK TABLES statement was dropped, futher actions with this table, such as UNLOCK TABLES, would lead to a crash. The problem originates from incomplete support of transactional temporary tables. When we added calls to handler::store_lock()/handler::external_lock() to operations that work with such tables, we only covered the normal server code flow and did not cover LOCK TABLES mode. In LOCK TABLES mode, ::external_lock(LOCK) would sometimes be called without matching ::external_lock(UNLOCK), e.g. when a transactional temporary table was dropped. Additionally, this table would be left in the list of LOCKed TABLES. The patch aims to address this inadequacy. Now, whenever an instance of 'handler' is destroyed, we assert that it was priorly external_lock(UNLOCK)-ed. All the places that violate this assert were fixed. This patch introduces no changes in behavior -- the discrepancy in behavior will be fixed when we start calling ::store_lock()/::external_lock() for all tables, regardless whether they are transactional or not, temporary or not. --- sql/handler.h | 40 +++++++++++++++++++++++++++++++++++++--- sql/lock.cc | 35 +++++++++++++++++++++++++++++------ sql/mysql_priv.h | 3 ++- sql/opt_range.cc | 6 +++--- sql/sql_base.cc | 40 ++++++++++++++++++++++++++++++++++++---- sql/sql_class.h | 24 ++++++++++++++++++------ sql/sql_table.cc | 10 +++++----- 7 files changed, 130 insertions(+), 28 deletions(-) (limited to 'sql') diff --git a/sql/handler.h b/sql/handler.h index a3767573178..cd9f9a91008 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -508,6 +508,29 @@ class handler :public Sql_alloc */ virtual int rnd_init(bool scan) =0; virtual int rnd_end() { return 0; } + /** + Is not invoked for non-transactional temporary tables. + + Tells the storage engine that we intend to read or write data + from the table. This call is prefixed with a call to handler::store_lock() + and is invoked only for those handler instances that stored the lock. + + Calls to rnd_init/index_init are prefixed with this call. When table + IO is complete, we call external_lock(F_UNLCK). + A storage engine writer should expect that each call to + ::external_lock(F_[RD|WR]LOCK is followed by a call to + ::external_lock(F_UNLCK). If it is not, it is a bug in MySQL. + + The name and signature originate from the first implementation + in MyISAM, which would call fcntl to set/clear an advisory + lock on the data file in this method. + + @param lock_type F_RDLCK, F_WRLCK, F_UNLCK + + @return non-0 in case of failure, 0 in case of success. + When lock_type is F_UNLCK, the return value is ignored. + */ + virtual int external_lock(THD *thd, int lock_type) { return 0; } public: const handlerton *ht; /* storage engine of this handler */ @@ -548,6 +571,7 @@ public: uint raid_type,raid_chunks; FT_INFO *ft_handler; enum {NONE=0, INDEX, RND} inited; + bool locked; bool auto_increment_column_changed; bool implicit_emptied; /* Can be !=0 only if HEAP */ const COND *pushed_cond; @@ -560,10 +584,11 @@ public: create_time(0), check_time(0), update_time(0), key_used_on_scan(MAX_KEY), active_index(MAX_KEY), ref_length(sizeof(my_off_t)), block_size(0), - raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0), + raid_type(0), ft_handler(0), inited(NONE), + locked(FALSE), implicit_emptied(0), pushed_cond(NULL) {} - virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ } + virtual ~handler(void) { DBUG_ASSERT(locked == FALSE); /* TODO: DBUG_ASSERT(inited == NONE); */ } virtual handler *clone(MEM_ROOT *mem_root); int ha_open(const char *name, int mode, int test_if_locked); void adjust_next_insert_id_after_explicit_value(ulonglong nr); @@ -597,6 +622,13 @@ public: virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return "";} + int ha_external_lock(THD *thd, int lock_type) + { + int rc; + DBUG_ENTER("ha_external_lock"); + locked= lock_type != F_UNLCK; + DBUG_RETURN(external_lock(thd, lock_type)); + } int ha_index_init(uint idx) { DBUG_ENTER("ha_index_init"); @@ -689,7 +721,6 @@ public: virtual int extra_opt(enum ha_extra_function operation, ulong cache_size) { return extra(operation); } virtual int reset() { return extra(HA_EXTRA_RESET); } - virtual int external_lock(THD *thd, int lock_type) { return 0; } virtual void unlock_row() {} virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;} /* @@ -837,6 +868,9 @@ public: /* lock_count() can be more than one if the table is a MERGE */ virtual uint lock_count(void) const { return 1; } + /** + Is not invoked for non-transactional temporary tables. + */ virtual THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type)=0; diff --git a/sql/lock.cc b/sql/lock.cc index 93358e56701..f730ac56d35 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -151,7 +151,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, } thd->proc_info="System lock"; - if (lock_external(thd, tables, count)) + if (sql_lock->table_count && lock_external(thd, sql_lock->table, + sql_lock->table_count)) { /* Clear the lock type of all lock data to avoid reusage. */ reset_lock_data(sql_lock); @@ -246,12 +247,12 @@ static int lock_external(THD *thd, TABLE **tables, uint count) (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT)) lock_type=F_RDLCK; - if ((error=(*tables)->file->external_lock(thd,lock_type))) + if ((error= (*tables)->file->ha_external_lock(thd,lock_type))) { print_lock_error(error, (*tables)->file->table_type()); for (; i-- ; tables--) { - (*tables)->file->external_lock(thd, F_UNLCK); + (*tables)->file->ha_external_lock(thd, F_UNLCK); (*tables)->current_lock=F_UNLCK; } DBUG_RETURN(error); @@ -353,10 +354,28 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) } +/** + Try to find the table in the list of locked tables. + In case of success, unlock the table and remove it from this list. -void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) + @note This function has a legacy side effect: the table is + unlocked even if it is not found in the locked list. + It's not clear if this side effect is intentional or still + desirable. It might lead to unmatched calls to + unlock_external(). Moreover, a discrepancy can be left + unnoticed by the storage engine, because in + unlock_external() we call handler::external_lock(F_UNLCK) only + if table->current_lock is not F_UNLCK. + + @param always_unlock specify explicitly if the legacy side + effect is desired. +*/ + +void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table, + bool always_unlock) { - mysql_unlock_some_tables(thd, &table,1); + if (always_unlock == TRUE) + mysql_unlock_some_tables(thd, &table, /* table count */ 1); if (locked) { reg1 uint i; @@ -370,6 +389,10 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) DBUG_ASSERT(table->lock_position == i); + /* Unlock if not yet unlocked */ + if (always_unlock == FALSE) + mysql_unlock_some_tables(thd, &table, /* table count */ 1); + /* Decrement table_count in advance, making below expressions easier */ old_tables= --locked->table_count; @@ -623,7 +646,7 @@ static int unlock_external(THD *thd, TABLE **table,uint count) if ((*table)->current_lock != F_UNLCK) { (*table)->current_lock = F_UNLCK; - if ((error=(*table)->file->external_lock(thd, F_UNLCK))) + if ((error= (*table)->file->ha_external_lock(thd, F_UNLCK))) { error_code=error; print_lock_error(error_code, (*table)->file->table_type()); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d14aab57489..ca6aa8ecab0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1452,7 +1452,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count); -void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); +void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table, + bool always_unlock); void mysql_lock_abort(THD *thd, TABLE *table); bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 247f0eada49..d978c8882ac 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -972,7 +972,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file, free_file)); file->reset(); - file->external_lock(current_thd, F_UNLCK); + file->ha_external_lock(current_thd, F_UNLCK); file->close(); } } @@ -1142,7 +1142,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) /* Caller will free the memory */ goto failure; /* purecov: inspected */ } - if (file->external_lock(thd, F_RDLCK)) + if (file->ha_external_lock(thd, F_RDLCK)) goto failure; if (!head->no_keyread) { @@ -1152,7 +1152,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) if (file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) || init() || reset()) { - file->external_lock(thd, F_UNLCK); + file->ha_external_lock(thd, F_UNLCK); file->close(); goto failure; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3860dfa1ded..61847a6b168 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1037,6 +1037,31 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name) return 0; // Not a temporary table } + +/** + Drop a temporary table. + + Try to locate the table in the list of thd->temporary_tables. + If the table is found: + - if the table is in thd->locked_tables, unlock it and + remove it from the list of locked tables. Currently only transactional + temporary tables are present in the locked_tables list. + - Close the temporary table, remove its .FRM + - remove the table from the list of temporary tables + + This function is used to drop user temporary tables, as well as + internal tables created in CREATE TEMPORARY TABLE ... SELECT + or ALTER TABLE. Even though part of the work done by this function + is redundant when the table is internal, as long as we + link both internal and user temporary tables into the same + thd->temporary_tables list, it's impossible to tell here whether + we're dealing with an internal or a user temporary table. + + @retval TRUE the table was not found in the list of temporary tables + of this thread + @retval FALSE the table was found and dropped successfully. +*/ + bool close_temporary_table(THD *thd, const char *db, const char *table_name) { TABLE *table,**prev; @@ -1045,6 +1070,11 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name) return 1; table= *prev; *prev= table->next; + /* + If LOCK TABLES list is not empty and contains this table, + unlock the table and remove the table from this list. + */ + mysql_lock_remove(thd, thd->locked_tables, table, FALSE); close_temporary(table, 1); if (thd->slave_thread) --slave_open_temp_tables; @@ -1120,7 +1150,7 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find) !memcmp(list->s->table_cache_key, key, key_length)) { if (thd->locked_tables) - mysql_lock_remove(thd, thd->locked_tables,list); + mysql_lock_remove(thd, thd->locked_tables, list, TRUE); VOID(hash_delete(&open_cache,(byte*) list)); // Close table } else @@ -1151,6 +1181,8 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find) dropped is already unlocked. In the former case it will also remove lock on the table. But one should not rely on this behaviour as it may change in future. + Currently, however, this function is never called for a + table that was locked with LOCK TABLES. */ void drop_open_table(THD *thd, TABLE *table, const char *db_name, @@ -2099,7 +2131,7 @@ bool close_data_tables(THD *thd,const char *db, const char *table_name) if (!strcmp(table->s->table_name, table_name) && !strcmp(table->s->db, db)) { - mysql_lock_remove(thd, thd->locked_tables,table); + mysql_lock_remove(thd, thd->locked_tables, table, TRUE); table->file->close(); table->db_stat=0; } @@ -2239,7 +2271,7 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, instances of this table. */ mysql_lock_abort(thd, table); - mysql_lock_remove(thd, thd->locked_tables, table); + mysql_lock_remove(thd, thd->locked_tables, table, TRUE); /* We want to protect the table from concurrent DDL operations (like RENAME TABLE) until we will re-open and re-lock it. @@ -2343,7 +2375,7 @@ bool drop_locked_tables(THD *thd,const char *db, const char *table_name) if (!strcmp(table->s->table_name, table_name) && !strcmp(table->s->db, db)) { - mysql_lock_remove(thd, thd->locked_tables,table); + mysql_lock_remove(thd, thd->locked_tables, table, TRUE); VOID(hash_delete(&open_cache,(byte*) table)); found=1; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 058f130d4e7..6ffbd9b4ac7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -995,13 +995,25 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1, class Open_tables_state { public: - /* - open_tables - list of regular tables in use by this thread - temporary_tables - list of temp tables in use by this thread - handler_tables - list of tables that were opened with HANDLER OPEN - and are still in use by this thread + /** + List of regular tables in use by this thread. Contains temporary and + base tables that were opened with @see open_tables(). + */ + TABLE *open_tables; + /** + List of temporary tables used by this thread. Contains user-level + temporary tables, created with CREATE TEMPORARY TABLE, and + internal temporary tables, created, e.g., to resolve a SELECT, + or for an intermediate table used in ALTER. + XXX Why are internal temporary tables added to this list? + */ + TABLE *temporary_tables; + /** + List of tables that were opened with HANDLER OPEN and are + still in use by this thread. */ - TABLE *open_tables, *temporary_tables, *handler_tables, *derived_tables; + TABLE *handler_tables; + TABLE *derived_tables; /* During a MySQL session, one can lock tables in two modes: automatic or manual. In automatic mode all necessary tables are locked just before diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e02595836ca..f11082a712c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3791,10 +3791,10 @@ view_err: { VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); - table->file->external_lock(thd, F_WRLCK); + table->file->ha_external_lock(thd, F_WRLCK); alter_table_manage_keys(table, table->file->indexes_are_disabled(), alter_info->keys_onoff); - table->file->external_lock(thd, F_UNLCK); + table->file->ha_external_lock(thd, F_UNLCK); VOID(pthread_mutex_unlock(&LOCK_open)); error= ha_commit_stmt(thd); if (ha_commit(thd)) @@ -3813,7 +3813,7 @@ view_err: The following function call will free the new_table pointer, in close_temporary_table(), so we can safely directly jump to err */ - close_temporary_table(thd,new_db,tmp_name); + close_temporary_table(thd, new_db, tmp_name); goto err; } /* Close lock if this is a transactional table */ @@ -4086,7 +4086,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (!(copy= new Copy_field[to->s->fields])) DBUG_RETURN(-1); /* purecov: inspected */ - if (to->file->external_lock(thd, F_WRLCK)) + if (to->file->ha_external_lock(thd, F_WRLCK)) DBUG_RETURN(-1); /* We need external lock before we can disable/enable keys */ @@ -4238,7 +4238,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, free_io_cache(from); *copied= found_count; *deleted=delete_count; - if (to->file->external_lock(thd,F_UNLCK)) + if (to->file->ha_external_lock(thd,F_UNLCK)) error=1; DBUG_RETURN(error > 0 ? -1 : 0); } -- cgit v1.2.1 From 889b4ebcee0cbbc01cc1d87d04a9c2524dc49408 Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Fri, 27 Jul 2007 16:56:29 +0200 Subject: Bug #29929 LOCK TABLES does not pre-lock tables used in triggers of the locked tables When a table was explicitly locked with LOCK TABLES no associated tables from any related trigger on the subject table were locked. As a result of this the user could experience unexpected locking behavior and statement failures similar to "failed: 1100: Table'xx' was not locked with LOCK TABLES". This patch fixes this problem by making sure triggers are pre-loaded on any statement if the subject table was explicitly locked with LOCK TABLES. --- sql/sql_lex.cc | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- sql/table.cc | 129 ------------------------------------------------------ sql/table.h | 1 - 3 files changed, 132 insertions(+), 133 deletions(-) (limited to 'sql') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c37d77345b6..106dcf88a84 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2035,12 +2035,131 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) /** - Update the parsed tree with information about triggers that - may be fired when executing this statement. + @brief Set the initial purpose of this TABLE_LIST object in the list of used + tables. + + We need to track this information on table-by-table basis, since when this + table becomes an element of the pre-locked list, it's impossible to identify + which SQL sub-statement it has been originally used in. + + E.g.: + + User request: SELECT * FROM t1 WHERE f1(); + FUNCTION f1(): DELETE FROM t2; RETURN 1; + BEFORE DELETE trigger on t2: INSERT INTO t3 VALUES (old.a); + + For this user request, the pre-locked list will contain t1, t2, t3 + table elements, each needed for different DML. + + The trigger event map is updated to reflect INSERT, UPDATE, DELETE, + REPLACE, LOAD DATA, CREATE TABLE .. SELECT, CREATE TABLE .. + REPLACE SELECT statements, and additionally ON DUPLICATE KEY UPDATE + clause. */ void st_lex::set_trg_event_type_for_tables() { + enum trg_event_type trg_event; + + uint8 new_trg_event_map= 0; + + /* + Some auxiliary operations + (e.g. GRANT processing) create TABLE_LIST instances outside + the parser. Additionally, some commands (e.g. OPTIMIZE) change + the lock type for a table only after parsing is done. Luckily, + these do not fire triggers and do not need to pre-load them. + For these TABLE_LISTs set_trg_event_type is never called, and + trg_event_map is always empty. That means that the pre-locking + algorithm will ignore triggers defined on these tables, if + any, and the execution will either fail with an assert in + sql_trigger.cc or with an error that a used table was not + pre-locked, in case of a production build. + + TODO: this usage pattern creates unnecessary module dependencies + and should be rewritten to go through the parser. + Table list instances created outside the parser in most cases + refer to mysql.* system tables. It is not allowed to have + a trigger on a system table, but keeping track of + initialization provides extra safety in case this limitation + is circumvented. + */ + + switch (sql_command) { + case SQLCOM_LOCK_TABLES: + /* + On a LOCK TABLE, all triggers must be pre-loaded for this TABLE_LIST + when opening an associated TABLE. + */ + new_trg_event_map= static_cast + (1 << static_cast(TRG_EVENT_INSERT)) | + static_cast + (1 << static_cast(TRG_EVENT_UPDATE)) | + static_cast + (1 << static_cast(TRG_EVENT_DELETE)); + break; + /* + Basic INSERT. If there is an additional ON DUPLIATE KEY UPDATE + clause, it will be handled later in this method. + */ + case SQLCOM_INSERT: /* fall through */ + case SQLCOM_INSERT_SELECT: + /* + LOAD DATA ... INFILE is expected to fire BEFORE/AFTER INSERT + triggers. + If the statement also has REPLACE clause, it will be + handled later in this method. + */ + case SQLCOM_LOAD: /* fall through */ + /* + REPLACE is semantically equivalent to INSERT. In case + of a primary or unique key conflict, it deletes the old + record and inserts a new one. So we also may need to + fire ON DELETE triggers. This functionality is handled + later in this method. + */ + case SQLCOM_REPLACE: /* fall through */ + case SQLCOM_REPLACE_SELECT: + /* + CREATE TABLE ... SELECT defaults to INSERT if the table or + view already exists. REPLACE option of CREATE TABLE ... + REPLACE SELECT is handled later in this method. + */ + case SQLCOM_CREATE_TABLE: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_INSERT)); + break; + /* Basic update and multi-update */ + case SQLCOM_UPDATE: /* fall through */ + case SQLCOM_UPDATE_MULTI: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_UPDATE)); + break; + /* Basic delete and multi-delete */ + case SQLCOM_DELETE: /* fall through */ + case SQLCOM_DELETE_MULTI: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_DELETE)); + break; + default: + break; + } + + switch (duplicates) { + case DUP_UPDATE: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_UPDATE)); + break; + case DUP_REPLACE: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_DELETE)); + break; + case DUP_ERROR: + default: + break; + } + + /* Do not iterate over sub-selects, only the tables in the outermost SELECT_LEX can be modified, if any. @@ -2049,7 +2168,17 @@ void st_lex::set_trg_event_type_for_tables() while (tables) { - tables->set_trg_event_type(this); + /* + This is a fast check to filter out statements that do + not change data, or tables on the right side, in case of + INSERT .. SELECT, CREATE TABLE .. SELECT and so on. + Here we also filter out OPTIMIZE statement and non-updateable + views, for which lock_type is TL_UNLOCK or TL_READ after + parsing. + */ + if (static_cast(tables->lock_type) >= + static_cast(TL_WRITE_ALLOW_WRITE)) + tables->trg_event_map= new_trg_event_map; tables= tables->next_local; } } diff --git a/sql/table.cc b/sql/table.cc index f24f5c6fbcc..f27076076bf 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1776,135 +1776,6 @@ void st_table::reset_item_list(List *item_list) const } } - -/** - Set the initial purpose of this TABLE_LIST object in the list of - used tables. We need to track this information on table-by- - table basis, since when this table becomes an element of the - pre-locked list, it's impossible to identify which SQL - sub-statement it has been originally used in. - - E.g.: - - User request: SELECT * FROM t1 WHERE f1(); - FUNCTION f1(): DELETE FROM t2; RETURN 1; - BEFORE DELETE trigger on t2: INSERT INTO t3 VALUES (old.a); - - For this user request, the pre-locked list will contain t1, t2, t3 - table elements, each needed for different DML. - - This method is called immediately after parsing for tables - of the table list of the top-level select lex. - - The trigger event map is updated to reflect INSERT, UPDATE, DELETE, - REPLACE, LOAD DATA, CREATE TABLE .. SELECT, CREATE TABLE .. - REPLACE SELECT statements, and additionally ON DUPLICATE KEY UPDATE - clause. -*/ - -void -TABLE_LIST::set_trg_event_type(const st_lex *lex) -{ - enum trg_event_type trg_event; - - /* - Some auxiliary operations - (e.g. GRANT processing) create TABLE_LIST instances outside - the parser. Additionally, some commands (e.g. OPTIMIZE) change - the lock type for a table only after parsing is done. Luckily, - these do not fire triggers and do not need to pre-load them. - For these TABLE_LISTs set_trg_event_type is never called, and - trg_event_map is always empty. That means that the pre-locking - algorithm will ignore triggers defined on these tables, if - any, and the execution will either fail with an assert in - sql_trigger.cc or with an error that a used table was not - pre-locked, in case of a production build. - - TODO: this usage pattern creates unnecessary module dependencies - and should be rewritten to go through the parser. - Table list instances created outside the parser in most cases - refer to mysql.* system tables. It is not allowed to have - a trigger on a system table, but keeping track of - initialization provides extra safety in case this limitation - is circumvented. - */ - - /* - This is a fast check to filter out statements that do - not change data, or tables on the right side, in case of - INSERT .. SELECT, CREATE TABLE .. SELECT and so on. - Here we also filter out OPTIMIZE statement and non-updateable - views, for which lock_type is TL_UNLOCK or TL_READ after - parsing. - */ - if (static_cast(lock_type) < static_cast(TL_WRITE_ALLOW_WRITE)) - return; - - switch (lex->sql_command) { - /* - Basic INSERT. If there is an additional ON DUPLIATE KEY UPDATE - clause, it will be handled later in this method. - */ - case SQLCOM_INSERT: /* fall through */ - case SQLCOM_INSERT_SELECT: - /* - LOAD DATA ... INFILE is expected to fire BEFORE/AFTER INSERT - triggers. - If the statement also has REPLACE clause, it will be - handled later in this method. - */ - case SQLCOM_LOAD: /* fall through */ - /* - REPLACE is semantically equivalent to INSERT. In case - of a primary or unique key conflict, it deletes the old - record and inserts a new one. So we also may need to - fire ON DELETE triggers. This functionality is handled - later in this method. - */ - case SQLCOM_REPLACE: /* fall through */ - case SQLCOM_REPLACE_SELECT: - /* - CREATE TABLE ... SELECT defaults to INSERT if the table or - view already exists. REPLACE option of CREATE TABLE ... - REPLACE SELECT is handled later in this method. - */ - case SQLCOM_CREATE_TABLE: - trg_event= TRG_EVENT_INSERT; - break; - /* Basic update and multi-update */ - case SQLCOM_UPDATE: /* fall through */ - case SQLCOM_UPDATE_MULTI: - trg_event= TRG_EVENT_UPDATE; - break; - /* Basic delete and multi-delete */ - case SQLCOM_DELETE: /* fall through */ - case SQLCOM_DELETE_MULTI: - trg_event= TRG_EVENT_DELETE; - break; - default: - /* - OK to return, since value of 'duplicates' is irrelevant - for non-updating commands. - */ - return; - } - trg_event_map|= static_cast(1 << static_cast(trg_event)); - - switch (lex->duplicates) { - case DUP_UPDATE: - trg_event= TRG_EVENT_UPDATE; - break; - case DUP_REPLACE: - trg_event= TRG_EVENT_DELETE; - break; - case DUP_ERROR: - default: - return; - } - trg_event_map|= static_cast(1 << static_cast(trg_event)); -} - - /* calculate md5 of query diff --git a/sql/table.h b/sql/table.h index f8f7d7f06b7..f411ce489c4 100644 --- a/sql/table.h +++ b/sql/table.h @@ -770,7 +770,6 @@ struct TABLE_LIST void reinit_before_use(THD *thd); Item_subselect *containing_subselect(); - void set_trg_event_type(const st_lex *lex); private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); -- cgit v1.2.1 From 64c5f996d18eb5f990361554299702a27adcb4e6 Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Sun, 29 Jul 2007 14:05:03 +0200 Subject: Clean up patch - Removed unused variable. --- sql/sql_lex.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 106dcf88a84..a62d8b383a5 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2059,8 +2059,6 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) void st_lex::set_trg_event_type_for_tables() { - enum trg_event_type trg_event; - uint8 new_trg_event_map= 0; /* -- cgit v1.2.1 From 80b48aea438babd21f8db508f610630cbd35075e Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 30 Jul 2007 14:22:29 +0400 Subject: Fix a compilation warning. --- sql/handler.h | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/handler.h b/sql/handler.h index cd9f9a91008..2caf9b20945 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -624,7 +624,6 @@ public: int ha_external_lock(THD *thd, int lock_type) { - int rc; DBUG_ENTER("ha_external_lock"); locked= lock_type != F_UNLCK; DBUG_RETURN(external_lock(thd, lock_type)); -- cgit v1.2.1