mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
14b1f91ba4
crash if referencing a table" and several other related bugs. Fix for bug #11834 "Re-execution of prepared statement with dropped function crashes server." which was spotted during work on previous bugs. Also couple of nice cleanups: - Replaced two separate hashes for stored routines used by statement with one. - Now instead of doing one pass through all routines used in statement for caching them and then doing another pass for adding their tables to table list, we do only one pass during which do both things. mysql-test/r/sp-error.result: Added test for bug #11834 "Re-execution of prepared statement with dropped function crashes server" also covering handling of prepared statements which use stored functions but does not require prelocking. mysql-test/r/sp.result: Updated test for LOCK TABLES with views in table list. (Old version of statement used in this test will work ok now, since prelocking algorithm was tuned and will lock only one multi-set of tables for each routine even if this routine is used in several different views). mysql-test/r/trigger.result: Added several tests for triggers using tables. mysql-test/t/sp-error.test: Added test for bug #11834 "Re-execution of prepared statement with dropped function crashes server" also covering handling of prepared statements which use stored functions but does not require prelocking. mysql-test/t/sp.test: Updated comment about recursive views to reflect current situation. Updated test for LOCK TABLES with views in table list. (Old version of statement used in this test will work ok now, since prelocking algorithm was tuned and will lock only one multi-set of tables for each routine even if this routine is used in several different views). mysql-test/t/trigger.test: Added several tests for triggers using tables. sql/item_func.cc: Item_func_sp::cleanup(): By next statement execution stored function can be dropped or altered so we can't assume that sp_head object for it will be still valid. sql/sp.cc: - Added Sroutine_hash_entry structure that represents element in the set of stored routines used by statement or routine. We can't as before use LEX_STRING for this purprose because we want link all elements of this set in list. - Replaced sp_add_to_hash() with sp_add_used_routine() which takes into account that now we use one hash for stored routines used by statement instead of two and which mantains list linking all elelemnts in this hash. - Renamed sp_merge_hash() to sp_update_sp_used_routines(). - Introduced sp_update_stmt_used_routines() for adding elements to the set of routines used by statement from another similar set for statement or routine. This function will also mantain list linking elements of destination set. - Now instead of one sp_cache_routines() function we have family of sp_cache_routines_and_add_tables() functions which are also responsible for adding tables used by routines being cached to statement table list. Nice optimization - thanks to list linking all elements in the hash of routines used by statement we don't need to perform several iterations over this hash (as it was before in cases when we have added new elements to it). sql/sp.h: Added declarations of functions used for manipulations with set (hash) of stored routines used by statement. sql/sp_head.cc: sp_name::init_qname(): Now sp_name also holds key identifying routine in the set (hash) of stored routines used by statement. sp_head: Instead of two separate hashes sp_funs/m_spprocs representing sets of stored routines used by this routine we use one hash - m_sroutines. sp_instr_set_trigger_field: Added support for subqueries in assignments to row accessors in triggers. Removed definition of sp_add_sp_tables_to_table_list() and auxilary functions since now we don't have separate stage on which we add tables used by routines used by statement to table list for prelocking. We do it on the same stage as we load those routines in SP cache. So all this functionality moved to sp_cache_routines_and_add_tables() family of functions. sql/sp_head.h: sp_name: Now this class also holds key identifying routine in the set (hash) of stored routines used by statement. sp_head: Instead of two separate hashes sp_funs/m_spprocs representing sets of stored routines used by this routine we use one hash - m_sroutines. sp_instr_set_trigger_field: Added support for subqueries in assignments to row accessors in triggers. Removed declaration of sp_add_sp_tables_to_table_list() since now we don't have separate stage on which we add tables used by routines used by statement to table list for prelocking. We do it on the same stage as we load those routines in SP cache. sql/sql_base.cc: open_tables(): - LEX::spfuns/spprocs hashes were replaced with one LEX::sroutines hash. - Now instead of doing one pass through all routines used in statement for caching them and then doing another pass for adding their tables to table list, we do only one pass during which do both things. It is easy to do since all routines in the set of routines used by statement are linked in the list. This also allows us to calculate table list for prelocking more precisely. - Now triggers properly inform prelocking algorithm about tables they use. sql/sql_lex.cc: lex_start(): Replaced LEX::spfuns/spprocs with with one LEX::sroutines hash. Added LEX::sroutines_list list linking all elements in this hash. st_lex::st_lex(): Moved definition of LEX constructor to sql_lex.cc file to be able use sp_sroutine_key declaration from sp.h in it. sql/sql_lex.h: LEX: Replaced two separate hashes for stored routines used by statement with one. Added list linking all elements in this hash to be able to iterate through all elements and add new elements to this hash at the same time. Moved constructor definition to sql_lex.cc. sql/sql_parse.cc: mysql_execute_command(): Replaced LEX::spfuns/spprocs with one LEX::sroutines hash. sql/sql_trigger.cc: Added missing GNU GPL notice. Table_triggers_list::check_n_load() Added initialization of sroutines_key which stores key representing triggers of this table in the set (hash) of routines used by this statement. sql/sql_trigger.h: Added missing GNU GPL notice. Table_triggers_list: Added sroutines_key member to store key representing triggers of this table in the set (hash) of routines used by this statement. Declared sp_cache_routines_and_add_tables_for_triggers() as friend since it needs access to sroutines_key and trigger bodies. sql/sql_yacc.yy: - Now we use sp_add_used_routine() instead of sp_add_to_hash() for adding elements to the set of stored routines used in statement. - Enabled support of subqueries as right sides in assignments to triggers' row accessors.
145 lines
4.5 KiB
C++
145 lines
4.5 KiB
C++
/* Copyright (C) 2004-2005 MySQL AB
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
/*
|
|
This class holds all information about triggers of table.
|
|
|
|
QQ: Will it be merged into TABLE in future ?
|
|
*/
|
|
class Table_triggers_list: public Sql_alloc
|
|
{
|
|
/* Triggers as SPs grouped by event, action_time */
|
|
sp_head *bodies[3][2];
|
|
/*
|
|
Copy of TABLE::Field array with field pointers set to TABLE::record[1]
|
|
buffer instead of TABLE::record[0] (used for OLD values in on UPDATE
|
|
trigger and DELETE trigger when it is called for REPLACE).
|
|
*/
|
|
Field **record1_field;
|
|
/*
|
|
During execution of trigger new_field and old_field should point to the
|
|
array of fields representing new or old version of row correspondingly
|
|
(so it can point to TABLE::field or to Tale_triggers_list::record1_field)
|
|
*/
|
|
Field **new_field;
|
|
Field **old_field;
|
|
/* TABLE instance for which this triggers list object was created */
|
|
TABLE *table;
|
|
/*
|
|
Names of triggers.
|
|
Should correspond to order of triggers on definitions_list,
|
|
used in CREATE/DROP TRIGGER for looking up trigger by name.
|
|
*/
|
|
List<LEX_STRING> names_list;
|
|
/*
|
|
Key representing triggers for this table in set of all stored
|
|
routines used by statement.
|
|
TODO: We won't need this member once triggers namespace will be
|
|
database-wide instead of table-wide because then we will be able
|
|
to use key based on sp_name as for other stored routines.
|
|
*/
|
|
LEX_STRING sroutines_key;
|
|
|
|
public:
|
|
/*
|
|
Field responsible for storing triggers definitions in file.
|
|
It have to be public because we are using it directly from parser.
|
|
*/
|
|
List<LEX_STRING> definitions_list;
|
|
|
|
Table_triggers_list(TABLE *table_arg):
|
|
record1_field(0), table(table_arg)
|
|
{
|
|
bzero((char *)bodies, sizeof(bodies));
|
|
}
|
|
~Table_triggers_list();
|
|
|
|
bool create_trigger(THD *thd, TABLE_LIST *table);
|
|
bool drop_trigger(THD *thd, TABLE_LIST *table);
|
|
bool process_triggers(THD *thd, trg_event_type event,
|
|
trg_action_time_type time_type,
|
|
bool old_row_is_record1)
|
|
{
|
|
int res= 0;
|
|
|
|
if (bodies[event][time_type])
|
|
{
|
|
bool save_in_sub_stmt= thd->transaction.in_sub_stmt;
|
|
#ifndef EMBEDDED_LIBRARY
|
|
/* Surpress OK packets in case if we will execute statements */
|
|
my_bool nsok= thd->net.no_send_ok;
|
|
thd->net.no_send_ok= TRUE;
|
|
#endif
|
|
|
|
if (old_row_is_record1)
|
|
{
|
|
old_field= record1_field;
|
|
new_field= table->field;
|
|
}
|
|
else
|
|
{
|
|
new_field= record1_field;
|
|
old_field= table->field;
|
|
}
|
|
|
|
/*
|
|
FIXME: We should juggle with security context here (because trigger
|
|
should be invoked with creator rights).
|
|
*/
|
|
/*
|
|
We disable binlogging, as in SP/functions, even though currently
|
|
triggers can't do updates. When triggers can do updates, someone
|
|
should add such a trigger to rpl_sp.test to verify that the update
|
|
does NOT go into binlog.
|
|
*/
|
|
tmp_disable_binlog(thd);
|
|
thd->transaction.in_sub_stmt= TRUE;
|
|
|
|
res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
|
|
|
|
thd->transaction.in_sub_stmt= save_in_sub_stmt;
|
|
reenable_binlog(thd);
|
|
|
|
#ifndef EMBEDDED_LIBRARY
|
|
thd->net.no_send_ok= nsok;
|
|
#endif
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static bool check_n_load(THD *thd, const char *db, const char *table_name,
|
|
TABLE *table);
|
|
|
|
bool has_delete_triggers()
|
|
{
|
|
return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
|
|
bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]);
|
|
}
|
|
|
|
bool has_before_update_triggers()
|
|
{
|
|
return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]);
|
|
}
|
|
|
|
friend class Item_trigger_field;
|
|
friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
|
|
Table_triggers_list *triggers);
|
|
|
|
private:
|
|
bool prepare_record1_accessors(TABLE *table);
|
|
};
|