mirror of
https://github.com/MariaDB/server.git
synced 2025-01-23 07:14:17 +01:00
ac9f68b9fa
and some SP-related cleanups. - We don't have separate stage for calculation of list of tables to be prelocked and doing implicit LOCK/UNLOCK any more. Instead we calculate this list at open_tables() and do implicit LOCK in lock_tables() (and UNLOCK in close_thread_tables()). Also now we support cases when same table (with same alias) is used several times in the same query in SP. - Cleaned up execution of SP. Moved all common code which handles LEX and does preparations before statement execution or complex expression evaluation to auxilary sp_lex_keeper class. Now all statements in SP (and corresponding instructions) that evaluate expression which can contain subquery have their own LEX. mysql-test/r/lock.result: Replaced wrong error code with the correct one after fixing bug in SP-locking. mysql-test/r/mysqldump.result: Added dropping of view which is used in test to its beginning. mysql-test/r/sp.result: Added tests for improved SP-locking. Temporarily disabled tests for SHOW PROCEDURE STATUS and alike (Until Monty will allow to open mysql.proc under LOCK TABLES without mentioning it in lock list). Replaced wrong results of test for bug #5240 with correct results after fixing bug in handling of cursors. mysql-test/t/lock.test: Replaced wrong error code with the correct one after fixing bug in SP-locking. mysql-test/t/mysqldump.test: Added dropping of view which is used in test to its beginning. mysql-test/t/sp.test: Added tests for improved SP-locking. Temporarily disabled tests for SHOW PROCEDURE STATUS and alike (Until Monty will allow to open mysql.proc under LOCK TABLES without mentioning it in lock list). Removed test for bug #1654 since we already test exactly this function in one of SP-locking tests. Removed comment about cursor's wrong behavior in test for bug #5240 after fixing bug which was its cause. sql/item_func.cc: Removed comment which is no longer true. sql/mysql_priv.h: Changed open_tables() signature. Now its 2nd parameter is in/out since it can add elements to table list. sql/sp.cc: sp_find_procedure(): Added one more parameter which enforces cache only lookup. sp_merge_hash(): Now uses its return value to indicate that first of two hashes changed as result of merge. sp_cache_routines(): This function caches all stored routines used in query now. sql/sp.h: - sp_find_procedure() now has one more parameter which enforces cache only lookup. - sp_merge_hash() now uses its return value to indicate that first of two hashes changed as result of merge. - sp_cache_routines() caches all stored routines now. So it does not need third argument any more. sql/sp_head.cc: sp_head::sp_head(): Added initialization of new m_spfuns and m_spprocs members. sp_head::execute(): Let us save/restore part of thread context which can be damaged by execution of instructions. sp_head::execute_function()/execute_procedure(): Now it is responsibility of caller to close tables used in subqueries which are passed as routine parameters. sp_head::restore_lex(): Let us accumulate information about routines used by this one in new m_spfuns, m_spprocs hashes. sp_lex_keeper::reset_lex_and_exec_core() Main method of new auxilary sp_lex_keeper class to which instructions delegate responsibility for handling LEX and preparations before executing statement or calculating complex expression. Since all instructions which calculate complex expression or execute command now use sp_lex_keeper they have to implement sp_instr::exec_core() method. Most of instruction specific logic has moved from sp_instr::execute() to this new method. Removed sp_instr_set_user_var class which is no longer used, because nowdays we allow execution of statements in stored functions and triggers. sp_merge_table_list() became sp_head::merge_table_list() method. It also treats sp_head::m_sptabs as multi-set of tables now. sp_hash_to_table_list() became sp_head::add_used_tables_to_table_list(). It takes into account that sp_head::m_sptabs is multi-set and allocates object into persistent arena of PS. Removed sp_merge_table_hash(), sp_open_and_lock_tables(), sp_unlock_tables(), sp_merge_routine_tables() methods since they are not used by new prelocking mechanism. Added sp_add_sp_tables_to_table_list() which serves for adding tables needed by routines used in query to the query table list for prelocking. sql/sp_head.h: class sp_head: - Added m_spfuns, m_spprocs members for storing names of routines used by this routine. - Added add_used_tables_to_table_list() method which allows to add tables needed by this routine to query's table list. - Converted sp_merge_table_list() to sp_head::merge_table_list() method. - Changed semantics of THD::m_sptabs. Now it is multi-set which contains only tables which are used by this routine and not routines that are called from this one. Removed sp_merge_routine_tables(), sp_merge_table_hash(), sp_open_and_lock_tables(), sp_unlock_tables() calls since they are not used for our prelocking list calculation. Added auxilary sp_lex_keeper class to which instructions delegate responsibility for handling LEX and preparations before executing statement or calculating complex expression. This class uses new sp_instr::exec_core() method which is responsible for executing instruction's core function after all preparations were made. All instructions which hold and calculate complex expression now have their own LEX (by aggregating sp_lex_keeper instance). sp_instr_stmt now uses sp_lex_keeper too. Removed sp_instr_set_user_var class which is no longer used, because nowdays we allow execution of statements in stored functions and triggers. sql/sp_rcontext.cc: Now sp_cursor holds pointer to sp_lex_keeper instead of LEX. sql/sp_rcontext.h: Now sp_cursor holds pointer to sp_lex_keeper instead of LEX. sql/sql_acl.cc: acl_init(), grant_init(): Now we use simple_open_n_lock_tables() instead of explicit calls to open_tables() and mysql_lock_tables(). sql/sql_base.cc: Implemented support for execution of statements in "prelocked" mode. When we have statement which uses stored routines explicitly or implicitly (via views or triggers) we have to open and lock all tables for these routines at the same time as tables for the main statement. In fact we have to do implicit LOCK TABLES at the begining of such statement and implict UNLOCK TABLES at its end. We call such mode "prelocked". When open_tables() is called for the statement tables which are needed for execution of routines used by it are added to its tables list (this process also caches all routines used). Implicit use of routines is discovered when we open view or table with trigger and apropriate tables are added to the table list at this moment. Statement which has such extra tables in its list (well actually any that uses functions) is marked as requiring prelocked mode for its execution. When lock_tables() sees such statement it will issue implicit LOCK TABLES for this extended table list instead of doing usual locking, it will also set THD::prelocked_mode to indicate that we are in prelocked mode. When open_tables()/lock_tables() are called for statement of stored routine (substatement), they notice that we are running in prelocked mode and use one of prelocked tables from those that are not used by upper levels of execution. close_thread_tables() for substatement won't really close tables used but will mark them as free for reuse instead. Finally when close_thread_tables() is called for the main statement it really unlocks and closes all tables used. Everything will work even if one uses such statement under real LOCK TABLES (we are simply not doing implicit LOCK/UNLOCK in this case). sql/sql_class.cc: Added initialization of THD::prelocked_mode member. sql/sql_class.h: - Added prelocked_mode_type enum and THD::prelocked_mode member which are used for indication whenever "prelocked mode" is on (i.e. that statement uses stored routines and is executed under implicit LOCK TABLES). - Removed THD::shortcut_make_view which is no longer needed. We use TABLE_LIST::prelocking_placeholder for the same purprose now. sql/sql_handler.cc: Changed open_tables() invocation. Now its 2nd parameter is in/out since it can add elements to table list. sql/sql_lex.cc: lex_start(): Added initialization of LEX::query_tables_own_last. Unused LEX::sptabs member was removed. st_lex::unlink_first_table()/link_first_table_back(): We should update LEX::query_tables_last properly if table list contains(ed) only one element. sql/sql_lex.h: LEX: - Removed sptabs member since it is no longer used. - Added query_tables_own_last member, which if non-0 indicates that statement requires prelocking (implicit LOCK TABLES) for its execution and points to last own element in query table list. If it is zero then this query does not need prelocking. - Added requires_prelocking(), mark_as_requiring_prelocking(), first_not_own_table() inline methods to incapsulate and simplify usage of this new member. sql/sql_parse.cc: dispatch_command(): To properly leave prelocked mode when needed we should call close_thread_tables() even if there are no open tables. mysql_execute_command(): - Removed part of function which were responsible for doing implicit LOCK TABLES before statement execution if statement used stored routines (and doing UNLOCK TABLES at the end). Now we do all this in open_tables()/lock_tables()/close_thread_tables() instead. - It is also sensible to reset errors before execution of statement which uses routines. - SQLCOM_DO, SQLCOM_SET_OPTION, SQLCOM_CALL We should always try to open tables because even if statement has empty table list, it can call routines using tables, which should be preopened before statement execution. - SQLCOM_CALL We should not look up routine called in mysql.proc, since it should be already cached by this moment by open_tables() call. - SQLCOM_LOCK_TABLES it is better to use simple_open_n_lock_tables() since we want to avoid materialization of derived tables for this command. sql/sql_prepare.cc: mysql_test_update(): Changed open_tables() invocations. Now its 2nd parameter is in/out since it can add elements to table list. check_prepared_statement(): Since now we cache all routines used by statement in open_tables() we don't need to do it explicitly. mysql_stmt_prepare(): Now we should call close_thread_tables() when THD::lex points to the LEX of statement which opened tables. reset_stmt_for_execute(): Commented why we are resetting all tables in table list. sql/sql_trigger.h: Table_triggers_list::process_triggers(): We should surpress sending of ok packet when we are calling trigger's routine, since now we allow statements in them. sql/sql_update.cc: Changed open_tables() invocations. Now its 2nd parameter is in/out since it can add elements to table list. sql/sql_view.cc: mysql_make_view(): - Removed handling of routines used in view. Instead we add tables which are needed for their execution to statement's table list in open_tables(). - Now we use TABLE_LIST::prelocking_placeholder instead of THD::shortcut_make_view for indicating that view is opened only to discover which tables and routines it uses (this happens when we build extended table list for prelocking). Also now we try to avoid to modify main LEX in this case (except of its table list). - Corrected small error we added tables to the table list of the main LEX without updating its query_tables_last member properly. sql/sql_yacc.yy: Now each expression which is used in SP statements and can contain subquery has its own LEX. This LEX is stored in corresponding sp_instr object and used along with Item tree for expression calculation. We don't need sp_instr_set_user_var() anymore since now we allow execution of statements in stored functions and triggers. sql/table.h: Added TABLE_LIST::prelocking_placeholder member for distinguishing elements of table list which does not belong to the statement itself and added there only for prelocking (as they are to be used by routines called by this statement). sql/tztime.cc: my_tz_init(): Now we use more simplier simple_open_n_lock_tables() call instead of open_tables()/lock_tables() pair.
953 lines
20 KiB
C++
953 lines
20 KiB
C++
/* -*- C++ -*- */
|
|
/* Copyright (C) 2002 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 */
|
|
|
|
#ifndef _SP_HEAD_H_
|
|
#define _SP_HEAD_H_
|
|
|
|
#ifdef __GNUC__
|
|
#pragma interface /* gcc class implementation */
|
|
#endif
|
|
|
|
#include <stddef.h>
|
|
|
|
// Values for the type enum. This reflects the order of the enum declaration
|
|
// in the CREATE TABLE command.
|
|
#define TYPE_ENUM_FUNCTION 1
|
|
#define TYPE_ENUM_PROCEDURE 2
|
|
#define TYPE_ENUM_TRIGGER 3
|
|
|
|
Item_result
|
|
sp_map_result_type(enum enum_field_types type);
|
|
|
|
bool
|
|
sp_multi_results_command(enum enum_sql_command cmd);
|
|
|
|
struct sp_label;
|
|
class sp_instr;
|
|
struct sp_cond_type;
|
|
struct sp_pvar;
|
|
|
|
class sp_name : public Sql_alloc
|
|
{
|
|
public:
|
|
|
|
LEX_STRING m_db;
|
|
LEX_STRING m_name;
|
|
LEX_STRING m_qname;
|
|
|
|
sp_name(LEX_STRING name)
|
|
: m_name(name)
|
|
{
|
|
m_db.str= m_qname.str= 0;
|
|
m_db.length= m_qname.length= 0;
|
|
}
|
|
|
|
sp_name(LEX_STRING db, LEX_STRING name)
|
|
: m_db(db), m_name(name)
|
|
{
|
|
m_qname.str= 0;
|
|
m_qname.length= 0;
|
|
}
|
|
|
|
// Init. the qualified name from the db and name.
|
|
void init_qname(THD *thd); // thd for memroot allocation
|
|
|
|
~sp_name()
|
|
{}
|
|
};
|
|
|
|
sp_name *
|
|
sp_name_current_db_new(THD *thd, LEX_STRING name);
|
|
|
|
|
|
class sp_head :private Item_arena
|
|
{
|
|
sp_head(const sp_head &); /* Prevent use of these */
|
|
void operator=(sp_head &);
|
|
|
|
public:
|
|
|
|
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
|
|
enum enum_field_types m_returns; // For FUNCTIONs only
|
|
CHARSET_INFO *m_returns_cs; // For FUNCTIONs only
|
|
my_bool m_has_return; // For FUNCTIONs only
|
|
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
|
|
my_bool m_multi_results; // TRUE if a procedure with SELECT(s)
|
|
my_bool m_in_handler; // TRUE if parser in a handler body
|
|
uchar *m_tmp_query; // Temporary pointer to sub query string
|
|
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
|
|
st_sp_chistics *m_chistics;
|
|
ulong m_sql_mode; // For SHOW CREATE
|
|
LEX_STRING m_qname; // db.name
|
|
LEX_STRING m_db;
|
|
LEX_STRING m_name;
|
|
LEX_STRING m_params;
|
|
LEX_STRING m_retstr; // For FUNCTIONs only
|
|
LEX_STRING m_body;
|
|
LEX_STRING m_defstr;
|
|
LEX_STRING m_definer_user;
|
|
LEX_STRING m_definer_host;
|
|
longlong m_created;
|
|
longlong m_modified;
|
|
/*
|
|
Sets containing names of SP and SF used by this routine.
|
|
|
|
TODO Probably we should combine these two hashes in one. It will
|
|
decrease memory overhead ans simplify algorithms using them. The
|
|
same applies to similar hashes in LEX.
|
|
*/
|
|
HASH m_spfuns, m_spprocs;
|
|
// Pointers set during parsing
|
|
uchar *m_param_begin, *m_param_end, *m_returns_begin, *m_returns_end,
|
|
*m_body_begin;
|
|
|
|
static void *
|
|
operator new(size_t size);
|
|
|
|
static void
|
|
operator delete(void *ptr, size_t size);
|
|
|
|
sp_head();
|
|
|
|
// Initialize after we have reset mem_root
|
|
void
|
|
init(LEX *lex);
|
|
|
|
// Initialize strings after parsing header
|
|
void
|
|
init_strings(THD *thd, LEX *lex, sp_name *name);
|
|
|
|
int
|
|
create(THD *thd);
|
|
|
|
virtual ~sp_head();
|
|
|
|
// Free memory
|
|
void
|
|
destroy();
|
|
|
|
int
|
|
execute_function(THD *thd, Item **args, uint argcount, Item **resp);
|
|
|
|
int
|
|
execute_procedure(THD *thd, List<Item> *args);
|
|
|
|
int
|
|
show_create_procedure(THD *thd);
|
|
|
|
int
|
|
show_create_function(THD *thd);
|
|
|
|
void
|
|
add_instr(sp_instr *instr);
|
|
|
|
inline uint
|
|
instructions()
|
|
{
|
|
return m_instr.elements;
|
|
}
|
|
|
|
inline sp_instr *
|
|
last_instruction()
|
|
{
|
|
sp_instr *i;
|
|
|
|
get_dynamic(&m_instr, (gptr)&i, m_instr.elements-1);
|
|
return i;
|
|
}
|
|
|
|
// Resets lex in 'thd' and keeps a copy of the old one.
|
|
void
|
|
reset_lex(THD *thd);
|
|
|
|
// Restores lex in 'thd' from our copy, but keeps some status from the
|
|
// one in 'thd', like ptr, tables, fields, etc.
|
|
void
|
|
restore_lex(THD *thd);
|
|
|
|
// Put the instruction on the backpatch list, associated with the label.
|
|
void
|
|
push_backpatch(sp_instr *, struct sp_label *);
|
|
|
|
// Update all instruction with this label in the backpatch list to
|
|
// the current position.
|
|
void
|
|
backpatch(struct sp_label *);
|
|
|
|
// Check that no unresolved references exist.
|
|
// If none found, 0 is returned, otherwise errors have been issued
|
|
// and -1 is returned.
|
|
// This is called by the parser at the end of a create procedure/function.
|
|
int
|
|
check_backpatch(THD *thd);
|
|
|
|
char *name(uint *lenp = 0) const
|
|
{
|
|
if (lenp)
|
|
*lenp= m_name.length;
|
|
return m_name.str;
|
|
}
|
|
|
|
char *create_string(THD *thd, ulong *lenp);
|
|
|
|
inline Item_result result()
|
|
{
|
|
return sp_map_result_type(m_returns);
|
|
}
|
|
|
|
void set_info(char *definer, uint definerlen,
|
|
longlong created, longlong modified,
|
|
st_sp_chistics *chistics, ulong sql_mode);
|
|
|
|
void reset_thd_mem_root(THD *thd);
|
|
|
|
void restore_thd_mem_root(THD *thd);
|
|
|
|
void optimize();
|
|
void opt_mark(uint ip);
|
|
|
|
inline sp_instr *
|
|
get_instr(uint i)
|
|
{
|
|
sp_instr *ip;
|
|
|
|
if (i < m_instr.elements)
|
|
get_dynamic(&m_instr, (gptr)&ip, i);
|
|
else
|
|
ip= NULL;
|
|
return ip;
|
|
}
|
|
|
|
/* Add tables used by routine to the table list. */
|
|
bool add_used_tables_to_table_list(THD *thd,
|
|
TABLE_LIST ***query_tables_last_ptr);
|
|
|
|
private:
|
|
|
|
MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root
|
|
THD *m_thd; // Set if we have reset mem_root
|
|
char *m_thd_db; // Original thd->db pointer
|
|
|
|
sp_pcontext *m_pcont; // Parse context
|
|
List<LEX> m_lex; // Temp. store for the other lex
|
|
DYNAMIC_ARRAY m_instr; // The "instructions"
|
|
typedef struct
|
|
{
|
|
struct sp_label *lab;
|
|
sp_instr *instr;
|
|
} bp_t;
|
|
List<bp_t> m_backpatch; // Instructions needing backpatching
|
|
/*
|
|
Multi-set representing optimized list of tables to be locked by this
|
|
routine. Does not include tables which are used by invoked routines.
|
|
*/
|
|
HASH m_sptabs;
|
|
|
|
int
|
|
execute(THD *thd);
|
|
|
|
/*
|
|
Merge the list of tables used by query into the multi-set of tables used
|
|
by routine.
|
|
*/
|
|
bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check);
|
|
}; // class sp_head : public Sql_alloc
|
|
|
|
|
|
//
|
|
// "Instructions"...
|
|
//
|
|
|
|
class sp_instr : public Sql_alloc
|
|
{
|
|
sp_instr(const sp_instr &); /* Prevent use of these */
|
|
void operator=(sp_instr &);
|
|
|
|
public:
|
|
|
|
uint marked;
|
|
Item *free_list; // My Items
|
|
uint m_ip; // My index
|
|
sp_pcontext *m_ctx; // My parse context
|
|
|
|
// Should give each a name or type code for debugging purposes?
|
|
sp_instr(uint ip, sp_pcontext *ctx)
|
|
:Sql_alloc(), marked(0), free_list(0), m_ip(ip), m_ctx(ctx)
|
|
{}
|
|
|
|
virtual ~sp_instr()
|
|
{ free_items(free_list); }
|
|
|
|
// Execute this instrution. '*nextp' will be set to the index of the next
|
|
// instruction to execute. (For most instruction this will be the
|
|
// instruction following this one.)
|
|
// Returns 0 on success, non-zero if some error occured.
|
|
virtual int execute(THD *thd, uint *nextp) = 0;
|
|
|
|
/*
|
|
Execute core function of instruction after all preparations (e.g.
|
|
setting of proper LEX, saving part of the thread context have been
|
|
done).
|
|
|
|
Should be implemented for instructions using expressions or whole
|
|
statements (thus having to have own LEX). Used in concert with
|
|
sp_lex_keeper class and its descendants.
|
|
*/
|
|
virtual int exec_core(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str) = 0;
|
|
|
|
virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
|
|
{}
|
|
|
|
virtual uint opt_mark(sp_head *sp)
|
|
{
|
|
marked= 1;
|
|
return m_ip+1;
|
|
}
|
|
|
|
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
|
|
{
|
|
return m_ip;
|
|
}
|
|
|
|
virtual void opt_move(uint dst, List<sp_instr> *ibp)
|
|
{
|
|
m_ip= dst;
|
|
}
|
|
|
|
}; // class sp_instr : public Sql_alloc
|
|
|
|
|
|
/*
|
|
Auxilary class to which instructions delegate responsibility
|
|
for handling LEX and preparations before executing statement
|
|
or calculating complex expression.
|
|
|
|
Exist mainly to avoid having double hierarchy between instruction
|
|
classes.
|
|
|
|
TODO: Add ability to not store LEX and do any preparations if
|
|
expression used is simple.
|
|
*/
|
|
|
|
class sp_lex_keeper
|
|
{
|
|
/* Prevent use of these */
|
|
sp_lex_keeper(const sp_lex_keeper &);
|
|
void operator=(sp_lex_keeper &);
|
|
public:
|
|
|
|
sp_lex_keeper(LEX *lex, bool lex_resp)
|
|
: m_lex(lex), m_lex_resp(lex_resp)
|
|
{
|
|
lex->sp_lex_in_use= TRUE;
|
|
}
|
|
virtual ~sp_lex_keeper()
|
|
{
|
|
if (m_lex_resp)
|
|
delete m_lex;
|
|
}
|
|
|
|
/*
|
|
Prepare execution of instruction using LEX, if requested check whenever
|
|
we have read access to tables used and open/lock them, call instruction's
|
|
exec_core() method, perform cleanup afterwards.
|
|
*/
|
|
int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables,
|
|
sp_instr* instr);
|
|
|
|
inline uint sql_command() const
|
|
{
|
|
return (uint)m_lex->sql_command;
|
|
}
|
|
|
|
private:
|
|
|
|
LEX *m_lex;
|
|
/*
|
|
Indicates whenever this sp_lex_keeper instance responsible
|
|
for LEX deletion.
|
|
*/
|
|
bool m_lex_resp;
|
|
};
|
|
|
|
|
|
//
|
|
// Call out to some prepared SQL statement.
|
|
//
|
|
class sp_instr_stmt : public sp_instr
|
|
{
|
|
sp_instr_stmt(const sp_instr_stmt &); /* Prevent use of these */
|
|
void operator=(sp_instr_stmt &);
|
|
|
|
public:
|
|
|
|
LEX_STRING m_query; // For thd->query
|
|
|
|
sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex)
|
|
: sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
|
|
{
|
|
m_query.str= 0;
|
|
m_query.length= 0;
|
|
}
|
|
|
|
virtual ~sp_instr_stmt()
|
|
{};
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual int exec_core(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
private:
|
|
|
|
sp_lex_keeper m_lex_keeper;
|
|
|
|
}; // class sp_instr_stmt : public sp_instr
|
|
|
|
|
|
class sp_instr_set : public sp_instr
|
|
{
|
|
sp_instr_set(const sp_instr_set &); /* Prevent use of these */
|
|
void operator=(sp_instr_set &);
|
|
|
|
public:
|
|
|
|
sp_instr_set(uint ip, sp_pcontext *ctx,
|
|
uint offset, Item *val, enum enum_field_types type,
|
|
LEX *lex, bool lex_resp)
|
|
: sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type),
|
|
m_lex_keeper(lex, lex_resp)
|
|
{}
|
|
|
|
virtual ~sp_instr_set()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual int exec_core(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
private:
|
|
|
|
uint m_offset; // Frame offset
|
|
Item *m_value;
|
|
enum enum_field_types m_type; // The declared type
|
|
sp_lex_keeper m_lex_keeper;
|
|
|
|
}; // class sp_instr_set : public sp_instr
|
|
|
|
|
|
/*
|
|
Set NEW/OLD row field value instruction. Used in triggers.
|
|
*/
|
|
class sp_instr_set_trigger_field : public sp_instr
|
|
{
|
|
sp_instr_set_trigger_field(const sp_instr_set_trigger_field &);
|
|
void operator=(sp_instr_set_trigger_field &);
|
|
|
|
public:
|
|
|
|
sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx,
|
|
LEX_STRING field_name, Item *val)
|
|
: sp_instr(ip, ctx),
|
|
trigger_field(Item_trigger_field::NEW_ROW, field_name.str),
|
|
value(val)
|
|
{}
|
|
|
|
virtual ~sp_instr_set_trigger_field()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
Item_trigger_field trigger_field;
|
|
|
|
private:
|
|
Item *value;
|
|
}; // class sp_instr_trigger_field : public sp_instr
|
|
|
|
|
|
class sp_instr_jump : public sp_instr
|
|
{
|
|
sp_instr_jump(const sp_instr_jump &); /* Prevent use of these */
|
|
void operator=(sp_instr_jump &);
|
|
|
|
public:
|
|
|
|
uint m_dest; // Where we will go
|
|
|
|
sp_instr_jump(uint ip, sp_pcontext *ctx)
|
|
: sp_instr(ip, ctx), m_dest(0), m_optdest(0)
|
|
{}
|
|
|
|
sp_instr_jump(uint ip, sp_pcontext *ctx, uint dest)
|
|
: sp_instr(ip, ctx), m_dest(dest), m_optdest(0)
|
|
{}
|
|
|
|
virtual ~sp_instr_jump()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual uint opt_mark(sp_head *sp);
|
|
|
|
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start);
|
|
|
|
virtual void opt_move(uint dst, List<sp_instr> *ibp);
|
|
|
|
virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
|
|
{
|
|
if (m_dest == 0) // Don't reset
|
|
m_dest= dest;
|
|
}
|
|
|
|
protected:
|
|
|
|
sp_instr *m_optdest; // Used during optimization
|
|
|
|
}; // class sp_instr_jump : public sp_instr
|
|
|
|
|
|
class sp_instr_jump_if : public sp_instr_jump
|
|
{
|
|
sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */
|
|
void operator=(sp_instr_jump_if &);
|
|
|
|
public:
|
|
|
|
sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
|
|
: sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
|
|
{}
|
|
|
|
sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
|
|
: sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
|
|
{}
|
|
|
|
virtual ~sp_instr_jump_if()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual int exec_core(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual uint opt_mark(sp_head *sp);
|
|
|
|
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
|
|
{
|
|
return m_ip;
|
|
}
|
|
|
|
private:
|
|
|
|
Item *m_expr; // The condition
|
|
sp_lex_keeper m_lex_keeper;
|
|
|
|
}; // class sp_instr_jump_if : public sp_instr_jump
|
|
|
|
|
|
class sp_instr_jump_if_not : public sp_instr_jump
|
|
{
|
|
sp_instr_jump_if_not(const sp_instr_jump_if_not &); /* Prevent use of these */
|
|
void operator=(sp_instr_jump_if_not &);
|
|
|
|
public:
|
|
|
|
sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
|
|
: sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
|
|
{}
|
|
|
|
sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
|
|
: sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
|
|
{}
|
|
|
|
virtual ~sp_instr_jump_if_not()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual int exec_core(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual uint opt_mark(sp_head *sp);
|
|
|
|
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
|
|
{
|
|
return m_ip;
|
|
}
|
|
|
|
private:
|
|
|
|
Item *m_expr; // The condition
|
|
sp_lex_keeper m_lex_keeper;
|
|
|
|
}; // class sp_instr_jump_if_not : public sp_instr_jump
|
|
|
|
|
|
class sp_instr_freturn : public sp_instr
|
|
{
|
|
sp_instr_freturn(const sp_instr_freturn &); /* Prevent use of these */
|
|
void operator=(sp_instr_freturn &);
|
|
|
|
public:
|
|
|
|
sp_instr_freturn(uint ip, sp_pcontext *ctx,
|
|
Item *val, enum enum_field_types type, LEX *lex)
|
|
: sp_instr(ip, ctx), m_value(val), m_type(type), m_lex_keeper(lex, TRUE)
|
|
{}
|
|
|
|
virtual ~sp_instr_freturn()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual int exec_core(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual uint opt_mark(sp_head *sp)
|
|
{
|
|
marked= 1;
|
|
return UINT_MAX;
|
|
}
|
|
|
|
protected:
|
|
|
|
Item *m_value;
|
|
enum enum_field_types m_type;
|
|
sp_lex_keeper m_lex_keeper;
|
|
|
|
}; // class sp_instr_freturn : public sp_instr
|
|
|
|
|
|
class sp_instr_hpush_jump : public sp_instr_jump
|
|
{
|
|
sp_instr_hpush_jump(const sp_instr_hpush_jump &); /* Prevent use of these */
|
|
void operator=(sp_instr_hpush_jump &);
|
|
|
|
public:
|
|
|
|
sp_instr_hpush_jump(uint ip, sp_pcontext *ctx, int htype, uint fp)
|
|
: sp_instr_jump(ip, ctx), m_type(htype), m_frame(fp)
|
|
{
|
|
m_handler= ip+1;
|
|
m_cond.empty();
|
|
}
|
|
|
|
virtual ~sp_instr_hpush_jump()
|
|
{
|
|
m_cond.empty();
|
|
}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual uint opt_mark(sp_head *sp);
|
|
|
|
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
|
|
{
|
|
return m_ip;
|
|
}
|
|
|
|
inline void add_condition(struct sp_cond_type *cond)
|
|
{
|
|
m_cond.push_front(cond);
|
|
}
|
|
|
|
private:
|
|
|
|
int m_type; // Handler type
|
|
uint m_frame;
|
|
uint m_handler; // Location of handler
|
|
List<struct sp_cond_type> m_cond;
|
|
|
|
}; // class sp_instr_hpush_jump : public sp_instr_jump
|
|
|
|
|
|
class sp_instr_hpop : public sp_instr
|
|
{
|
|
sp_instr_hpop(const sp_instr_hpop &); /* Prevent use of these */
|
|
void operator=(sp_instr_hpop &);
|
|
|
|
public:
|
|
|
|
sp_instr_hpop(uint ip, sp_pcontext *ctx, uint count)
|
|
: sp_instr(ip, ctx), m_count(count)
|
|
{}
|
|
|
|
virtual ~sp_instr_hpop()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual void backpatch(uint dest, sp_pcontext *dst_ctx);
|
|
|
|
virtual uint opt_mark(sp_head *sp)
|
|
{
|
|
if (m_count)
|
|
marked= 1;
|
|
return m_ip+1;
|
|
}
|
|
|
|
private:
|
|
|
|
uint m_count;
|
|
|
|
}; // class sp_instr_hpop : public sp_instr
|
|
|
|
|
|
class sp_instr_hreturn : public sp_instr_jump
|
|
{
|
|
sp_instr_hreturn(const sp_instr_hreturn &); /* Prevent use of these */
|
|
void operator=(sp_instr_hreturn &);
|
|
|
|
public:
|
|
|
|
sp_instr_hreturn(uint ip, sp_pcontext *ctx, uint fp)
|
|
: sp_instr_jump(ip, ctx), m_frame(fp)
|
|
{}
|
|
|
|
virtual ~sp_instr_hreturn()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual uint opt_mark(sp_head *sp);
|
|
|
|
private:
|
|
|
|
uint m_frame;
|
|
|
|
}; // class sp_instr_hreturn : public sp_instr
|
|
|
|
|
|
class sp_instr_cpush : public sp_instr
|
|
{
|
|
sp_instr_cpush(const sp_instr_cpush &); /* Prevent use of these */
|
|
void operator=(sp_instr_cpush &);
|
|
|
|
public:
|
|
|
|
sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex)
|
|
: sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
|
|
{}
|
|
|
|
virtual ~sp_instr_cpush()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
private:
|
|
|
|
sp_lex_keeper m_lex_keeper;
|
|
|
|
}; // class sp_instr_cpush : public sp_instr
|
|
|
|
|
|
class sp_instr_cpop : public sp_instr
|
|
{
|
|
sp_instr_cpop(const sp_instr_cpop &); /* Prevent use of these */
|
|
void operator=(sp_instr_cpop &);
|
|
|
|
public:
|
|
|
|
sp_instr_cpop(uint ip, sp_pcontext *ctx, uint count)
|
|
: sp_instr(ip, ctx), m_count(count)
|
|
{}
|
|
|
|
virtual ~sp_instr_cpop()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual void backpatch(uint dest, sp_pcontext *dst_ctx);
|
|
|
|
virtual uint opt_mark(sp_head *sp)
|
|
{
|
|
if (m_count)
|
|
marked= 1;
|
|
return m_ip+1;
|
|
}
|
|
|
|
private:
|
|
|
|
uint m_count;
|
|
|
|
}; // class sp_instr_cpop : public sp_instr
|
|
|
|
|
|
class sp_instr_copen : public sp_instr
|
|
{
|
|
sp_instr_copen(const sp_instr_copen &); /* Prevent use of these */
|
|
void operator=(sp_instr_copen &);
|
|
|
|
public:
|
|
|
|
sp_instr_copen(uint ip, sp_pcontext *ctx, uint c)
|
|
: sp_instr(ip, ctx), m_cursor(c)
|
|
{}
|
|
|
|
virtual ~sp_instr_copen()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual int exec_core(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
private:
|
|
|
|
uint m_cursor; // Stack index
|
|
|
|
}; // class sp_instr_copen : public sp_instr_stmt
|
|
|
|
|
|
class sp_instr_cclose : public sp_instr
|
|
{
|
|
sp_instr_cclose(const sp_instr_cclose &); /* Prevent use of these */
|
|
void operator=(sp_instr_cclose &);
|
|
|
|
public:
|
|
|
|
sp_instr_cclose(uint ip, sp_pcontext *ctx, uint c)
|
|
: sp_instr(ip, ctx), m_cursor(c)
|
|
{}
|
|
|
|
virtual ~sp_instr_cclose()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
private:
|
|
|
|
uint m_cursor;
|
|
|
|
}; // class sp_instr_cclose : public sp_instr
|
|
|
|
|
|
class sp_instr_cfetch : public sp_instr
|
|
{
|
|
sp_instr_cfetch(const sp_instr_cfetch &); /* Prevent use of these */
|
|
void operator=(sp_instr_cfetch &);
|
|
|
|
public:
|
|
|
|
sp_instr_cfetch(uint ip, sp_pcontext *ctx, uint c)
|
|
: sp_instr(ip, ctx), m_cursor(c)
|
|
{
|
|
m_varlist.empty();
|
|
}
|
|
|
|
virtual ~sp_instr_cfetch()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
void add_to_varlist(struct sp_pvar *var)
|
|
{
|
|
m_varlist.push_back(var);
|
|
}
|
|
|
|
private:
|
|
|
|
uint m_cursor;
|
|
List<struct sp_pvar> m_varlist;
|
|
|
|
}; // class sp_instr_cfetch : public sp_instr
|
|
|
|
|
|
class sp_instr_error : public sp_instr
|
|
{
|
|
sp_instr_error(const sp_instr_error &); /* Prevent use of these */
|
|
void operator=(sp_instr_error &);
|
|
|
|
public:
|
|
|
|
sp_instr_error(uint ip, sp_pcontext *ctx, int errcode)
|
|
: sp_instr(ip, ctx), m_errcode(errcode)
|
|
{}
|
|
|
|
virtual ~sp_instr_error()
|
|
{}
|
|
|
|
virtual int execute(THD *thd, uint *nextp);
|
|
|
|
virtual void print(String *str);
|
|
|
|
virtual uint opt_mark(sp_head *sp)
|
|
{
|
|
marked= 1;
|
|
return UINT_MAX;
|
|
}
|
|
|
|
private:
|
|
|
|
int m_errcode;
|
|
|
|
}; // class sp_instr_error : public sp_instr
|
|
|
|
|
|
struct st_sp_security_context
|
|
{
|
|
bool changed;
|
|
uint master_access;
|
|
uint db_access;
|
|
char *priv_user;
|
|
char priv_host[MAX_HOSTNAME];
|
|
char *user;
|
|
char *host;
|
|
char *ip;
|
|
};
|
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
void
|
|
sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp);
|
|
void
|
|
sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp);
|
|
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
|
|
|
|
TABLE_LIST *
|
|
sp_add_to_query_tables(THD *thd, LEX *lex,
|
|
const char *db, const char *name,
|
|
thr_lock_type locktype);
|
|
bool
|
|
sp_add_sp_tables_to_table_list(THD *thd, LEX *lex, LEX *func_lex);
|
|
|
|
#endif /* _SP_HEAD_H_ */
|