summaryrefslogtreecommitdiff
path: root/sql/sp_head.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sp_head.h')
-rw-r--r--sql/sp_head.h645
1 files changed, 576 insertions, 69 deletions
diff --git a/sql/sp_head.h b/sql/sp_head.h
index ed9fef5116f..272bc5d445c 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -40,11 +40,6 @@
@{
*/
-// 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 #define TYPE_ENUM_PROXY 4
-
Item::Type
sp_map_item_type(enum enum_field_types type);
@@ -107,39 +102,33 @@ protected:
/*************************************************************************/
-class sp_name : public Sql_alloc
+class sp_name : public Sql_alloc,
+ public Database_qualified_name
{
public:
-
- LEX_STRING m_db;
- LEX_STRING m_name;
- LEX_STRING m_qname;
bool m_explicit_name; /**< Prepend the db name? */
- sp_name(LEX_STRING db, LEX_STRING name, bool use_explicit_name)
- : m_db(db), m_name(name), m_explicit_name(use_explicit_name)
+ sp_name(const LEX_CSTRING *db, const LEX_CSTRING *name,
+ bool use_explicit_name)
+ : Database_qualified_name(db, name), m_explicit_name(use_explicit_name)
{
if (lower_case_table_names && m_db.str)
- m_db.length= my_casedn_str(files_charset_info, m_db.str);
- m_qname.str= 0;
- m_qname.length= 0;
+ m_db.length= my_casedn_str(files_charset_info, (char*) m_db.str);
}
- /** Create temporary sp_name object from MDL key. */
+ /** Create temporary sp_name object from MDL key. Store in qname_buff */
sp_name(const MDL_key *key, char *qname_buff);
- // Init. the qualified name from the db and name.
- void init_qname(THD *thd); // thd for memroot allocation
-
~sp_name()
{}
};
bool
-check_routine_name(LEX_STRING *ident);
+check_routine_name(const LEX_CSTRING *ident);
-class sp_head :private Query_arena
+class sp_head :private Query_arena,
+ public Database_qualified_name
{
sp_head(const sp_head &); /**< Prevent use of these */
void operator=(sp_head &);
@@ -172,28 +161,43 @@ public:
b) because in CONTAINS SQL case they don't provide enough
information anyway.
*/
- MODIFIES_DATA= 4096
+ MODIFIES_DATA= 4096,
+ /*
+ Marks routines that have column type references: DECLARE a t1.a%TYPE;
+ */
+ HAS_COLUMN_TYPE_REFS= 8192
};
- stored_procedure_type m_type;
+ const Sp_handler *m_handler;
uint m_flags; // Boolean attributes of a stored routine
Column_definition m_return_field_def; /**< This is used for FUNCTIONs only. */
const char *m_tmp_query; ///< Temporary pointer to sub query string
- st_sp_chistics *m_chistics;
+private:
+ /*
+ Private to guarantee that m_chistics.comment is properly set to:
+ - a string which is alloced on this->mem_root
+ - or (NULL,0)
+ set_chistics() makes sure this.
+ */
+ Sp_chistics m_chistics;
+public:
sql_mode_t m_sql_mode; ///< For SHOW CREATE and execution
- LEX_STRING m_qname; ///< db.name
- bool m_explicit_name; ///< Prepend the db name? */
- LEX_STRING m_db;
- LEX_STRING m_name;
- LEX_STRING m_params;
- LEX_STRING m_body;
- LEX_STRING m_body_utf8;
- LEX_STRING m_defstr;
- LEX_STRING m_definer_user;
- LEX_STRING m_definer_host;
-
+ bool m_explicit_name; /**< Prepend the db name? */
+ LEX_CSTRING m_qname; ///< db.name
+ LEX_CSTRING m_params;
+ LEX_CSTRING m_body;
+ LEX_CSTRING m_body_utf8;
+ LEX_CSTRING m_defstr;
+ AUTHID m_definer;
+
+ const st_sp_chistics &chistics() const { return m_chistics; }
+ const LEX_CSTRING &comment() const { return m_chistics.comment; }
+ void set_suid(enum_sp_suid_behaviour suid) { m_chistics.suid= suid; }
+ enum_sp_suid_behaviour suid() const { return m_chistics.suid; }
+ bool detistic() const { return m_chistics.detistic; }
+ enum_sp_data_access daccess() const { return m_chistics.daccess; }
/**
Is this routine being executed?
*/
@@ -210,6 +214,13 @@ public:
{
m_sp_cache_version= version_arg;
}
+
+ sp_rcontext *rcontext_create(THD *thd, Field *retval, List<Item> *args);
+ sp_rcontext *rcontext_create(THD *thd, Field *retval,
+ Item **args, uint arg_count);
+ sp_rcontext *rcontext_create(THD *thd, Field *retval,
+ Row_definition_list *list,
+ bool switch_security_ctx);
private:
/**
Version of the stored routine cache at the moment when the
@@ -306,7 +317,7 @@ public:
static void
operator delete(void *ptr, size_t size) throw ();
- sp_head();
+ sp_head(const Sp_handler *handler);
/// Initialize after we have reset mem_root
void
@@ -314,7 +325,7 @@ public:
/** Copy sp name from parser. */
void
- init_sp_name(THD *thd, sp_name *spname);
+ init_sp_name(const sp_name *spname);
/** Set the body-definition start position. */
void
@@ -328,8 +339,8 @@ public:
bool
execute_trigger(THD *thd,
- const LEX_STRING *db_name,
- const LEX_STRING *table_name,
+ const LEX_CSTRING *db_name,
+ const LEX_CSTRING *table_name,
GRANT_INFO *grant_info);
bool
@@ -339,14 +350,174 @@ public:
execute_procedure(THD *thd, List<Item> *args);
static void
- show_create_routine_get_fields(THD *thd, int type, List<Item> *fields);
+ show_create_routine_get_fields(THD *thd, const Sp_handler *sph,
+ List<Item> *fields);
bool
- show_create_routine(THD *thd, int type);
+ show_create_routine(THD *thd, const Sp_handler *sph);
+
+ MEM_ROOT *get_main_mem_root() { return &main_mem_root; }
int
add_instr(sp_instr *instr);
+ bool
+ add_instr_jump(THD *thd, sp_pcontext *spcont);
+
+ bool
+ add_instr_jump(THD *thd, sp_pcontext *spcont, uint dest);
+
+ bool
+ add_instr_jump_forward_with_backpatch(THD *thd, sp_pcontext *spcont,
+ sp_label *lab);
+ bool
+ add_instr_jump_forward_with_backpatch(THD *thd, sp_pcontext *spcont)
+ {
+ return add_instr_jump_forward_with_backpatch(thd, spcont,
+ spcont->last_label());
+ }
+
+ bool
+ add_instr_freturn(THD *thd, sp_pcontext *spcont, Item *item, LEX *lex);
+
+ bool
+ add_instr_preturn(THD *thd, sp_pcontext *spcont);
+
+ Item *adjust_assignment_source(THD *thd, Item *val, Item *val2);
+ /**
+ @param thd - the current thd
+ @param spcont - the current parse context
+ @param spv - the SP variable
+ @param val - the value to be assigned to the variable
+ @param lex - the LEX that was used to create "val"
+ @param responsible_to_free_lex - if the generated sp_instr_set should
+ free "lex".
+ @retval true - on error
+ @retval false - on success
+ */
+ bool set_local_variable(THD *thd, sp_pcontext *spcont,
+ sp_variable *spv, Item *val, LEX *lex,
+ bool responsible_to_free_lex);
+ bool set_local_variable_row_field(THD *thd, sp_pcontext *spcont,
+ sp_variable *spv, uint field_idx,
+ Item *val, LEX *lex);
+ bool set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont,
+ sp_variable *spv,
+ const LEX_CSTRING *field_name,
+ Item *val, LEX *lex);
+private:
+ /**
+ Generate a code to set a single cursor parameter variable.
+ @param thd - current thd, for mem_root allocations.
+ @param param_spcont - the context of the parameter block
+ @param idx - the index of the parameter
+ @param prm - the actual parameter (contains information about
+ the assignment source expression Item,
+ its free list, and its LEX)
+ */
+ bool add_set_cursor_param_variable(THD *thd,
+ sp_pcontext *param_spcont, uint idx,
+ sp_assignment_lex *prm)
+ {
+ DBUG_ASSERT(idx < param_spcont->context_var_count());
+ sp_variable *spvar= param_spcont->get_context_variable(idx);
+ /*
+ add_instr() gets free_list from m_thd->free_list.
+ Initialize it before the set_local_variable() call.
+ */
+ DBUG_ASSERT(m_thd->free_list == NULL);
+ m_thd->free_list= prm->get_free_list();
+ if (set_local_variable(thd, param_spcont, spvar, prm->get_item(), prm, true))
+ return true;
+ /*
+ Safety:
+ The item and its free_list are now fully owned by the sp_instr_set
+ instance, created by set_local_variable(). The sp_instr_set instance
+ is now responsible for freeing the item and the free_list.
+ Reset the "item" and the "free_list" members of "prm",
+ to avoid double pointers to the same objects from "prm" and
+ from the sp_instr_set instance.
+ */
+ prm->set_item_and_free_list(NULL, NULL);
+ return false;
+ }
+
+ /**
+ Generate a code to set all cursor parameter variables.
+ This method is called only when parameters exists,
+ and the number of formal parameters matches the number of actual
+ parameters. See also comments to add_open_cursor().
+ */
+ bool add_set_cursor_param_variables(THD *thd, sp_pcontext *param_spcont,
+ List<sp_assignment_lex> *parameters)
+ {
+ DBUG_ASSERT(param_spcont->context_var_count() == parameters->elements);
+ sp_assignment_lex *prm;
+ List_iterator<sp_assignment_lex> li(*parameters);
+ for (uint idx= 0; (prm= li++); idx++)
+ {
+ if (add_set_cursor_param_variable(thd, param_spcont, idx, prm))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ Generate a code to set all cursor parameter variables for a FOR LOOP, e.g.:
+ FOR index IN cursor(1,2,3)
+ @param
+ */
+ bool add_set_for_loop_cursor_param_variables(THD *thd,
+ sp_pcontext *param_spcont,
+ sp_assignment_lex *param_lex,
+ Item_args *parameters);
+
+public:
+ /**
+ Generate a code for an "OPEN cursor" statement.
+ @param thd - current thd, for mem_root allocations
+ @param spcont - the context of the cursor
+ @param offset - the offset of the cursor
+ @param param_spcont - the context of the cursor parameter block
+ @param parameters - the list of the OPEN actual parameters
+
+ The caller must make sure that the number of local variables
+ in "param_spcont" (formal parameters) matches the number of list elements
+ in "parameters" (actual parameters).
+ NULL in either of them means 0 parameters.
+ */
+ bool add_open_cursor(THD *thd, sp_pcontext *spcont,
+ uint offset,
+ sp_pcontext *param_spcont,
+ List<sp_assignment_lex> *parameters);
+
+ /**
+ Generate an initiation code for a CURSOR FOR LOOP, e.g.:
+ FOR index IN cursor -- cursor without parameters
+ FOR index IN cursor(1,2,3) -- cursor with parameters
+
+ The code generated by this method does the following during SP run-time:
+ - Sets all cursor parameter vartiables from "parameters"
+ - Initializes the index ROW-type variable from the cursor
+ (the structure is copied from the cursor to the index variable)
+ - The cursor gets opened
+ - The first records is fetched from the cursor to the variable "index".
+
+ @param thd - the current thread (for mem_root and error reporting)
+ @param spcont - the current parse context
+ @param index - the loop "index" ROW-type variable
+ @param pcursor - the cursor
+ @param coffset - the cursor offset
+ @param param_lex - the LEX that owns Items in "parameters"
+ @param parameters - the cursor parameters Item array
+ @retval true - on error (EOM)
+ @retval false - on success
+ */
+ bool add_for_loop_open_cursor(THD *thd, sp_pcontext *spcont,
+ sp_variable *index,
+ const sp_pcursor *pcursor, uint coffset,
+ sp_assignment_lex *param_lex,
+ Item_args *parameters);
/**
Returns true if any substatement in the routine directly
(not through another routine) modifies data/changes table.
@@ -368,6 +539,8 @@ public:
return i;
}
+ bool replace_instr_to_nop(THD *thd, uint ip);
+
/*
Resets lex in 'thd' and keeps a copy of the old one.
@@ -376,6 +549,23 @@ public:
bool
reset_lex(THD *thd);
+ bool
+ reset_lex(THD *thd, sp_lex_local *sublex);
+
+ /**
+ Merge two LEX instances.
+ @param oldlex - the upper level LEX we're going to restore to.
+ @param sublex - the local lex that have just parsed some substatement.
+ @returns - false on success, true on error (e.g. failed to
+ merge the routine list or the table list).
+ This method is shared by:
+ - restore_lex(), when the old LEX is popped by sp_head::m_lex.pop()
+ - THD::restore_from_local_lex_to_old_lex(), when the old LEX
+ is stored in the caller's local variable.
+ */
+ bool
+ merge_lex(THD *thd, LEX *oldlex, LEX *sublex);
+
/**
Restores lex in 'thd' from our copy, but keeps some status from the
one in 'thd', like ptr, tables, fields, etc.
@@ -383,16 +573,40 @@ public:
@todo Conflicting comment in sp_head.cc
*/
bool
- restore_lex(THD *thd);
+ restore_lex(THD *thd)
+ {
+ DBUG_ENTER("sp_head::restore_lex");
+ LEX *oldlex= (LEX *) m_lex.pop();
+ if (!oldlex)
+ DBUG_RETURN(false); // Nothing to restore
+ LEX *sublex= thd->lex;
+ if (thd->restore_from_local_lex_to_old_lex(oldlex))// This restores thd->lex
+ DBUG_RETURN(true);
+ if (!sublex->sp_lex_in_use)
+ {
+ sublex->sphead= NULL;
+ lex_end(sublex);
+ delete sublex;
+ }
+ DBUG_RETURN(false);
+ }
/// Put the instruction on the backpatch list, associated with the label.
int
push_backpatch(THD *thd, sp_instr *, sp_label *);
+ int
+ push_backpatch_goto(THD *thd, sp_pcontext *ctx, sp_label *lab);
/// Update all instruction with this label in the backpatch list to
/// the current position.
void
backpatch(sp_label *);
+ void
+ backpatch_goto(THD *thd, sp_label *, sp_label *);
+
+ /// Check for unresolved goto label
+ bool
+ check_unresolved_goto();
/// Start a new cont. backpatch level. If 'i' is NULL, the level is just incr.
int
@@ -406,26 +620,119 @@ public:
void
do_cont_backpatch();
- char *name(uint *lenp = 0) const
- {
- if (lenp)
- *lenp= (uint) m_name.length;
- return m_name.str;
- }
+ /// Add cpush instructions for all cursors declared in the current frame
+ bool sp_add_instr_cpush_for_cursors(THD *thd, sp_pcontext *pcontext);
+
+ const LEX_CSTRING *name() const
+ { return &m_name; }
char *create_string(THD *thd, ulong *lenp);
- Field *create_result_field(uint field_max_length, const char *field_name,
- TABLE *table);
+ Field *create_result_field(uint field_max_length, const LEX_CSTRING *field_name,
+ TABLE *table) const;
+
+
+ /**
+ Check and prepare an instance of Column_definition for field creation
+ (fill all necessary attributes), for variables, parameters and
+ function return values.
+
+ @param[in] thd Thread handle
+ @param[in] lex Yacc parsing context
+ @param[out] field_def An instance of create_field to be filled
- bool fill_field_definition(THD *thd, LEX *lex,
- Column_definition *field_def);
+ @retval false on success
+ @retval true on error
+ */
+ bool fill_field_definition(THD *thd, Column_definition *field_def)
+ {
+ const Type_handler *h= field_def->type_handler();
+ return h->Column_definition_fix_attributes(field_def) ||
+ field_def->sp_prepare_create_field(thd, mem_root);
+ }
+ bool row_fill_field_definitions(THD *thd, Row_definition_list *row)
+ {
+ /*
+ Prepare all row fields. This will (among other things)
+ - convert VARCHAR lengths from character length to octet length
+ - calculate interval lengths for SET and ENUM
+ */
+ List_iterator<Spvar_definition> it(*row);
+ for (Spvar_definition *def= it++; def; def= it++)
+ {
+ if (fill_spvar_definition(thd, def))
+ return true;
+ }
+ return false;
+ }
+ /**
+ Check and prepare a Column_definition for a variable or a parameter.
+ */
+ bool fill_spvar_definition(THD *thd, Column_definition *def)
+ {
+ if (fill_field_definition(thd, def))
+ return true;
+ def->pack_flag|= FIELDFLAG_MAYBE_NULL;
+ return false;
+ }
+ bool fill_spvar_definition(THD *thd, Column_definition *def,
+ LEX_CSTRING *name)
+ {
+ def->field_name= *name;
+ return fill_spvar_definition(thd, def);
+ }
+
+private:
+ /**
+ Set a column type reference for a parameter definition
+ */
+ void fill_spvar_using_type_reference(sp_variable *spvar,
+ Qualified_column_ident *ref)
+ {
+ spvar->field_def.set_column_type_ref(ref);
+ spvar->field_def.field_name= spvar->name;
+ m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
+ }
+
+ void fill_spvar_using_table_rowtype_reference(THD *thd,
+ sp_variable *spvar,
+ Table_ident *ref)
+ {
+ spvar->field_def.set_table_rowtype_ref(ref);
+ spvar->field_def.field_name= spvar->name;
+ fill_spvar_definition(thd, &spvar->field_def);
+ m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
+ }
+public:
+ bool spvar_fill_row(THD *thd, sp_variable *spvar, Row_definition_list *def);
+ bool spvar_fill_type_reference(THD *thd, sp_variable *spvar,
+ const LEX_CSTRING &table,
+ const LEX_CSTRING &column);
+ bool spvar_fill_type_reference(THD *thd, sp_variable *spvar,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &table,
+ const LEX_CSTRING &column);
+ bool spvar_fill_table_rowtype_reference(THD *thd, sp_variable *spvar,
+ const LEX_CSTRING &table);
+ bool spvar_fill_table_rowtype_reference(THD *thd, sp_variable *spvar,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &table);
+
+ void set_chistics(const st_sp_chistics &chistics);
void set_info(longlong created, longlong modified,
- st_sp_chistics *chistics, sql_mode_t sql_mode);
+ const st_sp_chistics &chistics, sql_mode_t sql_mode);
- void set_definer(const char *definer, uint definerlen);
- void set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name);
+ void set_definer(const char *definer, uint definerlen)
+ {
+ AUTHID tmp;
+ tmp.parse(definer, definerlen);
+ m_definer.copy(mem_root, &tmp.user, &tmp.host);
+ }
+ void set_definer(const LEX_CSTRING *user_name, const LEX_CSTRING *host_name)
+ {
+ m_definer.copy(mem_root, user_name, host_name);
+ }
void reset_thd_mem_root(THD *thd);
@@ -445,8 +752,6 @@ public:
*/
void add_mark_lead(uint ip, List<sp_instr> *leads);
- void recursion_level_error(THD *thd);
-
inline sp_instr *
get_instr(uint i)
{
@@ -511,7 +816,7 @@ public:
DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
prelocking_ctx->get_stmt_unsafe_flags()));
DBUG_PRINT("info", ("sp_head(0x%p=%s)->unsafe_flags: 0x%x",
- this, name(), unsafe_flags));
+ this, name()->str, unsafe_flags));
prelocking_ctx->set_stmt_unsafe_flags(unsafe_flags);
DBUG_VOID_RETURN;
}
@@ -520,6 +825,8 @@ public:
void set_select_number(uint num) { m_select_number= num; }
+ bool check_execute_access(THD *thd) const;
+
private:
MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root
@@ -528,12 +835,17 @@ private:
sp_pcontext *m_pcont; ///< Parse context
List<LEX> m_lex; ///< Temp. store for the other lex
DYNAMIC_ARRAY m_instr; ///< The "instructions"
+
+ enum backpatch_instr_type { GOTO, CPOP, HPOP };
typedef struct
{
sp_label *lab;
sp_instr *instr;
+ backpatch_instr_type instr_type;
} bp_t;
List<bp_t> m_backpatch; ///< Instructions needing backpatching
+ List<bp_t> m_backpatch_goto; // Instructions needing backpatching (for goto)
+
/**
We need a special list for backpatching of instructions with a continue
destination (in the case of a continue handler catching an error in
@@ -571,9 +883,55 @@ private:
by routine.
*/
bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check);
+
+ /// Put the instruction on the a backpatch list, associated with the label.
+ int
+ push_backpatch(THD *thd, sp_instr *, sp_label *, List<bp_t> *list,
+ backpatch_instr_type itype);
+
}; // class sp_head : public Sql_alloc
+class sp_lex_cursor: public sp_lex_local, public Query_arena
+{
+ LEX_CSTRING m_cursor_name;
+public:
+ sp_lex_cursor(THD *thd, const LEX *oldlex, MEM_ROOT *mem_root_arg)
+ :sp_lex_local(thd, oldlex),
+ Query_arena(mem_root_arg, STMT_INITIALIZED_FOR_SP),
+ m_cursor_name(null_clex_str)
+ { }
+ sp_lex_cursor(THD *thd, const LEX *oldlex)
+ :sp_lex_local(thd, oldlex),
+ Query_arena(thd->lex->sphead->get_main_mem_root(), STMT_INITIALIZED_FOR_SP)
+ { }
+ ~sp_lex_cursor() { free_items(); }
+ void cleanup_stmt() { }
+ Query_arena *query_arena() { return this; }
+ bool validate()
+ {
+ DBUG_ASSERT(sql_command == SQLCOM_SELECT);
+ if (result)
+ {
+ my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0));
+ return true;
+ }
+ return false;
+ }
+ bool stmt_finalize(THD *thd)
+ {
+ if (validate())
+ return true;
+ sp_lex_in_use= true;
+ free_list= thd->free_list;
+ thd->free_list= NULL;
+ return false;
+ }
+ const LEX_CSTRING *cursor_name() const { return &m_cursor_name; }
+ void set_cursor_name(const LEX_CSTRING *name) { m_cursor_name= *name; }
+};
+
+
//
// "Instructions"...
//
@@ -588,6 +946,7 @@ public:
uint marked;
uint m_ip; ///< My index
sp_pcontext *m_ctx; ///< My parse context
+ uint m_lineno;
/// Should give each a name or type code for debugging purposes?
sp_instr(uint ip, sp_pcontext *ctx)
@@ -731,6 +1090,9 @@ public:
int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables,
sp_instr* instr);
+ int cursor_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;
@@ -740,6 +1102,11 @@ public:
{
m_lex->safe_to_cache_query= 0;
}
+
+ const LEX_CSTRING *cursor_name() const
+ {
+ return m_lex->cursor_name();
+ }
private:
LEX *m_lex;
@@ -813,9 +1180,9 @@ class sp_instr_set : public sp_instr
public:
sp_instr_set(uint ip, sp_pcontext *ctx,
- uint offset, Item *val, enum enum_field_types type_arg,
+ uint offset, Item *val,
LEX *lex, bool lex_resp)
- : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type_arg),
+ : sp_instr(ip, ctx), m_offset(offset), m_value(val),
m_lex_keeper(lex, lex_resp)
{}
@@ -828,16 +1195,87 @@ public:
virtual void print(String *str);
-private:
+protected:
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
+/*
+ This class handles assignments of a ROW fields:
+ DECLARE rec ROW (a INT,b INT);
+ SET rec.a= 10;
+*/
+class sp_instr_set_row_field : public sp_instr_set
+{
+ sp_instr_set_row_field(const sp_instr_set_row_field &); // Prevent use of this
+ void operator=(sp_instr_set_row_field &);
+ uint m_field_offset;
+
+public:
+
+ sp_instr_set_row_field(uint ip, sp_pcontext *ctx,
+ uint offset, uint field_offset,
+ Item *val,
+ LEX *lex, bool lex_resp)
+ : sp_instr_set(ip, ctx, offset, val, lex, lex_resp),
+ m_field_offset(field_offset)
+ {}
+
+ virtual ~sp_instr_set_row_field()
+ {}
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+}; // class sp_instr_set_field : public sp_instr_set
+
+
+/**
+ This class handles assignment instructions like this:
+ DECLARE
+ CURSOR cur IS SELECT * FROM t1;
+ rec cur%ROWTYPE;
+ BEGIN
+ rec.column1:= 10; -- This instruction
+ END;
+
+ The idea is that during sp_rcontext::create() we do not know the extact
+ structure of "rec". It gets resolved at run time, during the corresponding
+ sp_instr_cursor_copy_struct::exec_core().
+
+ So sp_instr_set_row_field_by_name searches for ROW fields by name,
+ while sp_instr_set_row_field (see above) searches for ROW fields by index.
+*/
+class sp_instr_set_row_field_by_name : public sp_instr_set
+{
+ // Prevent use of this
+ sp_instr_set_row_field_by_name(const sp_instr_set_row_field &);
+ void operator=(sp_instr_set_row_field_by_name &);
+ const LEX_CSTRING m_field_name;
+
+public:
+
+ sp_instr_set_row_field_by_name(uint ip, sp_pcontext *ctx,
+ uint offset, const LEX_CSTRING &field_name,
+ Item *val,
+ LEX *lex, bool lex_resp)
+ : sp_instr_set(ip, ctx, offset, val, lex, lex_resp),
+ m_field_name(field_name)
+ {}
+
+ virtual ~sp_instr_set_row_field_by_name()
+ {}
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+}; // class sp_instr_set_field_by_name : public sp_instr_set
+
+
/**
Set NEW/OLD row field value instruction. Used in triggers.
*/
@@ -1009,6 +1447,41 @@ private:
}; // class sp_instr_jump_if_not : public sp_instr_jump
+class sp_instr_preturn : public sp_instr
+{
+ sp_instr_preturn(const sp_instr_preturn &); /**< Prevent use of these */
+ void operator=(sp_instr_preturn &);
+
+public:
+
+ sp_instr_preturn(uint ip, sp_pcontext *ctx)
+ : sp_instr(ip, ctx)
+ {}
+
+ virtual ~sp_instr_preturn()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp)
+ {
+ DBUG_ENTER("sp_instr_preturn::execute");
+ *nextp= UINT_MAX;
+ DBUG_RETURN(0);
+ }
+
+ virtual void print(String *str)
+ {
+ str->append(STRING_WITH_LEN("preturn"));
+ }
+
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
+ {
+ marked= 1;
+ return UINT_MAX;
+ }
+
+}; // class sp_instr_preturn : public sp_instr
+
+
class sp_instr_freturn : public sp_instr
{
sp_instr_freturn(const sp_instr_freturn &); /**< Prevent use of these */
@@ -1017,8 +1490,8 @@ class sp_instr_freturn : public sp_instr
public:
sp_instr_freturn(uint ip, sp_pcontext *ctx,
- Item *val, enum enum_field_types type_arg, LEX *lex)
- : sp_instr(ip, ctx), m_value(val), m_type(type_arg),
+ Item *val, const Type_handler *handler, LEX *lex)
+ : sp_instr(ip, ctx), m_value(val), m_type_handler(handler),
m_lex_keeper(lex, TRUE)
{}
@@ -1040,7 +1513,7 @@ public:
protected:
Item *m_value;
- enum enum_field_types m_type;
+ const Type_handler *m_type_handler;
sp_lex_keeper m_lex_keeper;
}; // class sp_instr_freturn : public sp_instr
@@ -1127,6 +1600,11 @@ public:
virtual ~sp_instr_hpop()
{}
+ void update_count(uint count)
+ {
+ m_count= count;
+ }
+
virtual int execute(THD *thd, uint *nextp);
virtual void print(String *str);
@@ -1219,6 +1697,11 @@ public:
virtual ~sp_instr_cpop()
{}
+ void update_count(uint count)
+ {
+ m_count= count;
+ }
+
virtual int execute(THD *thd, uint *nextp);
virtual void print(String *str);
@@ -1257,6 +1740,30 @@ private:
}; // class sp_instr_copen : public sp_instr_stmt
+/**
+ Initialize the structure of a cursor%ROWTYPE variable
+ from the LEX containing the cursor SELECT statement.
+*/
+class sp_instr_cursor_copy_struct: public sp_instr
+{
+ /**< Prevent use of these */
+ sp_instr_cursor_copy_struct(const sp_instr_cursor_copy_struct &);
+ void operator=(sp_instr_cursor_copy_struct &);
+ sp_lex_keeper m_lex_keeper;
+ uint m_var;
+public:
+ sp_instr_cursor_copy_struct(uint ip, sp_pcontext *ctx,
+ sp_lex_cursor *lex, uint voffs)
+ : sp_instr(ip, ctx), m_lex_keeper(lex, FALSE), m_var(voffs)
+ {}
+ virtual ~sp_instr_cursor_copy_struct()
+ {}
+ virtual int execute(THD *thd, uint *nextp);
+ virtual int exec_core(THD *thd, uint *nextp);
+ virtual void print(String *str);
+};
+
+
class sp_instr_cclose : public sp_instr
{
sp_instr_cclose(const sp_instr_cclose &); /**< Prevent use of these */
@@ -1393,8 +1900,7 @@ void
sp_restore_security_context(THD *thd, Security_context *backup);
bool
-set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
- Security_context **save_ctx);
+set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
TABLE_LIST *
@@ -1404,10 +1910,11 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
enum_mdl_type mdl_type);
Item *
-sp_prepare_func_item(THD* thd, Item **it_addr);
+sp_prepare_func_item(THD* thd, Item **it_addr, uint cols= 1);
bool
-sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr);
+sp_eval_expr(THD *thd, Item *result_item, Field *result_field,
+ Item **expr_item_ptr);
/**
@} (end of group Stored_Routines)