summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorkostja@bodhi.(none) <>2007-07-31 20:03:52 +0400
committerkostja@bodhi.(none) <>2007-07-31 20:03:52 +0400
commit1bf318b89558b7b18b9cf203fb0071de5b2b2580 (patch)
treee01a858aa56e916213cf8bdb5392ddf4dce83814 /sql
parent81905ee14fdfd83a33154103d854e9a773ae738c (diff)
parent80b48aea438babd21f8db508f610630cbd35075e (diff)
downloadmariadb-git-1bf318b89558b7b18b9cf203fb0071de5b2b2580.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into bodhi.(none):/opt/local/work/mysql-5.0-runtime
Diffstat (limited to 'sql')
-rw-r--r--sql/handler.h39
-rw-r--r--sql/lock.cc35
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/opt_range.cc6
-rw-r--r--sql/sp.cc4
-rw-r--r--sql/sql_base.cc40
-rw-r--r--sql/sql_class.h24
-rw-r--r--sql/sql_lex.cc133
-rw-r--r--sql/sql_table.cc6
-rw-r--r--sql/sql_yacc.yy2
-rw-r--r--sql/table.cc129
-rw-r--r--sql/table.h1
12 files changed, 260 insertions, 162 deletions
diff --git a/sql/handler.h b/sql/handler.h
index a3767573178..2caf9b20945 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,12 @@ public:
virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return "";}
+ int ha_external_lock(THD *thd, int lock_type)
+ {
+ 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 +720,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 +867,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/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;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 911e8d4d1f5..3cd0de922e5 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_lex.cc b/sql/sql_lex.cc
index c37d77345b6..a62d8b383a5 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2035,12 +2035,129 @@ 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()
{
+ 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<uint8>
+ (1 << static_cast<int>(TRG_EVENT_INSERT)) |
+ static_cast<uint8>
+ (1 << static_cast<int>(TRG_EVENT_UPDATE)) |
+ static_cast<uint8>
+ (1 << static_cast<int>(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<uint8>
+ (1 << static_cast<int>(TRG_EVENT_INSERT));
+ break;
+ /* Basic update and multi-update */
+ case SQLCOM_UPDATE: /* fall through */
+ case SQLCOM_UPDATE_MULTI:
+ new_trg_event_map|= static_cast<uint8>
+ (1 << static_cast<int>(TRG_EVENT_UPDATE));
+ break;
+ /* Basic delete and multi-delete */
+ case SQLCOM_DELETE: /* fall through */
+ case SQLCOM_DELETE_MULTI:
+ new_trg_event_map|= static_cast<uint8>
+ (1 << static_cast<int>(TRG_EVENT_DELETE));
+ break;
+ default:
+ break;
+ }
+
+ switch (duplicates) {
+ case DUP_UPDATE:
+ new_trg_event_map|= static_cast<uint8>
+ (1 << static_cast<int>(TRG_EVENT_UPDATE));
+ break;
+ case DUP_REPLACE:
+ new_trg_event_map|= static_cast<uint8>
+ (1 << static_cast<int>(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 +2166,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<int>(tables->lock_type) >=
+ static_cast<int>(TL_WRITE_ALLOW_WRITE))
+ tables->trg_event_map= new_trg_event_map;
tables= tables->next_local;
}
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 7db79543016..cc786c741c1 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3811,7 +3811,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 */
@@ -4084,7 +4084,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 */
@@ -4236,7 +4236,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);
}
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; }
diff --git a/sql/table.cc b/sql/table.cc
index ce894e6910f..96ab9cb111e 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1781,135 +1781,6 @@ void st_table::reset_item_list(List<Item> *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<int>(lock_type) < static_cast<int>(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<uint8>(1 << static_cast<int>(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<uint8>(1 << static_cast<int>(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);