summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/item_xmlfunc.cc4
-rw-r--r--sql/opt_subselect.cc4
-rw-r--r--sql/sp_head.cc264
-rw-r--r--sql/sp_head.h55
-rw-r--r--sql/sp_pcontext.cc563
-rw-r--r--sql/sp_pcontext.h813
-rw-r--r--sql/sp_rcontext.cc720
-rw-r--r--sql/sp_rcontext.h589
-rw-r--r--sql/sql_array.h120
-rw-r--r--sql/sql_class.cc18
-rw-r--r--sql/sql_class.h31
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_error.cc29
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_prepare.cc4
-rw-r--r--sql/sql_show.cc10
-rw-r--r--sql/sql_signal.cc35
-rw-r--r--sql/sql_signal.h8
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_yacc.yy234
21 files changed, 1737 insertions, 1772 deletions
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index b05d1da82a5..c1b09d16430 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -2501,12 +2501,12 @@ my_xpath_parse_VariableReference(MY_XPATH *xpath)
xpath->item= new Item_func_get_user_var(name);
else
{
- sp_variable_t *spv;
+ sp_variable *spv;
sp_pcontext *spc;
LEX *lex;
if ((lex= current_thd->lex) &&
(spc= lex->spcont) &&
- (spv= spc->find_variable(&name)))
+ (spv= spc->find_variable(name, false)))
{
Item_splocal *splocal= new Item_splocal(name, spv->offset, spv->type, 0);
#ifndef DBUG_OFF
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 4d3d60fc2f5..bda9532e874 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -5060,7 +5060,7 @@ public:
select_value_catcher(Item_subselect *item_arg)
:select_subselect(item_arg)
{}
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
int setup(List<Item> *items);
bool assigned; /* TRUE <=> we've caught a value */
uint n_elements; /* How many elements we get */
@@ -5088,7 +5088,7 @@ int select_value_catcher::setup(List<Item> *items)
}
-int select_value_catcher::send_data(List<Item> &items)
+bool select_value_catcher::send_data(List<Item> &items)
{
DBUG_ENTER("select_value_catcher::send_data");
DBUG_ASSERT(!assigned);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 59363a7a04a..03631e107db 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -772,7 +772,7 @@ sp_head::~sp_head()
for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
delete i;
delete_dynamic(&m_instr);
- m_pcont->destroy();
+ delete m_pcont;
free_items();
/*
@@ -1078,104 +1078,6 @@ void sp_head::recursion_level_error(THD *thd)
}
-/**
- Find an SQL handler for any condition (warning or error) after execution
- of a stored routine instruction. Basically, this function looks for an
- appropriate SQL handler in RT-contexts. If an SQL handler is found, it is
- remembered in the RT-context for future activation (the context can be
- inactive at the moment).
-
- If there is no pending condition, the function just returns.
-
- If there was an error during the execution, an SQL handler for it will be
- searched within the current and outer scopes.
-
- There might be several errors in the Warning Info (that's possible by using
- SIGNAL/RESIGNAL in nested scopes) -- the function is looking for an SQL
- handler for the latest (current) error only.
-
- If there was a warning during the execution, an SQL handler for it will be
- searched within the current scope only.
-
- If several warnings were thrown during the execution and there are different
- SQL handlers for them, it is not determined which SQL handler will be chosen.
- Only one SQL handler will be executed.
-
- If warnings and errors were thrown during the execution, the error takes
- precedence. I.e. error handler will be executed. If there is no handler
- for that error, condition will remain unhandled.
-
- Once a warning or an error has been handled it is not removed from
- Warning Info.
-
- According to The Standard (quoting PeterG):
-
- An SQL procedure statement works like this ...
- SQL/Foundation 13.5 <SQL procedure statement>
- (General Rules) (greatly summarized) says:
- (1) Empty diagnostics area, thus clearing the condition.
- (2) Execute statement.
- During execution, if Exception Condition occurs,
- set Condition Area = Exception Condition and stop
- statement.
- During execution, if No Data occurs,
- set Condition Area = No Data Condition and continue
- statement.
- During execution, if Warning occurs,
- and Condition Area is not already full due to
- an earlier No Data condition, set Condition Area
- = Warning and continue statement.
- (3) Finish statement.
- At end of execution, if Condition Area is not
- already full due to an earlier No Data or Warning,
- set Condition Area = Successful Completion.
- In effect, this system means there is a precedence:
- Exception trumps No Data, No Data trumps Warning,
- Warning trumps Successful Completion.
-
- NB: "Procedure statements" include any DDL or DML or
- control statements. So CREATE and DELETE and WHILE
- and CALL and RETURN are procedure statements. But
- DECLARE and END are not procedure statements.
-
- @param thd thread handle
- @param ctx runtime context of the stored routine
-*/
-
-static void
-find_handler_after_execution(THD *thd, sp_rcontext *ctx)
-{
- if (thd->is_error())
- {
- ctx->find_handler(thd,
- thd->get_stmt_da()->sql_errno(),
- thd->get_stmt_da()->get_sqlstate(),
- Sql_condition::WARN_LEVEL_ERROR,
- thd->get_stmt_da()->message());
- }
- else if (thd->get_stmt_da()->statement_warn_count())
- {
- Diagnostics_area::Sql_condition_iterator it=
- thd->get_stmt_da()->sql_conditions();
- const Sql_condition *err;
- while ((err= it++))
- {
- if (err->get_level() != Sql_condition::WARN_LEVEL_WARN &&
- err->get_level() != Sql_condition::WARN_LEVEL_NOTE)
- continue;
-
- if (ctx->find_handler(thd,
- err->get_sql_errno(),
- err->get_sqlstate(),
- err->get_level(),
- err->get_message_text()))
- {
- break;
- }
- }
- }
-}
-
/**
Execute the routine. The main instruction jump loop is there.
@@ -1445,19 +1347,10 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
errors are not catchable by SQL handlers) or the connection has been
killed during execution.
*/
- if (!thd->is_fatal_error && !thd->killed_errno())
+ if (!thd->is_fatal_error && !thd->killed_errno() &&
+ ctx->handle_sql_condition(thd, &ip, i))
{
- /*
- Find SQL handler in the appropriate RT-contexts:
- - warnings can be handled by SQL handlers within
- the current scope only;
- - errors can be handled by any SQL handler from outer scope.
- */
- find_handler_after_execution(thd, ctx);
-
- /* If found, activate handler for the current scope. */
- if (ctx->activate_handler(thd, &ip, i, &execute_arena, &backup_arena))
- err_status= FALSE;
+ err_status= FALSE;
}
/* Reset sp_rcontext::end_partial_result_set flag. */
@@ -1743,8 +1636,7 @@ sp_head::execute_trigger(THD *thd,
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
- if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) ||
- nctx->init(thd))
+ if (!(nctx= sp_rcontext::create(thd, m_pcont, NULL)))
{
err_status= TRUE;
goto err_with_cleanup;
@@ -1860,8 +1752,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
- if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) ||
- nctx->init(thd))
+ if (!(nctx= sp_rcontext::create(thd, m_pcont, return_value_fld)))
{
thd->restore_active_arena(&call_arena, &backup_arena);
err_status= TRUE;
@@ -2078,7 +1969,6 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (! octx)
{
/* Create a temporary old context. */
- if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || octx->init(thd))
{
delete octx; /* Delete octx if it was init() that failed. */
DBUG_RETURN(TRUE);
@@ -2093,8 +1983,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
thd->spcont->callers_arena= thd;
}
- if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) ||
- nctx->init(thd))
+ if (!(nctx= sp_rcontext::create(thd, m_pcont, NULL)))
{
delete nctx; /* Delete nctx if it was init() that failed. */
thd->spcont= save_spcont;
@@ -2117,12 +2006,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!arg_item)
break;
- sp_variable_t *spvar= m_pcont->find_variable(i);
+ sp_variable *spvar= m_pcont->find_variable(i);
if (!spvar)
continue;
- if (spvar->mode != sp_param_in)
+ if (spvar->mode != sp_variable::MODE_IN)
{
Settable_routine_parameter *srp=
arg_item->get_settable_routine_parameter();
@@ -2134,10 +2023,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
break;
}
- srp->set_required_privilege(spvar->mode == sp_param_inout);
+ srp->set_required_privilege(spvar->mode == sp_variable::MODE_INOUT);
}
- if (spvar->mode == sp_param_out)
+ if (spvar->mode == sp_variable::MODE_OUT)
{
Item_null *null_item= new Item_null();
Item *tmp_item= null_item;
@@ -2237,9 +2126,9 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!arg_item)
break;
- sp_variable_t *spvar= m_pcont->find_variable(i);
+ sp_variable *spvar= m_pcont->find_variable(i);
- if (spvar->mode == sp_param_in)
+ if (spvar->mode == sp_variable::MODE_IN)
continue;
Settable_routine_parameter *srp=
@@ -2399,7 +2288,7 @@ sp_head::restore_lex(THD *thd)
Put the instruction on the backpatch list, associated with the label.
*/
int
-sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
+sp_head::push_backpatch(sp_instr *i, sp_label *lab)
{
bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t));
@@ -2415,7 +2304,7 @@ sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
the current position.
*/
void
-sp_head::backpatch(sp_label_t *lab)
+sp_head::backpatch(sp_label *lab)
{
bp_t *bp;
uint dest= instructions();
@@ -2427,7 +2316,7 @@ sp_head::backpatch(sp_label_t *lab)
if (bp->lab == lab)
{
DBUG_PRINT("info", ("backpatch: (m_ip %d, label 0x%lx <%s>) to dest %d",
- bp->instr->m_ip, (ulong) lab, lab->name, dest));
+ bp->instr->m_ip, (ulong) lab, lab->name.str, dest));
bp->instr->backpatch(dest, lab->ctx);
}
}
@@ -3107,7 +2996,7 @@ int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
return result;
}
-uint sp_instr::get_cont_dest()
+uint sp_instr::get_cont_dest() const
{
return (m_ip+1);
}
@@ -3261,7 +3150,7 @@ sp_instr_set::print(String *str)
{
/* set name@offset ... */
int rsrv = SP_INSTR_UINT_MAXLEN+6;
- sp_variable_t *var = m_ctx->find_variable(m_offset);
+ sp_variable *var = m_ctx->find_variable(m_offset);
/* 'var' should always be non-null, but just in case... */
if (var)
@@ -3314,7 +3203,7 @@ sp_instr_set_trigger_field::print(String *str)
sp_instr_opt_meta
*/
-uint sp_instr_opt_meta::get_cont_dest()
+uint sp_instr_opt_meta::get_cont_dest() const
{
return m_cont_dest;
}
@@ -3532,14 +3421,12 @@ int
sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_hpush_jump::execute");
- List_iterator_fast<sp_cond_type_t> li(m_cond);
- sp_cond_type_t *p;
- while ((p= li++))
- thd->spcont->push_handler(p, m_ip+1, m_type);
+ int ret= thd->spcont->push_handler(m_handler, m_ip + 1);
*nextp= m_dest;
- DBUG_RETURN(0);
+
+ DBUG_RETURN(ret);
}
@@ -3549,27 +3436,22 @@ sp_instr_hpush_jump::print(String *str)
/* hpush_jump dest fsize type */
if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21))
return;
+
str->qs_append(STRING_WITH_LEN("hpush_jump "));
str->qs_append(m_dest);
str->qs_append(' ');
str->qs_append(m_frame);
- switch (m_type) {
- case SP_HANDLER_NONE:
- str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug
- break;
- case SP_HANDLER_EXIT:
+
+ switch (m_handler->type) {
+ case sp_handler::EXIT:
str->qs_append(STRING_WITH_LEN(" EXIT"));
break;
- case SP_HANDLER_CONTINUE:
+ case sp_handler::CONTINUE:
str->qs_append(STRING_WITH_LEN(" CONTINUE"));
break;
- case SP_HANDLER_UNDO:
- str->qs_append(STRING_WITH_LEN(" UNDO"));
- break;
default:
- // This would be a bug as well
- str->qs_append(STRING_WITH_LEN(" UNKNOWN:"));
- str->qs_append(m_type);
+ // The handler type must be either CONTINUE or EXIT.
+ DBUG_ASSERT(0);
}
}
@@ -3597,7 +3479,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
above, so we start on m_dest+1 here.
m_opt_hpop is the hpop marking the end of the handler scope.
*/
- if (m_type == SP_HANDLER_CONTINUE)
+ if (m_handler->type == sp_handler::CONTINUE)
{
for (uint scope_ip= m_dest+1; scope_ip <= m_opt_hpop; scope_ip++)
sp->add_mark_lead(scope_ip, leads);
@@ -3639,13 +3521,11 @@ int
sp_instr_hreturn::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_hreturn::execute");
- if (m_dest)
- *nextp= m_dest;
- else
- {
- *nextp= thd->spcont->pop_hstack();
- }
- thd->spcont->exit_handler();
+
+ uint continue_ip= thd->spcont->exit_handler(thd->get_stmt_da());
+
+ *nextp= m_dest ? m_dest : continue_ip;
+
DBUG_RETURN(0);
}
@@ -3657,12 +3537,17 @@ sp_instr_hreturn::print(String *str)
if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9))
return;
str->qs_append(STRING_WITH_LEN("hreturn "));
- str->qs_append(m_frame);
if (m_dest)
{
- str->qs_append(' ');
+ // NOTE: this is legacy: hreturn instruction for EXIT handler
+ // should print out 0 as frame index.
+ str->qs_append(STRING_WITH_LEN("0 "));
str->qs_append(m_dest);
}
+ else
+ {
+ str->qs_append(m_frame);
+ }
}
@@ -3694,41 +3579,32 @@ sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
- Query_arena backup_arena;
DBUG_ENTER("sp_instr_cpush::execute");
- /*
- We should create cursors in the callers arena, as
- it could be (and usually is) used in several instructions.
- */
- thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena);
-
- thd->spcont->push_cursor(&m_lex_keeper, this);
-
- thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
+ int ret= thd->spcont->push_cursor(&m_lex_keeper, this);
*nextp= m_ip+1;
- DBUG_RETURN(0);
+ DBUG_RETURN(ret);
}
void
sp_instr_cpush::print(String *str)
{
- LEX_STRING n;
- my_bool found= m_ctx->find_cursor(m_cursor, &n);
+ const LEX_STRING *cursor_name= m_ctx->find_cursor(m_cursor);
+
/* cpush name@offset */
uint rsrv= SP_INSTR_UINT_MAXLEN+7;
- if (found)
- rsrv+= n.length;
+ if (cursor_name)
+ rsrv+= cursor_name->length;
if (str->reserve(rsrv))
return;
str->qs_append(STRING_WITH_LEN("cpush "));
- if (found)
+ if (cursor_name)
{
- str->qs_append(n.str, n.length);
+ str->qs_append(cursor_name->str, cursor_name->length);
str->qs_append('@');
}
str->qs_append(m_cursor);
@@ -3816,19 +3692,19 @@ sp_instr_copen::exec_core(THD *thd, uint *nextp)
void
sp_instr_copen::print(String *str)
{
- LEX_STRING n;
- my_bool found= m_ctx->find_cursor(m_cursor, &n);
+ const LEX_STRING *cursor_name= m_ctx->find_cursor(m_cursor);
+
/* copen name@offset */
uint rsrv= SP_INSTR_UINT_MAXLEN+7;
- if (found)
- rsrv+= n.length;
+ if (cursor_name)
+ rsrv+= cursor_name->length;
if (str->reserve(rsrv))
return;
str->qs_append(STRING_WITH_LEN("copen "));
- if (found)
+ if (cursor_name)
{
- str->qs_append(n.str, n.length);
+ str->qs_append(cursor_name->str, cursor_name->length);
str->qs_append('@');
}
str->qs_append(m_cursor);
@@ -3858,19 +3734,19 @@ sp_instr_cclose::execute(THD *thd, uint *nextp)
void
sp_instr_cclose::print(String *str)
{
- LEX_STRING n;
- my_bool found= m_ctx->find_cursor(m_cursor, &n);
+ const LEX_STRING *cursor_name= m_ctx->find_cursor(m_cursor);
+
/* cclose name@offset */
uint rsrv= SP_INSTR_UINT_MAXLEN+8;
- if (found)
- rsrv+= n.length;
+ if (cursor_name)
+ rsrv+= cursor_name->length;
if (str->reserve(rsrv))
return;
str->qs_append(STRING_WITH_LEN("cclose "));
- if (found)
+ if (cursor_name)
{
- str->qs_append(n.str, n.length);
+ str->qs_append(cursor_name->str, cursor_name->length);
str->qs_append('@');
}
str->qs_append(m_cursor);
@@ -3899,21 +3775,21 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp)
void
sp_instr_cfetch::print(String *str)
{
- List_iterator_fast<struct sp_variable> li(m_varlist);
- sp_variable_t *pv;
- LEX_STRING n;
- my_bool found= m_ctx->find_cursor(m_cursor, &n);
+ List_iterator_fast<sp_variable> li(m_varlist);
+ sp_variable *pv;
+ const LEX_STRING *cursor_name= m_ctx->find_cursor(m_cursor);
+
/* cfetch name@offset vars... */
uint rsrv= SP_INSTR_UINT_MAXLEN+8;
- if (found)
- rsrv+= n.length;
+ if (cursor_name)
+ rsrv+= cursor_name->length;
if (str->reserve(rsrv))
return;
str->qs_append(STRING_WITH_LEN("cfetch "));
- if (found)
+ if (cursor_name)
{
- str->qs_append(n.str, n.length);
+ str->qs_append(cursor_name->str, cursor_name->length);
str->qs_append('@');
}
str->qs_append(m_cursor);
diff --git a/sql/sp_head.h b/sql/sp_head.h
index f5254c2ead2..f91e30ab8a4 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -30,8 +30,9 @@
#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_class.h" // THD, set_var.h: THD
#include "set_var.h" // Item
-#include "sp.h"
+#include "sp_pcontext.h" // sp_pcontext
#include <stddef.h>
+#include "sp.h"
/**
@defgroup Stored_Routines Stored Routines
@@ -39,6 +40,11 @@
@{
*/
+// 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_result
sp_map_result_type(enum enum_field_types type);
@@ -48,12 +54,9 @@ sp_map_item_type(enum enum_field_types type);
uint
sp_get_flags_for_command(LEX *lex);
-struct sp_label;
class sp_instr;
class sp_instr_opt_meta;
class sp_instr_jump_if_not;
-struct sp_cond_type;
-struct sp_variable;
/*************************************************************************/
@@ -602,7 +605,7 @@ public:
Get the continuation destination of this instruction.
@return the continuation destination
*/
- virtual uint get_cont_dest();
+ virtual uint get_cont_dest() const;
/*
Execute core function of instruction after all preparations (e.g.
@@ -874,7 +877,7 @@ public:
virtual void set_destination(uint old_dest, uint new_dest)
= 0;
- virtual uint get_cont_dest();
+ virtual uint get_cont_dest() const;
protected:
@@ -1025,15 +1028,21 @@ class sp_instr_hpush_jump : public sp_instr_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_opt_hpop(0)
+ sp_instr_hpush_jump(uint ip,
+ sp_pcontext *ctx,
+ sp_handler *handler)
+ :sp_instr_jump(ip, ctx),
+ m_handler(handler),
+ m_opt_hpop(0),
+ m_frame(ctx->current_var_count())
{
- m_cond.empty();
+ DBUG_ASSERT(m_handler->condition_values.elements == 0);
}
virtual ~sp_instr_hpush_jump()
{
- m_cond.empty();
+ m_handler->condition_values.empty();
+ m_handler= NULL;
}
virtual int execute(THD *thd, uint *nextp);
@@ -1057,17 +1066,24 @@ public:
m_opt_hpop= dest;
}
- inline void add_condition(struct sp_cond_type *cond)
- {
- m_cond.push_front(cond);
- }
+ void add_condition(sp_condition_value *condition_value)
+ { m_handler->condition_values.push_back(condition_value); }
+
+ sp_handler *get_handler()
+ { return m_handler; }
+
+private:
private:
+ /// Handler.
+ sp_handler *m_handler;
+
+ /// hpop marking end of handler scope.
+ uint m_opt_hpop;
- int m_type; ///< Handler type
+ // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
+ // debug version only). It's used in print().
uint m_frame;
- uint m_opt_hpop; // hpop marking end of handler scope.
- List<struct sp_cond_type> m_cond;
}; // class sp_instr_hpush_jump : public sp_instr_jump
@@ -1104,8 +1120,9 @@ class sp_instr_hreturn : public sp_instr_jump
public:
- sp_instr_hreturn(uint ip, sp_pcontext *ctx, uint fp)
- : sp_instr_jump(ip, ctx), m_frame(fp)
+ sp_instr_hreturn(uint ip, sp_pcontext *ctx)
+ :sp_instr_jump(ip, ctx),
+ m_frame(ctx->current_var_count())
{}
virtual ~sp_instr_hreturn()
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index f11daeecb7b..fc2f3e8bb2f 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -22,133 +22,86 @@
#include "sp_pcontext.h"
#include "sp_head.h"
-/* Initial size for the dynamic arrays in sp_pcontext */
-#define PCONTEXT_ARRAY_INIT_ALLOC 16
-/* Increment size for the dynamic arrays in sp_pcontext */
-#define PCONTEXT_ARRAY_INCREMENT_ALLOC 8
-
-/*
- Sanity check for SQLSTATEs. Will not check if it's really an existing
- state (there are just too many), but will check length and bad characters.
- Returns TRUE if it's ok, FALSE if it's bad.
-*/
-bool
-sp_cond_check(LEX_STRING *sqlstate)
+bool sp_condition_value::equals(const sp_condition_value *cv) const
{
- int i;
- const char *p;
+ DBUG_ASSERT(cv);
- if (sqlstate->length != 5)
- return FALSE;
- for (p= sqlstate->str, i= 0 ; i < 5 ; i++)
+ if (this == cv)
+ return true;
+
+ if (type != cv->type)
+ return false;
+
+ switch (type)
{
- char c = p[i];
+ case sp_condition_value::ERROR_CODE:
+ return (mysqlerr == cv->mysqlerr);
+
+ case sp_condition_value::SQLSTATE:
+ return (strcmp(sql_state, cv->sql_state) == 0);
- if ((c < '0' || '9' < c) &&
- (c < 'A' || 'Z' < c))
- return FALSE;
+ default:
+ return true;
}
- /* SQLSTATE class '00' : completion condition */
- if (strncmp(sqlstate->str, "00", 2) == 0)
- return FALSE;
- return TRUE;
}
+
+void sp_pcontext::init(uint var_offset,
+ uint cursor_offset,
+ int num_case_expressions)
+{
+ m_var_offset= var_offset;
+ m_cursor_offset= cursor_offset;
+ m_num_case_exprs= num_case_expressions;
+
+ m_labels.empty();
+}
+
+
sp_pcontext::sp_pcontext()
: Sql_alloc(),
- m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
- m_context_handlers(0), m_parent(NULL), m_pboundary(0),
- m_label_scope(LABEL_DEFAULT_SCOPE)
+ m_max_var_index(0), m_max_cursor_index(0),
+ m_parent(NULL), m_pboundary(0),
+ m_scope(REGULAR_SCOPE)
{
- (void) my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- (void) my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- (void) my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- (void) my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- (void) my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- m_label.empty();
- m_children.empty();
-
- m_var_offset= m_cursor_offset= 0;
- m_num_case_exprs= 0;
+ init(0, 0, 0);
}
-sp_pcontext::sp_pcontext(sp_pcontext *prev, label_scope_type label_scope)
+
+sp_pcontext::sp_pcontext(sp_pcontext *prev, sp_pcontext::enum_scope scope)
: Sql_alloc(),
- m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
- m_context_handlers(0), m_parent(prev), m_pboundary(0),
- m_label_scope(label_scope)
+ m_max_var_index(0), m_max_cursor_index(0),
+ m_parent(prev), m_pboundary(0),
+ m_scope(scope)
{
- (void) my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- (void) my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- (void) my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- (void) my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- (void) my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
- PCONTEXT_ARRAY_INIT_ALLOC,
- PCONTEXT_ARRAY_INCREMENT_ALLOC, MYF(0));
- m_label.empty();
- m_children.empty();
-
- m_var_offset= prev->m_var_offset + prev->m_max_var_index;
- m_cursor_offset= prev->current_cursor_count();
- m_num_case_exprs= prev->get_num_case_exprs();
+ init(prev->m_var_offset + prev->m_max_var_index,
+ prev->current_cursor_count(),
+ prev->get_num_case_exprs());
}
-void
-sp_pcontext::destroy()
+
+sp_pcontext::~sp_pcontext()
{
- List_iterator_fast<sp_pcontext> li(m_children);
- sp_pcontext *child;
-
- while ((child= li++))
- child->destroy();
-
- m_children.empty();
- m_label.empty();
- delete_dynamic(&m_vars);
- delete_dynamic(&m_case_expr_id_lst);
- delete_dynamic(&m_conds);
- delete_dynamic(&m_cursors);
- delete_dynamic(&m_handlers);
+ for (int i= 0; i < m_children.elements(); ++i)
+ delete m_children.at(i);
}
-sp_pcontext *
-sp_pcontext::push_context(label_scope_type label_scope)
+
+sp_pcontext *sp_pcontext::push_context(THD *thd, sp_pcontext::enum_scope scope)
{
- sp_pcontext *child= new sp_pcontext(this, label_scope);
+ sp_pcontext *child= new (thd->mem_root) sp_pcontext(this, scope);
if (child)
- m_children.push_back(child);
+ m_children.append(child);
return child;
}
-sp_pcontext *
-sp_pcontext::pop_context()
+
+sp_pcontext *sp_pcontext::pop_context()
{
m_parent->m_max_var_index+= m_max_var_index;
- uint submax= max_handler_index();
- if (submax > m_parent->m_max_handler_index)
- m_parent->m_max_handler_index= submax;
-
- submax= max_cursor_index();
+ uint submax= max_cursor_index();
if (submax > m_parent->m_max_cursor_index)
m_parent->m_max_cursor_index= submax;
@@ -158,142 +111,118 @@ sp_pcontext::pop_context()
return m_parent;
}
-uint
-sp_pcontext::diff_handlers(sp_pcontext *ctx, bool exclusive)
+
+uint sp_pcontext::diff_handlers(const sp_pcontext *ctx, bool exclusive) const
{
uint n= 0;
- sp_pcontext *pctx= this;
- sp_pcontext *last_ctx= NULL;
+ const sp_pcontext *pctx= this;
+ const sp_pcontext *last_ctx= NULL;
while (pctx && pctx != ctx)
{
- n+= pctx->m_context_handlers;
+ n+= pctx->m_handlers.elements();
last_ctx= pctx;
pctx= pctx->parent_context();
}
if (pctx)
- return (exclusive && last_ctx ? n - last_ctx->m_context_handlers : n);
+ return (exclusive && last_ctx ? n - last_ctx->m_handlers.elements() : n);
return 0; // Didn't find ctx
}
-uint
-sp_pcontext::diff_cursors(sp_pcontext *ctx, bool exclusive)
+
+uint sp_pcontext::diff_cursors(const sp_pcontext *ctx, bool exclusive) const
{
uint n= 0;
- sp_pcontext *pctx= this;
- sp_pcontext *last_ctx= NULL;
+ const sp_pcontext *pctx= this;
+ const sp_pcontext *last_ctx= NULL;
while (pctx && pctx != ctx)
{
- n+= pctx->m_cursors.elements;
+ n+= pctx->m_cursors.elements();
last_ctx= pctx;
pctx= pctx->parent_context();
}
if (pctx)
- return (exclusive && last_ctx ? n - last_ctx->m_cursors.elements : n);
+ return (exclusive && last_ctx ? n - last_ctx->m_cursors.elements() : n);
return 0; // Didn't find ctx
}
-/*
- This does a linear search (from newer to older variables, in case
- we have shadowed names).
- It's possible to have a more efficient allocation and search method,
- but it might not be worth it. The typical number of parameters and
- variables will in most cases be low (a handfull).
- ...and, this is only called during parsing.
-*/
-sp_variable_t *
-sp_pcontext::find_variable(LEX_STRING *name, my_bool scoped)
+
+sp_variable *sp_pcontext::find_variable(LEX_STRING name,
+ bool current_scope_only) const
{
- uint i= m_vars.elements - m_pboundary;
+ uint i= m_vars.elements() - m_pboundary;
while (i--)
{
- sp_variable_t *p;
+ sp_variable *p= m_vars.at(i);
- get_dynamic(&m_vars, (uchar*)&p, i);
if (my_strnncoll(system_charset_info,
- (const uchar *)name->str, name->length,
+ (const uchar *)name.str, name.length,
(const uchar *)p->name.str, p->name.length) == 0)
{
return p;
}
}
- if (!scoped && m_parent)
- return m_parent->find_variable(name, scoped);
- return NULL;
+
+ return (!current_scope_only && m_parent) ?
+ m_parent->find_variable(name, false) :
+ NULL;
}
-/*
- Find a variable by offset from the top.
- This used for two things:
- - When evaluating parameters at the beginning, and setting out parameters
- at the end, of invokation. (Top frame only, so no recursion then.)
- - For printing of sp_instr_set. (Debug mode only.)
-*/
-sp_variable_t *
-sp_pcontext::find_variable(uint offset)
+
+sp_variable *sp_pcontext::find_variable(uint offset) const
{
- if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements)
- { // This frame
- sp_variable_t *p;
+ if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements())
+ return m_vars.at(offset - m_var_offset); // This frame
- get_dynamic(&m_vars, (uchar*)&p, offset - m_var_offset);
- return p;
- }
- if (m_parent)
- return m_parent->find_variable(offset); // Some previous frame
- return NULL; // index out of bounds
+ return m_parent ?
+ m_parent->find_variable(offset) : // Some previous frame
+ NULL; // Index out of bounds
}
-sp_variable_t *
-sp_pcontext::push_variable(LEX_STRING *name, enum enum_field_types type,
- sp_param_mode_t mode)
+
+sp_variable *sp_pcontext::add_variable(THD *thd,
+ LEX_STRING name,
+ enum enum_field_types type,
+ sp_variable::enum_mode mode)
{
- sp_variable_t *p= (sp_variable_t *)sql_alloc(sizeof(sp_variable_t));
+ sp_variable *p=
+ new (thd->mem_root) sp_variable(name, type,mode, current_var_count());
if (!p)
return NULL;
++m_max_var_index;
- p->name.str= name->str;
- p->name.length= name->length;
- p->type= type;
- p->mode= mode;
- p->offset= current_var_count();
- p->dflt= NULL;
- if (insert_dynamic(&m_vars, (uchar*)&p))
- return NULL;
- return p;
+ return m_vars.append(p) ? NULL : p;
}
-sp_label_t *
-sp_pcontext::push_label(char *name, uint ip)
+sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip)
{
- sp_label_t *lab = (sp_label_t *)sql_alloc(sizeof(sp_label_t));
+ sp_label *label=
+ new (thd->mem_root) sp_label(name, ip, sp_label::IMPLICIT, this);
- if (lab)
- {
- lab->name= name;
- lab->ip= ip;
- lab->type= SP_LAB_IMPL;
- lab->ctx= this;
- m_label.push_front(lab);
- }
- return lab;
+ if (!label)
+ return NULL;
+
+ m_labels.push_front(label);
+
+ return label;
}
-sp_label_t *
-sp_pcontext::find_label(char *name)
+
+sp_label *sp_pcontext::find_label(LEX_STRING name)
{
- List_iterator_fast<sp_label_t> li(m_label);
- sp_label_t *lab;
+ List_iterator_fast<sp_label> li(m_labels);
+ sp_label *lab;
while ((lab= li++))
- if (my_strcasecmp(system_charset_info, name, lab->name) == 0)
+ {
+ if (my_strcasecmp(system_charset_info, name.str, lab->name.str) == 0)
return lab;
+ }
/*
Note about exception handlers.
@@ -303,159 +232,253 @@ sp_pcontext::find_label(char *name)
In short, a DECLARE HANDLER block can not refer
to labels from the parent context, as they are out of scope.
*/
- if (m_parent && (m_label_scope == LABEL_DEFAULT_SCOPE))
- return m_parent->find_label(name);
- return NULL;
+ return (m_parent && (m_scope == REGULAR_SCOPE)) ?
+ m_parent->find_label(name) :
+ NULL;
}
-int
-sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val)
+
+bool sp_pcontext::add_condition(THD *thd,
+ LEX_STRING name,
+ sp_condition_value *value)
{
- sp_cond_t *p= (sp_cond_t *)sql_alloc(sizeof(sp_cond_t));
+ sp_condition *p= new (thd->mem_root) sp_condition(name, value);
if (p == NULL)
- return 1;
- p->name.str= name->str;
- p->name.length= name->length;
- p->val= val;
- return insert_dynamic(&m_conds, (uchar *)&p);
+ return true;
+
+ return m_conditions.append(p);
}
-/*
- See comment for find_variable() above
-*/
-sp_cond_type_t *
-sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped)
+
+sp_condition_value *sp_pcontext::find_condition(LEX_STRING name,
+ bool current_scope_only) const
{
- uint i= m_conds.elements;
+ uint i= m_conditions.elements();
while (i--)
{
- sp_cond_t *p;
+ sp_condition *p= m_conditions.at(i);
- get_dynamic(&m_conds, (uchar*)&p, i);
if (my_strnncoll(system_charset_info,
- (const uchar *)name->str, name->length,
- (const uchar *)p->name.str, p->name.length) == 0)
+ (const uchar *) name.str, name.length,
+ (const uchar *) p->name.str, p->name.length) == 0)
{
- return p->val;
+ return p->value;
}
}
- if (!scoped && m_parent)
- return m_parent->find_cond(name, scoped);
- return NULL;
+
+ return (!current_scope_only && m_parent) ?
+ m_parent->find_condition(name, false) :
+ NULL;
}
-/*
- This only searches the current context, for error checking of
- duplicates.
- Returns TRUE if found.
-*/
-bool
-sp_pcontext::find_handler(sp_cond_type_t *cond)
+
+sp_handler *sp_pcontext::add_handler(THD *thd,
+ sp_handler::enum_type type)
{
- uint i= m_handlers.elements;
+ sp_handler *h= new (thd->mem_root) sp_handler(type);
- while (i--)
+ if (!h)
+ return NULL;
+
+ return m_handlers.append(h) ? NULL : h;
+}
+
+
+bool sp_pcontext::check_duplicate_handler(
+ const sp_condition_value *cond_value) const
+{
+ for (int i= 0; i < m_handlers.elements(); ++i)
{
- sp_cond_type_t *p;
+ sp_handler *h= m_handlers.at(i);
+
+ List_iterator_fast<sp_condition_value> li(h->condition_values);
+ sp_condition_value *cv;
- get_dynamic(&m_handlers, (uchar*)&p, i);
- if (cond->type == p->type)
+ while ((cv= li++))
{
- switch (p->type)
+ if (cond_value->equals(cv))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+sp_handler*
+sp_pcontext::find_handler(const char *sql_state,
+ uint sql_errno,
+ Sql_condition::enum_warning_level level) const
+{
+ sp_handler *found_handler= NULL;
+ sp_condition_value *found_cv= NULL;
+
+ for (int i= 0; i < m_handlers.elements(); ++i)
+ {
+ sp_handler *h= m_handlers.at(i);
+
+ List_iterator_fast<sp_condition_value> li(h->condition_values);
+ sp_condition_value *cv;
+
+ while ((cv= li++))
+ {
+ switch (cv->type)
{
- case sp_cond_type_t::number:
- if (cond->mysqlerr == p->mysqlerr)
- return TRUE;
- break;
- case sp_cond_type_t::state:
- if (strcmp(cond->sqlstate, p->sqlstate) == 0)
- return TRUE;
- break;
- default:
- return TRUE;
+ case sp_condition_value::ERROR_CODE:
+ if (sql_errno == cv->mysqlerr &&
+ (!found_cv ||
+ found_cv->type > sp_condition_value::ERROR_CODE))
+ {
+ found_cv= cv;
+ found_handler= h;
+ }
+ break;
+
+ case sp_condition_value::SQLSTATE:
+ if (strcmp(sql_state, cv->sql_state) == 0 &&
+ (!found_cv ||
+ found_cv->type > sp_condition_value::SQLSTATE))
+ {
+ found_cv= cv;
+ found_handler= h;
+ }
+ break;
+
+ case sp_condition_value::WARNING:
+ if ((is_sqlstate_warning(sql_state) ||
+ level == Sql_condition::WARN_LEVEL_WARN) && !found_cv)
+ {
+ found_cv= cv;
+ found_handler= h;
+ }
+ break;
+
+ case sp_condition_value::NOT_FOUND:
+ if (is_sqlstate_not_found(sql_state) && !found_cv)
+ {
+ found_cv= cv;
+ found_handler= h;
+ }
+ break;
+
+ case sp_condition_value::EXCEPTION:
+ if (is_sqlstate_exception(sql_state) &&
+ level == Sql_condition::WARN_LEVEL_ERROR && !found_cv)
+ {
+ found_cv= cv;
+ found_handler= h;
+ }
+ break;
}
}
}
- return FALSE;
+
+ if (found_handler)
+ return found_handler;
+
+
+ // There is no appropriate handler in this parsing context. We need to look up
+ // in parent contexts. There might be two cases here:
+ //
+ // 1. The current context has REGULAR_SCOPE. That means, it's a simple
+ // BEGIN..END block:
+ // ...
+ // BEGIN
+ // ... # We're here.
+ // END
+ // ...
+ // In this case we simply call find_handler() on parent's context recursively.
+ //
+ // 2. The current context has HANDLER_SCOPE. That means, we're inside an
+ // SQL-handler block:
+ // ...
+ // DECLARE ... HANDLER FOR ...
+ // BEGIN
+ // ... # We're here.
+ // END
+ // ...
+ // In this case we can not just call parent's find_handler(), because
+ // parent's handler don't catch conditions from this scope. Instead, we should
+ // try to find first parent context (we might have nested handler
+ // declarations), which has REGULAR_SCOPE (i.e. which is regular BEGIN..END
+ // block).
+
+ const sp_pcontext *p= this;
+
+ while (p && p->m_scope == HANDLER_SCOPE)
+ p= p->m_parent;
+
+ if (!p || !p->m_parent)
+ return NULL;
+
+ return p->m_parent->find_handler(sql_state, sql_errno, level);
}
-int
-sp_pcontext::push_cursor(LEX_STRING *name)
+
+bool sp_pcontext::add_cursor(LEX_STRING name)
{
- LEX_STRING n;
+ if (m_cursors.elements() == (int) m_max_cursor_index)
+ ++m_max_cursor_index;
- if (m_cursors.elements == m_max_cursor_index)
- m_max_cursor_index+= 1;
- n.str= name->str;
- n.length= name->length;
- return insert_dynamic(&m_cursors, (uchar *)&n);
+ return m_cursors.append(name);
}
-/*
- See comment for find_variable() above
-*/
-my_bool
-sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
+
+bool sp_pcontext::find_cursor(LEX_STRING name,
+ uint *poff,
+ bool current_scope_only) const
{
- uint i= m_cursors.elements;
+ uint i= m_cursors.elements();
while (i--)
{
- LEX_STRING n;
+ LEX_STRING n= m_cursors.at(i);
- get_dynamic(&m_cursors, (uchar*)&n, i);
if (my_strnncoll(system_charset_info,
- (const uchar *)name->str, name->length,
- (const uchar *)n.str, n.length) == 0)
+ (const uchar *) name.str, name.length,
+ (const uchar *) n.str, n.length) == 0)
{
*poff= m_cursor_offset + i;
- return TRUE;
+ return true;
}
}
- if (!scoped && m_parent)
- return m_parent->find_cursor(name, poff, scoped);
- return FALSE;
+
+ return (!current_scope_only && m_parent) ?
+ m_parent->find_cursor(name, poff, false) :
+ false;
}
-void
-sp_pcontext::retrieve_field_definitions(List<Create_field> *field_def_lst)
+void sp_pcontext::retrieve_field_definitions(
+ List<Create_field> *field_def_lst) const
{
/* Put local/context fields in the result list. */
- for (uint i = 0; i < m_vars.elements; ++i)
+ for (int i= 0; i < m_vars.elements(); ++i)
{
- sp_variable_t *var_def;
- get_dynamic(&m_vars, (uchar*) &var_def, i);
+ sp_variable *var_def= m_vars.at(i);
field_def_lst->push_back(&var_def->field_def);
}
/* Put the fields of the enclosed contexts in the result list. */
- List_iterator_fast<sp_pcontext> li(m_children);
- sp_pcontext *ctx;
-
- while ((ctx = li++))
- ctx->retrieve_field_definitions(field_def_lst);
+ for (int i= 0; i < m_children.elements(); ++i)
+ m_children.at(i)->retrieve_field_definitions(field_def_lst);
}
-/*
- Find a cursor by offset from the top.
- This is only used for debugging.
-*/
-my_bool
-sp_pcontext::find_cursor(uint offset, LEX_STRING *n)
+
+const LEX_STRING *sp_pcontext::find_cursor(uint offset) const
{
if (m_cursor_offset <= offset &&
- offset < m_cursor_offset + m_cursors.elements)
- { // This frame
- get_dynamic(&m_cursors, (uchar*)n, offset - m_cursor_offset);
- return TRUE;
+ offset < m_cursor_offset + m_cursors.elements())
+ {
+ return &m_cursors.at(offset - m_cursor_offset); // This frame
}
- if (m_parent)
- return m_parent->find_cursor(offset, n); // Some previous frame
- return FALSE; // index out of bounds
+
+ return m_parent ?
+ m_parent->find_cursor(offset) : // Some previous frame
+ NULL; // Index out of bounds
}
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index f1d0d250c47..fbf32244665 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -24,438 +24,541 @@
#include "sql_string.h" // LEX_STRING
#include "mysql_com.h" // enum_field_types
#include "field.h" // Create_field
+#include "sql_array.h" // Dynamic_array
-class sp_pcontext;
-typedef enum
-{
- sp_param_in,
- sp_param_out,
- sp_param_inout
-} sp_param_mode_t;
+/// This class represents a stored program variable or a parameter
+/// (also referenced as 'SP-variable').
-typedef struct sp_variable
+class sp_variable : public Sql_alloc
{
- LEX_STRING name;
- enum enum_field_types type;
- sp_param_mode_t mode;
-
- /*
- offset -- this the index to the variable's value in the runtime frame.
- This is calculated during parsing and used when creating sp_instr_set
- instructions and Item_splocal items.
- I.e. values are set/referred by array indexing in runtime.
- */
- uint offset;
-
- Item *dflt;
- Create_field field_def;
-} sp_variable_t;
+public:
+ enum enum_mode
+ {
+ MODE_IN,
+ MODE_OUT,
+ MODE_INOUT
+ };
+ /// Name of the SP-variable.
+ LEX_STRING name;
-#define SP_LAB_IMPL 0 // Implicit label generated by parser
-#define SP_LAB_BEGIN 1 // Label at BEGIN
-#define SP_LAB_ITER 2 // Label at iteration control
+ /// Field-type of the SP-variable.
+ enum enum_field_types type;
-/*
- An SQL/PSM label. Can refer to the identifier used with the
- "label_name:" construct which may precede some SQL/PSM statements, or
- to an implicit implementation-dependent identifier which the parser
- inserts before a high-level flow control statement such as
- IF/WHILE/REPEAT/LOOP, when such statement is rewritten into
- a combination of low-level jump/jump_if instructions and labels.
-*/
+ /// Mode of the SP-variable.
+ enum_mode mode;
-typedef struct sp_label
-{
- char *name;
- uint ip; // Instruction index
- int type; // begin/iter or ref/free
- sp_pcontext *ctx; // The label's context
-} sp_label_t;
+ /// The index to the variable's value in the runtime frame.
+ ///
+ /// It is calculated during parsing and used when creating sp_instr_set
+ /// instructions and Item_splocal items. I.e. values are set/referred by
+ /// array indexing in runtime.
+ uint offset;
-typedef struct sp_cond_type
-{
- enum { number, state, warning, notfound, exception } type;
- char sqlstate[SQLSTATE_LENGTH+1];
- uint mysqlerr;
-} sp_cond_type_t;
+ /// Default value of the SP-variable (if any).
+ Item *default_value;
-/*
- Sanity check for SQLSTATEs. Will not check if it's really an existing
- state (there are just too many), but will check length bad characters.
-*/
-extern bool
-sp_cond_check(LEX_STRING *sqlstate);
+ /// Full type information (field meta-data) of the SP-variable.
+ Create_field field_def;
-typedef struct sp_cond
-{
- LEX_STRING name;
- sp_cond_type_t *val;
-} sp_cond_t;
-
-/**
- The scope of a label in Stored Procedures,
- for name resolution of labels in a parsing context.
-*/
-enum label_scope_type
-{
- /**
- The labels declared in a parent context are in scope.
- */
- LABEL_DEFAULT_SCOPE,
- /**
- The labels declared in a parent context are not in scope.
- */
- LABEL_HANDLER_SCOPE
+public:
+ sp_variable(LEX_STRING _name, enum_field_types _type, enum_mode _mode,
+ uint _offset)
+ :Sql_alloc(),
+ name(_name),
+ type(_type),
+ mode(_mode),
+ offset(_offset),
+ default_value(NULL)
+ { }
};
-/**
- The parse-time context, used to keep track of declared variables/parameters,
- conditions, handlers, cursors and labels, during parsing.
- sp_contexts are organized as a tree, with one object for each begin-end
- block, one object for each exception handler,
- plus a root-context for the parameters.
- This is used during parsing for looking up defined names (e.g. declared
- variables and visible labels), for error checking, and to calculate offsets
- to be used at runtime. (During execution variable values, active handlers
- and cursors, etc, are referred to by an index in a stack.)
- Parsing contexts for exception handlers limit the visibility of labels.
- The pcontext tree is also kept during execution and is used for error
- checking (e.g. correct number of parameters), and in the future, used by
- the debugger.
-*/
+///////////////////////////////////////////////////////////////////////////
-class sp_pcontext : public Sql_alloc
+/// This class represents an SQL/PSM label. Can refer to the identifier
+/// used with the "label_name:" construct which may precede some SQL/PSM
+/// statements, or to an implicit implementation-dependent identifier which
+/// the parser inserts before a high-level flow control statement such as
+/// IF/WHILE/REPEAT/LOOP, when such statement is rewritten into a
+/// combination of low-level jump/jump_if instructions and labels.
+
+class sp_label : public Sql_alloc
{
public:
-
- /**
- Constructor.
- Builds a parsing context root node.
- */
- sp_pcontext();
-
- // Free memory
- void
- destroy();
-
- /**
- Create and push a new context in the tree.
- @param label_scope label scope for the new parsing context
- @return the node created
- */
- sp_pcontext *
- push_context(label_scope_type label_scope);
-
- /**
- Pop a node from the parsing context tree.
- @return the parent node
- */
- sp_pcontext *
- pop_context();
-
- sp_pcontext *
- parent_context()
+ enum enum_type
{
- return m_parent;
- }
+ /// Implicit label generated by parser.
+ IMPLICIT,
- /*
- Number of handlers/cursors to pop between this context and 'ctx'.
- If 'exclusive' is true, don't count the last block we are leaving;
- this is used for LEAVE where we will jump to the cpop/hpop instructions.
- */
- uint
- diff_handlers(sp_pcontext *ctx, bool exclusive);
- uint
- diff_cursors(sp_pcontext *ctx, bool exclusive);
-
-
- //
- // Parameters and variables
- //
-
- /*
- The maximum number of variables used in this and all child contexts
- In the root, this gives us the number of slots needed for variables
- during execution.
- */
- inline uint
- max_var_index()
- {
- return m_max_var_index;
- }
+ /// Label at BEGIN.
+ BEGIN,
- /*
- The current number of variables used in the parents (from the root),
- including this context.
- */
- inline uint
- current_var_count()
- {
- return m_var_offset + m_vars.elements;
- }
+ /// Label at iteration control
+ ITERATION
+ };
- /* The number of variables in this context alone */
- inline uint
- context_var_count()
- {
- return m_vars.elements;
- }
+ /// Name of the label.
+ LEX_STRING name;
- /* Map index in this pcontext to runtime offset */
- inline uint
- var_context2runtime(uint i)
- {
- return m_var_offset + i;
- }
+ /// Instruction pointer of the label.
+ uint ip;
- /* Set type of variable. 'i' is the offset from the top */
- inline void
- set_type(uint i, enum enum_field_types type)
- {
- sp_variable_t *p= find_variable(i);
+ /// Type of the label.
+ enum_type type;
- if (p)
- p->type= type;
- }
+ /// Scope of the label.
+ class sp_pcontext *ctx;
- /* Set default value of variable. 'i' is the offset from the top */
- inline void
- set_default(uint i, Item *it)
- {
- sp_variable_t *p= find_variable(i);
+public:
+ sp_label(LEX_STRING _name, uint _ip, enum_type _type, sp_pcontext *_ctx)
+ :Sql_alloc(),
+ name(_name),
+ ip(_ip),
+ type(_type),
+ ctx(_ctx)
+ { }
+};
- if (p)
- p->dflt= it;
- }
+///////////////////////////////////////////////////////////////////////////
+
+/// This class represents condition-value term in DECLARE CONDITION or
+/// DECLARE HANDLER statements. sp_condition_value has little to do with
+/// SQL-conditions.
+///
+/// In some sense, this class is a union -- a set of filled attributes
+/// depends on the sp_condition_value::type value.
- sp_variable_t *
- push_variable(LEX_STRING *name, enum enum_field_types type,
- sp_param_mode_t mode);
-
- /*
- Retrieve definitions of fields from the current context and its
- children.
- */
- void
- retrieve_field_definitions(List<Create_field> *field_def_lst);
-
- // Find by name
- sp_variable_t *
- find_variable(LEX_STRING *name, my_bool scoped=0);
-
- // Find by offset (from the top)
- sp_variable_t *
- find_variable(uint offset);
-
- /*
- Set the current scope boundary (for default values).
- The argument is the number of variables to skip.
- */
- inline void
- declare_var_boundary(uint n)
+class sp_condition_value : public Sql_alloc
+{
+public:
+ enum enum_type
{
- m_pboundary= n;
- }
+ ERROR_CODE,
+ SQLSTATE,
+ WARNING,
+ NOT_FOUND,
+ EXCEPTION
+ };
- /*
- CASE expressions support.
- */
+ /// Type of the condition value.
+ enum_type type;
- inline int
- register_case_expr()
- {
- return m_num_case_exprs++;
- }
+ /// SQLSTATE of the condition value.
+ char sql_state[SQLSTATE_LENGTH+1];
- inline int
- get_num_case_exprs() const
- {
- return m_num_case_exprs;
- }
+ /// MySQL error code of the condition value.
+ uint mysqlerr;
- inline bool
- push_case_expr_id(int case_expr_id)
+public:
+ sp_condition_value(uint _mysqlerr)
+ :Sql_alloc(),
+ type(ERROR_CODE),
+ mysqlerr(_mysqlerr)
+ { }
+
+ sp_condition_value(const char *_sql_state)
+ :Sql_alloc(),
+ type(SQLSTATE)
{
- return insert_dynamic(&m_case_expr_id_lst, (uchar*) &case_expr_id);
+ memcpy(sql_state, _sql_state, SQLSTATE_LENGTH);
+ sql_state[SQLSTATE_LENGTH]= 0;
}
- inline void
- pop_case_expr_id()
+ sp_condition_value(enum_type _type)
+ :Sql_alloc(),
+ type(_type)
{
- pop_dynamic(&m_case_expr_id_lst);
+ DBUG_ASSERT(type != ERROR_CODE && type != SQLSTATE);
}
- inline int
- get_current_case_expr_id() const
- {
- int case_expr_id;
+ /// Check if two instances of sp_condition_value are equal or not.
+ ///
+ /// @param cv another instance of sp_condition_value to check.
+ ///
+ /// @return true if the instances are equal, false otherwise.
+ bool equals(const sp_condition_value *cv) const;
+};
- get_dynamic((DYNAMIC_ARRAY*)&m_case_expr_id_lst, (uchar*) &case_expr_id,
- m_case_expr_id_lst.elements - 1);
+///////////////////////////////////////////////////////////////////////////
- return case_expr_id;
- }
+/// This class represents 'DECLARE CONDITION' statement.
+/// sp_condition has little to do with SQL-conditions.
- //
- // Labels
- //
+class sp_condition : public Sql_alloc
+{
+public:
+ /// Name of the condition.
+ LEX_STRING name;
- sp_label_t *
- push_label(char *name, uint ip);
+ /// Value of the condition.
+ sp_condition_value *value;
- sp_label_t *
- find_label(char *name);
+public:
+ sp_condition(LEX_STRING _name, sp_condition_value *_value)
+ :Sql_alloc(),
+ name(_name),
+ value(_value)
+ { }
+};
- inline sp_label_t *
- last_label()
- {
- sp_label_t *lab= m_label.head();
+///////////////////////////////////////////////////////////////////////////
- if (!lab && m_parent)
- lab= m_parent->last_label();
- return lab;
- }
+/// This class represents 'DECLARE HANDLER' statement.
- inline sp_label_t *
- pop_label()
+class sp_handler : public Sql_alloc
+{
+public:
+ /// Enumeration of possible handler types.
+ /// Note: UNDO handlers are not (and have never been) supported.
+ enum enum_type
{
- return m_label.pop();
- }
+ EXIT,
+ CONTINUE
+ };
- //
- // Conditions
- //
+ /// Handler type.
+ enum_type type;
- int
- push_cond(LEX_STRING *name, sp_cond_type_t *val);
+ /// Conditions caught by this handler.
+ List<sp_condition_value> condition_values;
- sp_cond_type_t *
- find_cond(LEX_STRING *name, my_bool scoped=0);
+public:
+ /// The constructor.
+ ///
+ /// @param _type SQL-handler type.
+ sp_handler(enum_type _type)
+ :Sql_alloc(),
+ type(_type)
+ { }
+};
- //
- // Handlers
- //
+///////////////////////////////////////////////////////////////////////////
+
+/// The class represents parse-time context, which keeps track of declared
+/// variables/parameters, conditions, handlers, cursors and labels.
+///
+/// sp_context objects are organized in a tree according to the following
+/// rules:
+/// - one sp_pcontext object corresponds for for each BEGIN..END block;
+/// - one sp_pcontext object corresponds for each exception handler;
+/// - one additional sp_pcontext object is created to contain
+/// Stored Program parameters.
+///
+/// sp_pcontext objects are used both at parse-time and at runtime.
+///
+/// During the parsing stage sp_pcontext objects are used:
+/// - to look up defined names (e.g. declared variables and visible
+/// labels);
+/// - to check for duplicates;
+/// - for error checking;
+/// - to calculate offsets to be used at runtime.
+///
+/// During the runtime phase, a tree of sp_pcontext objects is used:
+/// - for error checking (e.g. to check correct number of parameters);
+/// - to resolve SQL-handlers.
- inline void
- push_handler(sp_cond_type_t *cond)
+class sp_pcontext : public Sql_alloc
+{
+public:
+ enum enum_scope
{
- insert_dynamic(&m_handlers, (uchar*)&cond);
- }
-
- bool
- find_handler(sp_cond_type *cond);
+ /// REGULAR_SCOPE designates regular BEGIN ... END blocks.
+ REGULAR_SCOPE,
- inline uint
- max_handler_index()
- {
- return m_max_handler_index + m_context_handlers;
- }
+ /// HANDLER_SCOPE designates SQL-handler blocks.
+ HANDLER_SCOPE
+ };
- inline void
- add_handlers(uint n)
+public:
+ sp_pcontext();
+ ~sp_pcontext();
+
+
+ /// Create and push a new context in the tree.
+
+ /// @param thd thread context.
+ /// @param scope scope of the new parsing context.
+ /// @return the node created.
+ sp_pcontext *push_context(THD *thd, enum_scope scope);
+
+ /// Pop a node from the parsing context tree.
+ /// @return the parent node.
+ sp_pcontext *pop_context();
+
+ sp_pcontext *parent_context() const
+ { return m_parent; }
+
+ /// Calculate and return the number of handlers to pop between the given
+ /// context and this one.
+ ///
+ /// @param ctx the other parsing context.
+ /// @param exclusive specifies if the last scope should be excluded.
+ ///
+ /// @return the number of handlers to pop between the given context and
+ /// this one. If 'exclusive' is true, don't count the last scope we are
+ /// leaving; this is used for LEAVE where we will jump to the hpop
+ /// instructions.
+ uint diff_handlers(const sp_pcontext *ctx, bool exclusive) const;
+
+ /// Calculate and return the number of cursors to pop between the given
+ /// context and this one.
+ ///
+ /// @param ctx the other parsing context.
+ /// @param exclusive specifies if the last scope should be excluded.
+ ///
+ /// @return the number of cursors to pop between the given context and
+ /// this one. If 'exclusive' is true, don't count the last scope we are
+ /// leaving; this is used for LEAVE where we will jump to the cpop
+ /// instructions.
+ uint diff_cursors(const sp_pcontext *ctx, bool exclusive) const;
+
+ /////////////////////////////////////////////////////////////////////////
+ // SP-variables (parameters and variables).
+ /////////////////////////////////////////////////////////////////////////
+
+ /// @return the maximum number of variables used in this and all child
+ /// contexts. For the root parsing context, this gives us the number of
+ /// slots needed for variables during the runtime phase.
+ uint max_var_index() const
+ { return m_max_var_index; }
+
+ /// @return the current number of variables used in the parent contexts
+ /// (from the root), including this context.
+ uint current_var_count() const
+ { return m_var_offset + m_vars.elements(); }
+
+ /// @return the number of variables in this context alone.
+ uint context_var_count() const
+ { return m_vars.elements(); }
+
+ /// @return map index in this parsing context to runtime offset.
+ uint var_context2runtime(uint i) const
+ { return m_var_offset + i; }
+
+ /// Add SP-variable to the parsing context.
+ ///
+ /// @param thd Thread context.
+ /// @param name Name of the SP-variable.
+ /// @param type Type of the SP-variable.
+ /// @param mode Mode of the SP-variable.
+ ///
+ /// @return instance of newly added SP-variable.
+ sp_variable *add_variable(THD *thd,
+ LEX_STRING name,
+ enum enum_field_types type,
+ sp_variable::enum_mode mode);
+
+ /// Retrieve full type information about SP-variables in this parsing
+ /// context and its children.
+ ///
+ /// @param field_def_lst[out] Container to store type information.
+ void retrieve_field_definitions(List<Create_field> *field_def_lst) const;
+
+ /// Find SP-variable by name.
+ ///
+ /// The function does a linear search (from newer to older variables,
+ /// in case we have shadowed names).
+ ///
+ /// The function is called only at parsing time.
+ ///
+ /// @param name Variable name.
+ /// @param current_scope_only A flag if we search only in current scope.
+ ///
+ /// @return instance of found SP-variable, or NULL if not found.
+ sp_variable *find_variable(LEX_STRING name, bool current_scope_only) const;
+
+ /// Find SP-variable by the offset in the root parsing context.
+ ///
+ /// The function is used for two things:
+ /// - When evaluating parameters at the beginning, and setting out parameters
+ /// at the end, of invocation. (Top frame only, so no recursion then.)
+ /// - For printing of sp_instr_set. (Debug mode only.)
+ ///
+ /// @param offset Variable offset in the root parsing context.
+ ///
+ /// @return instance of found SP-variable, or NULL if not found.
+ sp_variable *find_variable(uint offset) const;
+
+ /// Set the current scope boundary (for default values).
+ ///
+ /// @param n The number of variables to skip.
+ void declare_var_boundary(uint n)
+ { m_pboundary= n; }
+
+ /////////////////////////////////////////////////////////////////////////
+ // CASE expressions.
+ /////////////////////////////////////////////////////////////////////////
+
+ int register_case_expr()
+ { return m_num_case_exprs++; }
+
+ int get_num_case_exprs() const
+ { return m_num_case_exprs; }
+
+ bool push_case_expr_id(int case_expr_id)
+ { return m_case_expr_ids.append(case_expr_id); }
+
+ void pop_case_expr_id()
+ { m_case_expr_ids.pop(); }
+
+ int get_current_case_expr_id() const
+ { return *m_case_expr_ids.back(); }
+
+ /////////////////////////////////////////////////////////////////////////
+ // Labels.
+ /////////////////////////////////////////////////////////////////////////
+
+ sp_label *push_label(THD *thd, LEX_STRING name, uint ip);
+
+ sp_label *find_label(LEX_STRING name);
+
+ sp_label *last_label()
{
- m_context_handlers+= n;
- }
-
- //
- // Cursors
- //
+ sp_label *label= m_labels.head();
- int
- push_cursor(LEX_STRING *name);
+ if (!label && m_parent)
+ label= m_parent->last_label();
- my_bool
- find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0);
-
- /* Find by offset (for debugging only) */
- my_bool
- find_cursor(uint offset, LEX_STRING *n);
-
- inline uint
- max_cursor_index()
- {
- return m_max_cursor_index + m_cursors.elements;
- }
-
- inline uint
- current_cursor_count()
- {
- return m_cursor_offset + m_cursors.elements;
+ return label;
}
-protected:
+ sp_label *pop_label()
+ { return m_labels.pop(); }
+
+ /////////////////////////////////////////////////////////////////////////
+ // Conditions.
+ /////////////////////////////////////////////////////////////////////////
+
+ bool add_condition(THD *thd, LEX_STRING name, sp_condition_value *value);
+
+ /// See comment for find_variable() above.
+ sp_condition_value *find_condition(LEX_STRING name,
+ bool current_scope_only) const;
+
+ /////////////////////////////////////////////////////////////////////////
+ // Handlers.
+ /////////////////////////////////////////////////////////////////////////
+
+ sp_handler *add_handler(THD* thd, sp_handler::enum_type type);
+
+ /// This is an auxilary parsing-time function to check if an SQL-handler
+ /// exists in the current parsing context (current scope) for the given
+ /// SQL-condition. This function is used to check for duplicates during
+ /// the parsing phase.
+ ///
+ /// This function can not be used during the runtime phase to check
+ /// SQL-handler existence because it searches for the SQL-handler in the
+ /// current scope only (during runtime, current and parent scopes
+ /// should be checked according to the SQL-handler resolution rules).
+ ///
+ /// @param condition_value the handler condition value
+ /// (not SQL-condition!).
+ ///
+ /// @retval true if such SQL-handler exists.
+ /// @retval false otherwise.
+ bool check_duplicate_handler(const sp_condition_value *cond_value) const;
+
+ /// Find an SQL handler for the given SQL condition according to the
+ /// SQL-handler resolution rules. This function is used at runtime.
+ ///
+ /// @param sql_state The SQL condition state
+ /// @param sql_errno The error code
+ /// @param level The SQL condition level
+ ///
+ /// @return a pointer to the found SQL-handler or NULL.
+ sp_handler *find_handler(const char *sql_state,
+ uint sql_errno,
+ Sql_condition::enum_warning_level level) const;
+
+ /////////////////////////////////////////////////////////////////////////
+ // Cursors.
+ /////////////////////////////////////////////////////////////////////////
+
+ bool add_cursor(LEX_STRING name);
+
+ /// See comment for find_variable() above.
+ bool find_cursor(LEX_STRING name, uint *poff, bool current_scope_only) const;
+
+ /// Find cursor by offset (for debugging only).
+ const LEX_STRING *find_cursor(uint offset) const;
+
+ uint max_cursor_index() const
+ { return m_max_cursor_index + m_cursors.elements(); }
+
+ uint current_cursor_count() const
+ { return m_cursor_offset + m_cursors.elements(); }
- /**
- Constructor for a tree node.
- @param prev the parent parsing context
- @param label_scope label_scope for this parsing context
- */
- sp_pcontext(sp_pcontext *prev, label_scope_type label_scope);
-
- /*
- m_max_var_index -- number of variables (including all types of arguments)
- in this context including all children contexts.
-
- m_max_var_index >= m_vars.elements.
+private:
+ /// Constructor for a tree node.
+ /// @param prev the parent parsing context
+ /// @param scope scope of this parsing context
+ sp_pcontext(sp_pcontext *prev, enum_scope scope);
- m_max_var_index of the root parsing context contains number of all
- variables (including arguments) in all enclosed contexts.
- */
- uint m_max_var_index;
+ void init(uint var_offset, uint cursor_offset, int num_case_expressions);
- // The maximum sub context's framesizes
- uint m_max_cursor_index;
- uint m_max_handler_index;
- uint m_context_handlers; // No. of handlers in this context
+ /* Prevent use of these */
+ sp_pcontext(const sp_pcontext &);
+ void operator=(sp_pcontext &);
private:
+ /// m_max_var_index -- number of variables (including all types of arguments)
+ /// in this context including all children contexts.
+ ///
+ /// m_max_var_index >= m_vars.elements().
+ ///
+ /// m_max_var_index of the root parsing context contains number of all
+ /// variables (including arguments) in all enclosed contexts.
+ uint m_max_var_index;
+
+ /// The maximum sub context's framesizes.
+ uint m_max_cursor_index;
- sp_pcontext *m_parent; // Parent context
-
- /*
- m_var_offset -- this is an index of the first variable in this
- parsing context.
-
- m_var_offset is 0 for root context.
+ /// Parent context.
+ sp_pcontext *m_parent;
- Since now each variable is stored in separate place, no reuse is done,
- so m_var_offset is different for all enclosed contexts.
- */
+ /// An index of the first SP-variable in this parsing context. The index
+ /// belongs to a runtime table of SP-variables.
+ ///
+ /// Note:
+ /// - m_var_offset is 0 for root parsing context;
+ /// - m_var_offset is different for all nested parsing contexts.
uint m_var_offset;
- uint m_cursor_offset; // Cursor offset for this context
+ /// Cursor offset for this context.
+ uint m_cursor_offset;
- /*
- Boundary for finding variables in this context. This is the number
- of variables currently "invisible" to default clauses.
- This is normally 0, but will be larger during parsing of
- DECLARE ... DEFAULT, to get the scope right for DEFAULT values.
- */
+ /// Boundary for finding variables in this context. This is the number of
+ /// variables currently "invisible" to default clauses. This is normally 0,
+ /// but will be larger during parsing of DECLARE ... DEFAULT, to get the
+ /// scope right for DEFAULT values.
uint m_pboundary;
int m_num_case_exprs;
- DYNAMIC_ARRAY m_vars; // Parameters/variables
- DYNAMIC_ARRAY m_case_expr_id_lst; /* Stack of CASE expression ids. */
- DYNAMIC_ARRAY m_conds; // Conditions
- DYNAMIC_ARRAY m_cursors; // Cursors
- DYNAMIC_ARRAY m_handlers; // Handlers, for checking for duplicates
+ /// SP parameters/variables.
+ Dynamic_array<sp_variable *> m_vars;
- List<sp_label_t> m_label; // The label list
+ /// Stack of CASE expression ids.
+ Dynamic_array<int> m_case_expr_ids;
- List<sp_pcontext> m_children; // Children contexts, used for destruction
+ /// Stack of SQL-conditions.
+ Dynamic_array<sp_condition *> m_conditions;
- /**
- Scope of labels for this parsing context.
- */
- label_scope_type m_label_scope;
+ /// Stack of cursors.
+ Dynamic_array<LEX_STRING> m_cursors;
-private:
- sp_pcontext(const sp_pcontext &); /* Prevent use of these */
- void operator=(sp_pcontext &);
+ /// Stack of SQL-handlers.
+ Dynamic_array<sp_handler *> m_handlers;
+
+ /// List of labels.
+ List<sp_label> m_labels;
+
+ /// Children contexts, used for destruction.
+ Dynamic_array<sp_pcontext *> m_children;
+
+ /// Scope of this parsing context.
+ enum_scope m_scope;
}; // class sp_pcontext : public Sql_alloc
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index fc6a67fb496..3e79cb3fa36 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -26,23 +26,21 @@
#include "sp_pcontext.h"
#include "sql_select.h" // create_virtual_tmp_table
-sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
+///////////////////////////////////////////////////////////////////////////
+// sp_rcontext implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+sp_rcontext::sp_rcontext(const sp_pcontext *root_parsing_ctx,
Field *return_value_fld,
- sp_rcontext *prev_runtime_ctx)
- :end_partial_result_set(FALSE),
+ bool in_sub_stmt)
+ :end_partial_result_set(false),
m_root_parsing_ctx(root_parsing_ctx),
- m_var_table(0),
- m_var_items(0),
+ m_var_table(NULL),
m_return_value_fld(return_value_fld),
- m_return_value_set(FALSE),
- in_sub_stmt(FALSE),
- m_hcount(0),
- m_hsp(0),
- m_ihsp(0),
- m_hfound(-1),
- m_ccount(0),
- m_case_expr_holders(0),
- m_prev_runtime_ctx(prev_runtime_ctx)
+ m_return_value_set(false),
+ m_in_sub_stmt(in_sub_stmt),
+ m_ccount(0)
{
}
@@ -51,422 +49,307 @@ sp_rcontext::~sp_rcontext()
{
if (m_var_table)
free_blobs(m_var_table);
+
+ // Leave m_handlers, m_handler_call_stack, m_var_items, m_cstack
+ // and m_case_expr_holders untouched.
+ // They are allocated in mem roots and will be freed accordingly.
}
-/*
- Initialize sp_rcontext instance.
+sp_rcontext *sp_rcontext::create(THD *thd,
+ const sp_pcontext *root_parsing_ctx,
+ Field *return_value_fld)
+{
+ sp_rcontext *ctx= new (thd->mem_root) sp_rcontext(root_parsing_ctx,
+ return_value_fld,
+ thd->in_sub_stmt);
- SYNOPSIS
- thd Thread handle
- RETURN
- FALSE on success
- TRUE on error
-*/
+ if (!ctx)
+ return NULL;
-bool sp_rcontext::init(THD *thd)
-{
- uint handler_count= m_root_parsing_ctx->max_handler_index();
-
- in_sub_stmt= thd->in_sub_stmt;
-
- if (init_var_table(thd) || init_var_items())
- return TRUE;
-
- if (!(m_raised_conditions= new (thd->mem_root) Sql_condition_info[handler_count]))
- return TRUE;
-
- return
- !(m_handler=
- (sp_handler_t*)thd->alloc(handler_count * sizeof(sp_handler_t))) ||
- !(m_hstack=
- (uint*)thd->alloc(handler_count * sizeof(uint))) ||
- !(m_in_handler=
- (sp_active_handler_t*)thd->alloc(handler_count *
- sizeof(sp_active_handler_t))) ||
- !(m_cstack=
- (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() *
- sizeof(sp_cursor*))) ||
- !(m_case_expr_holders=
- (Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() *
- sizeof (Item_cache*)));
+ if (ctx->alloc_arrays(thd) ||
+ ctx->init_var_table(thd) ||
+ ctx->init_var_items(thd))
+ {
+ delete ctx;
+ return NULL;
+ }
+
+ return ctx;
}
-/*
- Create and initialize a table to store SP-vars.
+bool sp_rcontext::alloc_arrays(THD *thd)
+{
+ {
+ size_t n= m_root_parsing_ctx->max_cursor_index();
+ m_cstack.reset(
+ static_cast<sp_cursor **> (
+ thd->alloc(n * sizeof (sp_cursor*))),
+ n);
+ }
+
+ {
+ size_t n= m_root_parsing_ctx->get_num_case_exprs();
+ m_case_expr_holders.reset(
+ static_cast<Item_cache **> (
+ thd->calloc(n * sizeof (Item_cache*))),
+ n);
+ }
+
+ return !m_cstack.array() || !m_case_expr_holders.array();
+}
- SYNOPSIS
- thd Thread handler.
- RETURN
- FALSE on success
- TRUE on error
-*/
-bool
-sp_rcontext::init_var_table(THD *thd)
+bool sp_rcontext::init_var_table(THD *thd)
{
List<Create_field> field_def_lst;
if (!m_root_parsing_ctx->max_var_index())
- return FALSE;
+ return false;
m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->max_var_index());
-
+
if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst)))
- return TRUE;
+ return true;
- m_var_table->copy_blobs= TRUE;
- m_var_table->alias.set("", 0, table_alias_charset);
+ m_var_table->copy_blobs= true;
+ m_var_table->alias.set("", 0, m_var_table->alias.charset());
- return FALSE;
+ return false;
}
-/*
- Create and initialize an Item-adapter (Item_field) for each SP-var field.
-
- RETURN
- FALSE on success
- TRUE on error
-*/
-
-bool
-sp_rcontext::init_var_items()
+bool sp_rcontext::init_var_items(THD *thd)
{
- uint idx;
uint num_vars= m_root_parsing_ctx->max_var_index();
- if (!(m_var_items= (Item**) sql_alloc(num_vars * sizeof (Item *))))
- return TRUE;
+ m_var_items.reset(
+ static_cast<Item **> (
+ thd->alloc(num_vars * sizeof (Item *))),
+ num_vars);
+
+ if (!m_var_items.array())
+ return true;
- for (idx = 0; idx < num_vars; ++idx)
+ for (uint idx = 0; idx < num_vars; ++idx)
{
if (!(m_var_items[idx]= new Item_field(m_var_table->field[idx])))
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-bool
-sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
+bool sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
{
DBUG_ASSERT(m_return_value_fld);
- m_return_value_set = TRUE;
+ m_return_value_set = true;
return sp_eval_expr(thd, m_return_value_fld, return_value_item);
}
-#define IS_WARNING_CONDITION(S) ((S)[0] == '0' && (S)[1] == '1')
-#define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2')
-#define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2')
-
-/**
- Find an SQL handler for the given error.
-
- SQL handlers are pushed on the stack m_handler, with the latest/innermost
- one on the top; we then search for matching handlers from the top and
- down.
-
- We search through all the handlers, looking for the most specific one
- (sql_errno more specific than sqlstate more specific than the rest).
- Note that mysql error code handlers is a MySQL extension, not part of
- the standard.
-
- SQL handlers for warnings are searched in the current scope only.
-
- SQL handlers for errors are searched in the current and in outer scopes.
- That's why finding and activation of handler must be separated: an errror
- handler might be located in the outer scope, which is not active at the
- moment. Before such handler can be activated, execution flow should
- unwind to that scope.
-
- Found SQL handler is remembered in m_hfound for future activation.
- If no handler is found, m_hfound is -1.
-
- @param thd Thread handle
- @param sql_errno The error code
- @param sqlstate The error SQL state
- @param level The error level
- @param msg The error message
-
- @retval TRUE if an SQL handler was found
- @retval FALSE otherwise
-*/
-
-bool
-sp_rcontext::find_handler(THD *thd,
- uint sql_errno,
- const char *sqlstate,
- Sql_condition::enum_warning_level level,
- const char *msg)
+bool sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper,
+ sp_instr_cpush *i)
{
- int i= m_hcount;
-
- /* Reset previously found handler. */
- m_hfound= -1;
-
/*
- If this is a fatal sub-statement error, and this runtime
- context corresponds to a sub-statement, no CONTINUE/EXIT
- handlers from this context are applicable: try to locate one
- in the outer scope.
+ We should create cursors in the callers arena, as
+ it could be (and usually is) used in several instructions.
*/
- if (thd->is_fatal_sub_stmt_error && in_sub_stmt)
- i= 0;
-
- /* Search handlers from the latest (innermost) to the oldest (outermost) */
- while (i--)
- {
- sp_cond_type_t *cond= m_handler[i].cond;
- int j= m_ihsp;
+ sp_cursor *c= new (callers_arena->mem_root) sp_cursor(lex_keeper, i);
- /* Check active handlers, to avoid invoking one recursively */
- while (j--)
- if (m_in_handler[j].ip == m_handler[i].handler)
- break;
- if (j >= 0)
- continue; // Already executing this handler
+ if (c == NULL)
+ return true;
- switch (cond->type)
- {
- case sp_cond_type_t::number:
- if (sql_errno == cond->mysqlerr &&
- (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_cond_type_t::number))
- m_hfound= i; // Always the most specific
- break;
- case sp_cond_type_t::state:
- if (strcmp(sqlstate, cond->sqlstate) == 0 &&
- (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_cond_type_t::state))
- m_hfound= i;
- break;
- case sp_cond_type_t::warning:
- if ((IS_WARNING_CONDITION(sqlstate) ||
- level == Sql_condition::WARN_LEVEL_WARN) &&
- m_hfound < 0)
- m_hfound= i;
- break;
- case sp_cond_type_t::notfound:
- if (IS_NOT_FOUND_CONDITION(sqlstate) && m_hfound < 0)
- m_hfound= i;
- break;
- case sp_cond_type_t::exception:
- if (IS_EXCEPTION_CONDITION(sqlstate) &&
- level == Sql_condition::WARN_LEVEL_ERROR &&
- m_hfound < 0)
- m_hfound= i;
- break;
- }
- }
-
- if (m_hfound >= 0)
- {
- DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index());
-
- m_raised_conditions[m_hfound].clear();
- m_raised_conditions[m_hfound].set(sql_errno, sqlstate, level, msg);
-
- return TRUE;
- }
-
- /*
- Only "exception conditions" are propagated to handlers in calling
- contexts. If no handler is found locally for a "completion condition"
- (warning or "not found") we will simply resume execution.
- */
- if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
- level == Sql_condition::WARN_LEVEL_ERROR)
- {
- return m_prev_runtime_ctx->find_handler(thd, sql_errno, sqlstate,
- level, msg);
- }
-
- return FALSE;
+ m_cstack[m_ccount++]= c;
+ return false;
}
-void
-sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
-{
- DBUG_ENTER("sp_rcontext::push_cursor");
- DBUG_ASSERT(m_ccount < m_root_parsing_ctx->max_cursor_index());
- m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i);
- DBUG_PRINT("info", ("m_ccount: %d", m_ccount));
- DBUG_VOID_RETURN;
-}
-void
-sp_rcontext::pop_cursors(uint count)
+void sp_rcontext::pop_cursors(uint count)
{
- DBUG_ENTER("sp_rcontext::pop_cursors");
DBUG_ASSERT(m_ccount >= count);
+
while (count--)
- {
delete m_cstack[--m_ccount];
- }
- DBUG_PRINT("info", ("m_ccount: %d", m_ccount));
- DBUG_VOID_RETURN;
}
-void
-sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type)
-{
- DBUG_ENTER("sp_rcontext::push_handler");
- DBUG_ASSERT(m_hcount < m_root_parsing_ctx->max_handler_index());
- m_handler[m_hcount].cond= cond;
- m_handler[m_hcount].handler= h;
- m_handler[m_hcount].type= type;
- m_hcount+= 1;
-
- DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
- DBUG_VOID_RETURN;
-}
-
-void
-sp_rcontext::pop_handlers(uint count)
+bool sp_rcontext::push_handler(sp_handler *handler, uint first_ip)
{
- DBUG_ENTER("sp_rcontext::pop_handlers");
- DBUG_ASSERT(m_hcount >= count);
+ /*
+ We should create handler entries in the callers arena, as
+ they could be (and usually are) used in several instructions.
+ */
+ sp_handler_entry *he=
+ new (callers_arena->mem_root) sp_handler_entry(handler, first_ip);
- m_hcount-= count;
+ if (he == NULL)
+ return true;
- DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
- DBUG_VOID_RETURN;
+ return m_handlers.append(he);
}
-void
-sp_rcontext::push_hstack(uint h)
-{
- DBUG_ENTER("sp_rcontext::push_hstack");
- DBUG_ASSERT(m_hsp < m_root_parsing_ctx->max_handler_index());
- m_hstack[m_hsp++]= h;
+void sp_rcontext::pop_handlers(int count)
+{
+ DBUG_ASSERT(m_handlers.elements() >= count);
- DBUG_PRINT("info", ("m_hsp: %d", m_hsp));
- DBUG_VOID_RETURN;
+ for (int i= 0; i < count; ++i)
+ m_handlers.pop();
}
-uint
-sp_rcontext::pop_hstack()
+
+bool sp_rcontext::handle_sql_condition(THD *thd,
+ uint *ip,
+ const sp_instr *cur_spi)
{
- uint handler;
- DBUG_ENTER("sp_rcontext::pop_hstack");
- DBUG_ASSERT(m_hsp);
+ DBUG_ENTER("sp_rcontext::handle_sql_condition");
- handler= m_hstack[--m_hsp];
+ /*
+ If this is a fatal sub-statement error, and this runtime
+ context corresponds to a sub-statement, no CONTINUE/EXIT
+ handlers from this context are applicable: try to locate one
+ in the outer scope.
+ */
+ if (thd->is_fatal_sub_stmt_error && m_in_sub_stmt)
+ DBUG_RETURN(false);
- DBUG_PRINT("info", ("m_hsp: %d", m_hsp));
- DBUG_RETURN(handler);
-}
+ Diagnostics_area *da= thd->get_stmt_da();
+ const sp_handler *found_handler= NULL;
+ const Sql_condition *found_condition= NULL;
-/**
- Prepare found handler to be executed.
+ if (thd->is_error())
+ {
+ found_handler=
+ cur_spi->m_ctx->find_handler(da->get_sqlstate(),
+ da->sql_errno(),
+ Sql_condition::WARN_LEVEL_ERROR);
- @retval TRUE if an SQL handler is activated (was found) and IP of the
- first handler instruction.
- @retval FALSE if there is no active handler
-*/
+ if (found_handler)
+ found_condition= da->get_error_condition();
+ }
+ else if (da->current_statement_warn_count())
+ {
+ Diagnostics_area::Sql_condition_iterator it= da->sql_conditions();
+ const Sql_condition *c;
-bool
-sp_rcontext::activate_handler(THD *thd,
- uint *ip,
- sp_instr *instr,
- Query_arena *execute_arena,
- Query_arena *backup_arena)
-{
- if (m_hfound < 0)
- return FALSE;
+ // Here we need to find the last warning/note from the stack.
+ // In MySQL most substantial warning is the last one.
+ // (We could have used a reverse iterator here if one existed)
- switch (m_handler[m_hfound].type) {
- case SP_HANDLER_NONE:
- break;
+ while ((c= it++))
+ {
+ if (c->get_level() == Sql_condition::WARN_LEVEL_WARN ||
+ c->get_level() == Sql_condition::WARN_LEVEL_NOTE)
+ {
+ const sp_handler *handler=
+ cur_spi->m_ctx->find_handler(c->get_sqlstate(),
+ c->get_sql_errno(),
+ c->get_level());
+ if (handler)
+ {
+ found_handler= handler;
+ found_condition= c;
+ }
+ }
+ }
+ }
- case SP_HANDLER_CONTINUE:
- thd->restore_active_arena(execute_arena, backup_arena);
- thd->set_n_backup_active_arena(execute_arena, backup_arena);
- push_hstack(instr->get_cont_dest());
+ if (!found_handler)
+ DBUG_RETURN(false);
- /* Fall through */
+ // At this point, we know that:
+ // - there is a pending SQL-condition (error or warning);
+ // - there is an SQL-handler for it.
- default:
- /* End aborted result set. */
+ DBUG_ASSERT(found_condition);
- if (end_partial_result_set)
- thd->protocol->end_partial_result_set(thd);
+ sp_handler_entry *handler_entry= NULL;
+ for (int i= 0; i < m_handlers.elements(); ++i)
+ {
+ sp_handler_entry *h= m_handlers.at(i);
- /* Enter handler. */
+ if (h->handler == found_handler)
+ {
+ handler_entry= h;
+ break;
+ }
+ }
- DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index());
- DBUG_ASSERT(m_hfound >= 0);
+ /*
+ handler_entry usually should not be NULL here, as that indicates
+ that the parser context thinks a HANDLER should be activated,
+ but the runtime context cannot find it.
+
+ However, this can happen (and this is in line with the Standard)
+ if SQL-condition has been raised before DECLARE HANDLER instruction
+ is processed.
+
+ For example:
+ CREATE PROCEDURE p()
+ BEGIN
+ DECLARE v INT DEFAULT 'get'; -- raises SQL-warning here
+ DECLARE EXIT HANDLER ... -- this handler does not catch the warning
+ END
+ */
+ if (!handler_entry)
+ DBUG_RETURN(false);
- m_in_handler[m_ihsp].ip= m_handler[m_hfound].handler;
- m_in_handler[m_ihsp].index= m_hfound;
- m_ihsp++;
+ // Mark active conditions so that they can be deleted when the handler exits.
+ da->mark_sql_conditions_for_removal();
- DBUG_PRINT("info", ("Entering handler..."));
- DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
+ uint continue_ip= handler_entry->handler->type == sp_handler::CONTINUE ?
+ cur_spi->get_cont_dest() : 0;
- /* Reset error state. */
+ /* End aborted result set. */
+ if (end_partial_result_set)
+ thd->protocol->end_partial_result_set(thd);
- thd->clear_error();
- thd->reset_killed(); // Some errors set thd->killed
- // (e.g. "bad data").
+ /* Reset error state. */
+ thd->clear_error();
+ thd->killed= NOT_KILLED; // Some errors set thd->killed
+ // (e.g. "bad data").
- /* Return IP of the activated SQL handler. */
- *ip= m_handler[m_hfound].handler;
+ /* Add a frame to handler-call-stack. */
+ Sql_condition_info *cond_info=
+ new (callers_arena->mem_root) Sql_condition_info(found_condition,
+ callers_arena);
+ Handler_call_frame *frame=
+ new (callers_arena->mem_root) Handler_call_frame(cond_info, continue_ip);
+ m_handler_call_stack.append(frame);
- /* Reset found handler. */
- m_hfound= -1;
- }
+ *ip= handler_entry->first_ip;
- return TRUE;
+ DBUG_RETURN(true);
}
-void
-sp_rcontext::exit_handler()
-{
- DBUG_ENTER("sp_rcontext::exit_handler");
- DBUG_ASSERT(m_ihsp);
-
- uint hindex= m_in_handler[m_ihsp-1].index;
- m_raised_conditions[hindex].clear();
- m_ihsp-= 1;
- DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
- DBUG_VOID_RETURN;
-}
-
-Sql_condition_info* sp_rcontext::raised_condition() const
+uint sp_rcontext::exit_handler(Diagnostics_area *da)
{
- if (m_ihsp > 0)
- {
- uint hindex= m_in_handler[m_ihsp - 1].index;
- Sql_condition_info *raised= & m_raised_conditions[hindex];
- return raised;
- }
+ DBUG_ENTER("sp_rcontext::exit_handler");
+ DBUG_ASSERT(m_handler_call_stack.elements() > 0);
- if (m_prev_runtime_ctx)
- return m_prev_runtime_ctx->raised_condition();
+ Handler_call_frame *f= m_handler_call_stack.pop();
- return NULL;
-}
+ /*
+ Remove the SQL conditions that were present in DA when the
+ handler was activated.
+ */
+ da->remove_marked_sql_conditions();
+ uint continue_ip= f->continue_ip;
-int
-sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value)
-{
- return set_variable(thd, m_var_table->field[var_idx], value);
+ DBUG_RETURN(continue_ip);
}
-int
-sp_rcontext::set_variable(THD *thd, Field *field, Item **value)
+int sp_rcontext::set_variable(THD *thd, Field *field, Item **value)
{
if (!value)
{
@@ -478,25 +361,47 @@ sp_rcontext::set_variable(THD *thd, Field *field, Item **value)
}
-Item *
-sp_rcontext::get_item(uint var_idx)
+Item_cache *sp_rcontext::create_case_expr_holder(THD *thd,
+ const Item *item) const
{
- return m_var_items[var_idx];
+ Item_cache *holder;
+ Query_arena current_arena;
+
+ thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
+
+ holder= Item_cache::get_cache(item);
+
+ thd->restore_active_arena(thd->spcont->callers_arena, &current_arena);
+
+ return holder;
}
-Item **
-sp_rcontext::get_item_addr(uint var_idx)
+bool sp_rcontext::set_case_expr(THD *thd, int case_expr_id,
+ Item **case_expr_item_ptr)
{
- return m_var_items + var_idx;
+ Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr);
+ if (!case_expr_item)
+ return true;
+
+ if (!m_case_expr_holders[case_expr_id] ||
+ m_case_expr_holders[case_expr_id]->result_type() !=
+ case_expr_item->result_type())
+ {
+ m_case_expr_holders[case_expr_id]=
+ create_case_expr_holder(thd, case_expr_item);
+ }
+
+ m_case_expr_holders[case_expr_id]->store(case_expr_item);
+ m_case_expr_holders[case_expr_id]->cache_value();
+ return false;
}
-/*
- *
- * sp_cursor
- *
- */
+///////////////////////////////////////////////////////////////////////////
+// sp_cursor implementation.
+///////////////////////////////////////////////////////////////////////////
+
sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
:m_lex_keeper(lex_keeper),
@@ -523,8 +428,7 @@ sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
0 in case of success, -1 otherwise
*/
-int
-sp_cursor::open(THD *thd)
+int sp_cursor::open(THD *thd)
{
if (server_side_cursor)
{
@@ -538,8 +442,7 @@ sp_cursor::open(THD *thd)
}
-int
-sp_cursor::close(THD *thd)
+int sp_cursor::close(THD *thd)
{
if (! server_side_cursor)
{
@@ -551,16 +454,14 @@ sp_cursor::close(THD *thd)
}
-void
-sp_cursor::destroy()
+void sp_cursor::destroy()
{
delete server_side_cursor;
- server_side_cursor= 0;
+ server_side_cursor= NULL;
}
-int
-sp_cursor::fetch(THD *thd, List<struct sp_variable> *vars)
+int sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
{
if (! server_side_cursor)
{
@@ -599,108 +500,13 @@ sp_cursor::fetch(THD *thd, List<struct sp_variable> *vars)
}
-/*
- Create an instance of appropriate Item_cache class depending on the
- specified type in the callers arena.
-
- SYNOPSIS
- thd thread handler
- result_type type of the expression
-
- RETURN
- Pointer to valid object on success
- NULL on error
-
- NOTE
- We should create cache items in the callers arena, as they are used
- between in several instructions.
-*/
-
-Item_cache *
-sp_rcontext::create_case_expr_holder(THD *thd, const Item *item)
-{
- Item_cache *holder;
- Query_arena current_arena;
-
- thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
-
- holder= Item_cache::get_cache(item);
-
- thd->restore_active_arena(thd->spcont->callers_arena, &current_arena);
-
- return holder;
-}
-
-
-/*
- Set CASE expression to the specified value.
-
- SYNOPSIS
- thd thread handler
- case_expr_id identifier of the CASE expression
- case_expr_item a value of the CASE expression
+///////////////////////////////////////////////////////////////////////////
+// sp_cursor::Select_fetch_into_spvars implementation.
+///////////////////////////////////////////////////////////////////////////
- RETURN
- FALSE on success
- TRUE on error
-
- NOTE
- The idea is to reuse Item_cache for the expression of the one CASE
- statement. This optimization takes place when there is CASE statement
- inside of a loop. So, in other words, we will use the same object on each
- iteration instead of creating a new one for each iteration.
-
- TODO
- Hypothetically, a type of CASE expression can be different for each
- iteration. For instance, this can happen if the expression contains a
- session variable (something like @@VAR) and its type is changed from one
- iteration to another.
-
- In order to cope with this problem, we check type each time, when we use
- already created object. If the type does not match, we re-create Item.
- This also can (should?) be optimized.
-*/
-int
-sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr)
-{
- Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr);
- if (!case_expr_item)
- return TRUE;
-
- if (!m_case_expr_holders[case_expr_id] ||
- m_case_expr_holders[case_expr_id]->result_type() !=
- case_expr_item->result_type())
- {
- m_case_expr_holders[case_expr_id]=
- create_case_expr_holder(thd, case_expr_item);
- }
-
- m_case_expr_holders[case_expr_id]->store(case_expr_item);
- m_case_expr_holders[case_expr_id]->cache_value();
- return FALSE;
-}
-
-
-Item *
-sp_rcontext::get_case_expr(int case_expr_id)
-{
- return m_case_expr_holders[case_expr_id];
-}
-
-
-Item **
-sp_rcontext::get_case_expr_addr(int case_expr_id)
-{
- return (Item**) m_case_expr_holders + case_expr_id;
-}
-
-
-/***************************************************************************
- Select_fetch_into_spvars
-****************************************************************************/
-
-int Select_fetch_into_spvars::prepare(List<Item> &fields, SELECT_LEX_UNIT *u)
+int sp_cursor::Select_fetch_into_spvars::prepare(List<Item> &fields,
+ SELECT_LEX_UNIT *u)
{
/*
Cache the number of columns in the result set in order to easily
@@ -711,11 +517,11 @@ int Select_fetch_into_spvars::prepare(List<Item> &fields, SELECT_LEX_UNIT *u)
}
-int Select_fetch_into_spvars::send_data(List<Item> &items)
+bool sp_cursor::Select_fetch_into_spvars::send_data(List<Item> &items)
{
- List_iterator_fast<struct sp_variable> spvar_iter(*spvar_list);
+ List_iterator_fast<sp_variable> spvar_iter(*spvar_list);
List_iterator_fast<Item> item_iter(items);
- sp_variable_t *spvar;
+ sp_variable *spvar;
Item *item;
/* Must be ensured by the caller */
@@ -728,7 +534,7 @@ int Select_fetch_into_spvars::send_data(List<Item> &items)
for (; spvar= spvar_iter++, item= item_iter++; )
{
if (thd->spcont->set_variable(thd, spvar->offset, &item))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index dd1d625a46c..00fbf3e13ab 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -22,80 +22,18 @@
#endif
#include "sql_class.h" // select_result_interceptor
+#include "sp_pcontext.h" // sp_condition_value
+
+///////////////////////////////////////////////////////////////////////////
+// sp_rcontext declaration.
+///////////////////////////////////////////////////////////////////////////
-struct sp_cond_type;
class sp_cursor;
-struct sp_variable;
class sp_lex_keeper;
class sp_instr_cpush;
class Query_arena;
class sp_head;
-class sp_pcontext;
class Item_cache;
-typedef class st_select_lex_unit SELECT_LEX_UNIT;
-class Server_side_cursor;
-
-#define SP_HANDLER_NONE 0
-#define SP_HANDLER_EXIT 1
-#define SP_HANDLER_CONTINUE 2
-#define SP_HANDLER_UNDO 3
-
-typedef struct
-{
- /** Condition caught by this HANDLER. */
- struct sp_cond_type *cond;
- /** Location (instruction pointer) of the handler code. */
- uint handler;
- /** Handler type (EXIT, CONTINUE). */
- int type;
-} sp_handler_t;
-
-typedef struct
-{
- /** Instruction pointer of the active handler. */
- uint ip;
- /** Handler index of the active handler. */
- uint index;
-} sp_active_handler_t;
-
-
-class Sql_condition_info : public Sql_alloc
-{
-public:
- /** SQL error code. */
- uint m_sql_errno;
-
- /** Error level. */
- Sql_condition::enum_warning_level m_level;
-
- /** SQLSTATE. */
- char m_sql_state[SQLSTATE_LENGTH + 1];
-
- /** Text message. */
- char m_message[MYSQL_ERRMSG_SIZE];
-
- void set(uint sql_errno, const char* sqlstate,
- Sql_condition::enum_warning_level level,
- const char* msg)
- {
- m_sql_errno= sql_errno;
- m_level= level;
-
- memcpy(m_sql_state, sqlstate, SQLSTATE_LENGTH);
- m_sql_state[SQLSTATE_LENGTH]= '\0';
-
- strncpy(m_message, msg, MYSQL_ERRMSG_SIZE);
- }
-
- void clear()
- {
- m_sql_errno= 0;
- m_level= Sql_condition::WARN_LEVEL_ERROR;
-
- m_sql_state[0]= '\0';
- m_message[0]= '\0';
- }
-};
/*
@@ -119,251 +57,412 @@ public:
class sp_rcontext : public Sql_alloc
{
- sp_rcontext(const sp_rcontext &); /* Prevent use of these */
- void operator=(sp_rcontext &);
-
- public:
-
- /*
- Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT
- SP parameters when they don't fit into prealloced items. This
- is common situation with String items. It is used mainly in
- sp_eval_func_item().
- */
- Query_arena *callers_arena;
-
- /*
- End a open result set before start executing a continue/exit
- handler if one is found as otherwise the client will hang
- due to a violation of the client/server protocol.
- */
- bool end_partial_result_set;
-
-#ifndef DBUG_OFF
- /*
- The routine for which this runtime context is created. Used for checking
- if correct runtime context is used for variable handling.
- */
- sp_head *sp;
-#endif
-
- sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld,
- sp_rcontext *prev_runtime_ctx);
- bool init(THD *thd);
+public:
+ /// Construct and properly initialize a new sp_rcontext instance. The static
+ /// create-function is needed because we need a way to return an error from
+ /// the constructor.
+ ///
+ /// @param thd Thread handle.
+ /// @param root_parsing_ctx Top-level parsing context for this stored program.
+ /// @param return_value_fld Field object to store the return value
+ /// (for stored functions only).
+ ///
+ /// @return valid sp_rcontext object or NULL in case of OOM-error.
+ static sp_rcontext *create(THD *thd,
+ const sp_pcontext *root_parsing_ctx,
+ Field *return_value_fld);
~sp_rcontext();
- int
- set_variable(THD *thd, uint var_idx, Item **value);
-
- Item *
- get_item(uint var_idx);
+private:
+ sp_rcontext(const sp_pcontext *root_parsing_ctx,
+ Field *return_value_fld,
+ bool in_sub_stmt);
- Item **
- get_item_addr(uint var_idx);
+ // Prevent use of copying constructor and operator.
+ sp_rcontext(const sp_rcontext &);
+ void operator=(sp_rcontext &);
- bool
- set_return_value(THD *thd, Item **return_value_item);
+private:
+ /// This is an auxillary class to store entering instruction pointer for an
+ /// SQL-handler.
+ class sp_handler_entry : public Sql_alloc
+ {
+ public:
+ /// Handler definition (from parsing context).
+ const sp_handler *handler;
+
+ /// Instruction pointer to the first instruction.
+ uint first_ip;
+
+ /// The constructor.
+ ///
+ /// @param _handler sp_handler object.
+ /// @param _first_ip first instruction pointer.
+ sp_handler_entry(const sp_handler *_handler, uint _first_ip)
+ :handler(_handler), first_ip(_first_ip)
+ { }
+ };
- inline bool
- is_return_value_set() const
+public:
+ /// This class stores basic information about SQL-condition, such as:
+ /// - SQL error code;
+ /// - error level;
+ /// - SQLSTATE;
+ /// - text message.
+ ///
+ /// It's used to organize runtime SQL-handler call stack.
+ ///
+ /// Standard Sql_condition class can not be used, because we don't always have
+ /// an Sql_condition object for an SQL-condition in Diagnostics_area.
+ ///
+ /// Eventually, this class should be moved to sql_error.h, and be a part of
+ /// standard SQL-condition processing (Diagnostics_area should contain an
+ /// object for active SQL-condition, not just information stored in DA's
+ /// fields).
+ class Sql_condition_info : public Sql_alloc
{
- return m_return_value_set;
- }
+ public:
+ /// SQL error code.
+ uint sql_errno;
+
+ /// Error level.
+ Sql_condition::enum_warning_level level;
+
+ /// SQLSTATE.
+ char sql_state[SQLSTATE_LENGTH + 1];
+
+ /// Text message.
+ char *message;
+
+ /// The constructor.
+ ///
+ /// @param _sql_condition The SQL condition.
+ /// @param arena Query arena for SP
+ Sql_condition_info(const Sql_condition *_sql_condition,
+ Query_arena *arena)
+ :sql_errno(_sql_condition->get_sql_errno()),
+ level(_sql_condition->get_level())
+ {
+ memcpy(sql_state, _sql_condition->get_sqlstate(), SQLSTATE_LENGTH);
+ sql_state[SQLSTATE_LENGTH]= '\0';
+
+ message= strdup_root(arena->mem_root, _sql_condition->get_message_text());
+ }
+ };
- /*
- SQL handlers support.
- */
+private:
+ /// This class represents a call frame of SQL-handler (one invocation of a
+ /// handler). Basically, it's needed to store continue instruction pointer for
+ /// CONTINUE SQL-handlers.
+ class Handler_call_frame : public Sql_alloc
+ {
+ public:
+ /// SQL-condition, triggered handler activation.
+ const Sql_condition_info *sql_condition;
+
+ /// Continue-instruction-pointer for CONTINUE-handlers.
+ /// The attribute contains 0 for EXIT-handlers.
+ uint continue_ip;
+
+ /// The constructor.
+ ///
+ /// @param _sql_condition SQL-condition, triggered handler activation.
+ /// @param _continue_ip Continue instruction pointer.
+ Handler_call_frame(const Sql_condition_info *_sql_condition,
+ uint _continue_ip)
+ :sql_condition(_sql_condition),
+ continue_ip(_continue_ip)
+ { }
+ };
- void push_handler(struct sp_cond_type *cond, uint h, int type);
+public:
+ /// Arena used to (re) allocate items on. E.g. reallocate INOUT/OUT
+ /// SP-variables when they don't fit into prealloced items. This is common
+ /// situation with String items. It is used mainly in sp_eval_func_item().
+ Query_arena *callers_arena;
- void pop_handlers(uint count);
+ /// Flag to end an open result set before start executing an SQL-handler
+ /// (if one is found). Otherwise the client will hang due to a violation
+ /// of the client/server protocol.
+ bool end_partial_result_set;
- bool
- find_handler(THD *thd,
- uint sql_errno,
- const char *sqlstate,
- Sql_condition::enum_warning_level level,
- const char *msg);
+#ifndef DBUG_OFF
+ /// The stored program for which this runtime context is created. Used for
+ /// checking if correct runtime context is used for variable handling.
+ sp_head *sp;
+#endif
- Sql_condition_info *raised_condition() const;
+ /////////////////////////////////////////////////////////////////////////
+ // SP-variables.
+ /////////////////////////////////////////////////////////////////////////
- void
- push_hstack(uint h);
+ int set_variable(THD *thd, uint var_idx, Item **value)
+ { return set_variable(thd, m_var_table->field[var_idx], value); }
- uint
- pop_hstack();
+ Item *get_item(uint var_idx) const
+ { return m_var_items[var_idx]; }
- bool
- activate_handler(THD *thd,
- uint *ip,
- sp_instr *instr,
- Query_arena *execute_arena,
- Query_arena *backup_arena);
+ Item **get_item_addr(uint var_idx) const
+ { return m_var_items.array() + var_idx; }
+ bool set_return_value(THD *thd, Item **return_value_item);
- void
- exit_handler();
+ bool is_return_value_set() const
+ { return m_return_value_set; }
- void
- push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
+ /////////////////////////////////////////////////////////////////////////
+ // SQL-handlers.
+ /////////////////////////////////////////////////////////////////////////
- void
- pop_cursors(uint count);
+ /// Create a new sp_handler_entry instance and push it to the handler call
+ /// stack.
+ ///
+ /// @param handler SQL-handler object.
+ /// @param first_ip First instruction pointer of the handler.
+ ///
+ /// @return error flag.
+ /// @retval false on success.
+ /// @retval true on error.
+ bool push_handler(sp_handler *handler, uint first_ip);
- inline void
- pop_all_cursors()
- {
- pop_cursors(m_ccount);
- }
+ /// Pop and delete given number of sp_handler_entry instances from the handler
+ /// call stack.
+ ///
+ /// @param count Number of handler entries to pop & delete.
+ void pop_handlers(int count);
- inline sp_cursor *
- get_cursor(uint i)
+ const Sql_condition_info *raised_condition() const
{
- return m_cstack[i];
+ return m_handler_call_stack.elements() ?
+ (*m_handler_call_stack.back())->sql_condition : NULL;
}
- /*
- CASE expressions support.
- */
+ /// Handle current SQL condition (if any).
+ ///
+ /// This is the public-interface function to handle SQL conditions in
+ /// stored routines.
+ ///
+ /// @param thd Thread handle.
+ /// @param ip[out] Instruction pointer to the first handler
+ /// instruction.
+ /// @param cur_spi Current SP instruction.
+ ///
+ /// @retval true if an SQL-handler has been activated. That means, all of
+ /// the following conditions are satisfied:
+ /// - the SP-instruction raised SQL-condition(s),
+ /// - and there is an SQL-handler to process at least one of those
+ /// SQL-conditions,
+ /// - and that SQL-handler has been activated.
+ /// Note, that the return value has nothing to do with "error flag"
+ /// semantics.
+ ///
+ /// @retval false otherwise.
+ bool handle_sql_condition(THD *thd,
+ uint *ip,
+ const sp_instr *cur_spi);
+
+ /// Remove latest call frame from the handler call stack.
+ ///
+ /// @param da Diagnostics area containing handled conditions.
+ ///
+ /// @return continue instruction pointer of the removed handler.
+ uint exit_handler(Diagnostics_area *da);
+
+ /////////////////////////////////////////////////////////////////////////
+ // Cursors.
+ /////////////////////////////////////////////////////////////////////////
+
+ /// Create a new sp_cursor instance and push it to the cursor stack.
+ ///
+ /// @param lex_keeper SP-instruction execution helper.
+ /// @param i Cursor-push instruction.
+ ///
+ /// @return error flag.
+ /// @retval false on success.
+ /// @retval true on error.
+ bool push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
+
+ /// Pop and delete given number of sp_cursor instance from the cursor stack.
+ ///
+ /// @param count Number of cursors to pop & delete.
+ void pop_cursors(uint count);
+
+ void pop_all_cursors()
+ { pop_cursors(m_ccount); }
+
+ sp_cursor *get_cursor(uint i) const
+ { return m_cstack[i]; }
+
+ /////////////////////////////////////////////////////////////////////////
+ // CASE expressions.
+ /////////////////////////////////////////////////////////////////////////
+
+ /// Set CASE expression to the specified value.
+ ///
+ /// @param thd Thread handler.
+ /// @param case_expr_id The CASE expression identifier.
+ /// @param case_expr_item The CASE expression value
+ ///
+ /// @return error flag.
+ /// @retval false on success.
+ /// @retval true on error.
+ ///
+ /// @note The idea is to reuse Item_cache for the expression of the one
+ /// CASE statement. This optimization takes place when there is CASE
+ /// statement inside of a loop. So, in other words, we will use the same
+ /// object on each iteration instead of creating a new one for each
+ /// iteration.
+ ///
+ /// TODO
+ /// Hypothetically, a type of CASE expression can be different for each
+ /// iteration. For instance, this can happen if the expression contains
+ /// a session variable (something like @@VAR) and its type is changed
+ /// from one iteration to another.
+ ///
+ /// In order to cope with this problem, we check type each time, when we
+ /// use already created object. If the type does not match, we re-create
+ /// Item. This also can (should?) be optimized.
+ bool set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr);
+
+ Item *get_case_expr(int case_expr_id) const
+ { return m_case_expr_holders[case_expr_id]; }
+
+ Item ** get_case_expr_addr(int case_expr_id) const
+ { return (Item**) m_case_expr_holders.array() + case_expr_id; }
- int
- set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr);
+private:
+ /// Internal function to allocate memory for arrays.
+ ///
+ /// @param thd Thread handle.
+ ///
+ /// @return error flag: false on success, true in case of failure.
+ bool alloc_arrays(THD *thd);
+
+ /// Create and initialize a table to store SP-variables.
+ ///
+ /// param thd Thread handle.
+ ///
+ /// @return error flag.
+ /// @retval false on success.
+ /// @retval true on error.
+ bool init_var_table(THD *thd);
- Item *
- get_case_expr(int case_expr_id);
+ /// Create and initialize an Item-adapter (Item_field) for each SP-var field.
+ ///
+ /// param thd Thread handle.
+ ///
+ /// @return error flag.
+ /// @retval false on success.
+ /// @retval true on error.
+ bool init_var_items(THD *thd);
+
+ /// Create an instance of appropriate Item_cache class depending on the
+ /// specified type in the callers arena.
+ ///
+ /// @note We should create cache items in the callers arena, as they are
+ /// used between in several instructions.
+ ///
+ /// @param thd Thread handler.
+ /// @param item Item to get the expression type.
+ ///
+ /// @return Pointer to valid object on success, or NULL in case of error.
+ Item_cache *create_case_expr_holder(THD *thd, const Item *item) const;
- Item **
- get_case_expr_addr(int case_expr_id);
+ int set_variable(THD *thd, Field *field, Item **value);
private:
- sp_pcontext *m_root_parsing_ctx;
+ /// Top-level (root) parsing context for this runtime context.
+ const sp_pcontext *m_root_parsing_ctx;
- /* Virtual table for storing variables. */
+ /// Virtual table for storing SP-variables.
TABLE *m_var_table;
- /*
- Collection of Item_field proxies, each of them points to the corresponding
- field in m_var_table.
- */
- Item **m_var_items;
+ /// Collection of Item_field proxies, each of them points to the
+ /// corresponding field in m_var_table.
+ Bounds_checked_array<Item *> m_var_items;
- /*
- This is a pointer to a field, which should contain return value for stored
- functions (only). For stored procedures, this pointer is NULL.
- */
+ /// This is a pointer to a field, which should contain return value for
+ /// stored functions (only). For stored procedures, this pointer is NULL.
Field *m_return_value_fld;
- /*
- Indicates whether the return value (in m_return_value_fld) has been set
- during execution.
- */
+ /// Indicates whether the return value (in m_return_value_fld) has been
+ /// set during execution.
bool m_return_value_set;
- /**
- TRUE if the context is created for a sub-statement.
- */
- bool in_sub_stmt;
+ /// Flag to tell if the runtime context is created for a sub-statement.
+ bool m_in_sub_stmt;
- sp_handler_t *m_handler; // Visible handlers
+ /// Stack of visible handlers.
+ Dynamic_array<sp_handler_entry *> m_handlers;
- /**
- SQL conditions caught by each handler.
- This is an array indexed by handler index.
- */
- Sql_condition_info *m_raised_conditions;
+ /// Stack of caught SQL conditions.
+ Dynamic_array<Handler_call_frame *> m_handler_call_stack;
- uint m_hcount; // Stack pointer for m_handler
- uint *m_hstack; // Return stack for continue handlers
- uint m_hsp; // Stack pointer for m_hstack
- /** Active handler stack. */
- sp_active_handler_t *m_in_handler;
- uint m_ihsp; // Stack pointer for m_in_handler
- int m_hfound; // Set by find_handler; -1 if not found
+ /// Stack of cursors.
+ Bounds_checked_array<sp_cursor *> m_cstack;
- sp_cursor **m_cstack;
+ /// Current number of cursors in m_cstack.
uint m_ccount;
- Item_cache **m_case_expr_holders;
-
- /* Previous runtime context (NULL if none) */
- sp_rcontext *m_prev_runtime_ctx;
-
-private:
- bool init_var_table(THD *thd);
- bool init_var_items();
-
- Item_cache *create_case_expr_holder(THD *thd, const Item *item);
-
- int set_variable(THD *thd, Field *field, Item **value);
+ /// Array of CASE expression holders.
+ Bounds_checked_array<Item_cache *> m_case_expr_holders;
}; // class sp_rcontext : public Sql_alloc
+///////////////////////////////////////////////////////////////////////////
+// sp_cursor declaration.
+///////////////////////////////////////////////////////////////////////////
-/*
- An interceptor of cursor result set used to implement
- FETCH <cname> INTO <varlist>.
-*/
-
-class Select_fetch_into_spvars: public select_result_interceptor
-{
- List<struct sp_variable> *spvar_list;
- uint field_count;
-public:
- Select_fetch_into_spvars() {} /* Remove gcc warning */
- uint get_field_count() { return field_count; }
- void set_spvar_list(List<struct sp_variable> *vars) { spvar_list= vars; }
-
- virtual bool send_eof() { return FALSE; }
- virtual int send_data(List<Item> &items);
- virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
-};
-
+class Server_side_cursor;
+typedef class st_select_lex_unit SELECT_LEX_UNIT;
/* A mediator between stored procedures and server side cursors */
class sp_cursor : public Sql_alloc
{
-public:
+private:
+ /// An interceptor of cursor result set used to implement
+ /// FETCH <cname> INTO <varlist>.
+ class Select_fetch_into_spvars: public select_result_interceptor
+ {
+ List<sp_variable> *spvar_list;
+ uint field_count;
+ public:
+ Select_fetch_into_spvars() {} /* Remove gcc warning */
+ uint get_field_count() { return field_count; }
+ void set_spvar_list(List<sp_variable> *vars) { spvar_list= vars; }
+
+ virtual bool send_eof() { return FALSE; }
+ virtual bool send_data(List<Item> &items);
+ virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
+};
+public:
sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
virtual ~sp_cursor()
- {
- destroy();
- }
+ { destroy(); }
- sp_lex_keeper *
- get_lex_keeper() { return m_lex_keeper; }
+ sp_lex_keeper *get_lex_keeper() { return m_lex_keeper; }
- int
- open(THD *thd);
+ int open(THD *thd);
- int
- close(THD *thd);
+ int close(THD *thd);
- inline bool
- is_open()
- {
- return test(server_side_cursor);
- }
+ my_bool is_open()
+ { return test(server_side_cursor); }
- int
- fetch(THD *, List<struct sp_variable> *vars);
+ int fetch(THD *, List<sp_variable> *vars);
- inline sp_instr_cpush *
- get_instr()
- {
- return m_i;
- }
+ sp_instr_cpush *get_instr()
+ { return m_i; }
private:
-
Select_fetch_into_spvars result;
sp_lex_keeper *m_lex_keeper;
Server_side_cursor *server_side_cursor;
sp_instr_cpush *m_i; // My push instruction
- void
- destroy();
+ void destroy();
}; // class sp_cursor : public Sql_alloc
diff --git a/sql/sql_array.h b/sql/sql_array.h
index 9ac27cca63b..baed3687215 100644
--- a/sql/sql_array.h
+++ b/sql/sql_array.h
@@ -100,28 +100,64 @@ template <class Elem> class Dynamic_array
public:
Dynamic_array(uint prealloc=16, uint increment=16)
{
+ init(prealloc, increment);
+ }
+
+ void init(uint prealloc=16, uint increment=16)
+ {
my_init_dynamic_array(&array, sizeof(Elem), prealloc, increment,
MYF(MY_THREAD_SPECIFIC));
}
+ /**
+ @note Though formally this could be declared "const" it would be
+ misleading at it returns a non-const pointer to array's data.
+ */
Elem& at(int idx)
{
return *(((Elem*)array.buffer) + idx);
}
+ /// Const variant of at(), which cannot change data
+ const Elem& at(int idx) const
+ {
+ return *(((Elem*)array.buffer) + idx);
+ }
+ /// @returns pointer to first element; undefined behaviour if array is empty
Elem *front()
{
+ DBUG_ASSERT(array.elements >= 1);
return (Elem*)array.buffer;
}
+ /// @returns pointer to first element; undefined behaviour if array is empty
+ const Elem *front() const
+ {
+ DBUG_ASSERT(array.elements >= 1);
+ return (const Elem*)array.buffer;
+ }
+
+ /// @returns pointer to last element; undefined behaviour if array is empty.
Elem *back()
{
- return ((Elem*)array.buffer) + array.elements;
+ DBUG_ASSERT(array.elements >= 1);
+ return ((Elem*)array.buffer) + (array.elements - 1);
+ }
+
+ /// @returns pointer to last element; undefined behaviour if array is empty.
+ const Elem *back() const
+ {
+ DBUG_ASSERT(array.elements >= 1);
+ return ((const Elem*)array.buffer) + (array.elements - 1);
}
- bool append(Elem &el)
+ /**
+ @retval false ok
+ @retval true OOM, @c my_error() has been called.
+ */
+ bool append(const Elem &el)
{
- return (insert_dynamic(&array, (uchar*)&el));
+ return insert_dynamic(&array, &el);
}
/// Pops the last element. Does nothing if array is empty.
@@ -135,91 +171,37 @@ public:
delete_dynamic_element(&array, idx);
}
- int elements()
+ int elements() const
{
return array.elements;
}
- ~Dynamic_array()
- {
- delete_dynamic(&array);
- }
-
- typedef int (*CMP_FUNC)(const Elem *el1, const Elem *el2);
-
- void sort(CMP_FUNC cmp_func)
- {
- my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func);
- }
-};
-
-/*
- Array of pointers to Elem that uses memory from MEM_ROOT
-
- MEM_ROOT has no realloc() so this is supposed to be used for cases when
- reallocations are rare.
-*/
-
-template <class Elem> class Array
-{
- enum {alloc_increment = 16};
- Elem **buffer;
- uint n_elements, max_element;
-public:
- Array(MEM_ROOT *mem_root, uint prealloc=16)
- {
- buffer= (Elem**)alloc_root(mem_root, prealloc * sizeof(Elem**));
- max_element = buffer? prealloc : 0;
- n_elements= 0;
- }
-
- Elem& at(int idx)
- {
- return *(((Elem*)buffer) + idx);
- }
-
- Elem **front()
- {
- return buffer;
- }
-
- Elem **back()
+ void elements(uint num_elements)
{
- return buffer + n_elements;
+ DBUG_ASSERT(num_elements <= array.max_element);
+ array.elements= num_elements;
}
- bool append(MEM_ROOT *mem_root, Elem *el)
+ void clear()
{
- if (n_elements == max_element)
- {
- Elem **newbuf;
- if (!(newbuf= (Elem**)alloc_root(mem_root, (n_elements + alloc_increment)*
- sizeof(Elem**))))
- {
- return FALSE;
- }
- memcpy(newbuf, buffer, n_elements*sizeof(Elem*));
- buffer= newbuf;
- }
- buffer[n_elements++]= el;
- return FALSE;
+ elements(0);
}
- int elements()
+ void set(uint idx, const Elem &el)
{
- return n_elements;
+ set_dynamic(&array, &el, idx);
}
- void clear()
+ ~Dynamic_array()
{
- n_elements= 0;
+ delete_dynamic(&array);
}
- typedef int (*CMP_FUNC)(Elem * const *el1, Elem *const *el2);
+ typedef int (*CMP_FUNC)(const Elem *el1, const Elem *el2);
void sort(CMP_FUNC cmp_func)
{
- my_qsort(buffer, n_elements, sizeof(Elem*), (qsort_cmp)cmp_func);
+ my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func);
}
};
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 7ef0ea29434..4f19b18b126 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -72,6 +72,8 @@
char internal_table_name[2]= "*";
char empty_c_string[1]= {0}; /* used for not defined db */
+LEX_STRING EMPTY_STR= { (char *) "", 0 };
+
const char * const THD::DEFAULT_WHERE= "field list";
/****************************************************************************
@@ -2454,7 +2456,7 @@ void select_send::cleanup()
/* Send data to client. Returns 0 if ok */
-int select_send::send_data(List<Item> &items)
+bool select_send::send_data(List<Item> &items)
{
Protocol *protocol= thd->protocol;
DBUG_ENTER("select_send::send_data");
@@ -2744,7 +2746,7 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
(int) (uchar) (x) == line_sep_char || \
!(x))
-int select_export::send_data(List<Item> &items)
+bool select_export::send_data(List<Item> &items)
{
DBUG_ENTER("select_export::send_data");
@@ -3003,7 +3005,7 @@ select_dump::prepare(List<Item> &list __attribute__((unused)),
}
-int select_dump::send_data(List<Item> &items)
+bool select_dump::send_data(List<Item> &items)
{
List_iterator_fast<Item> li(items);
char buff[MAX_FIELD_WIDTH];
@@ -3051,7 +3053,7 @@ select_subselect::select_subselect(Item_subselect *item_arg)
}
-int select_singlerow_subselect::send_data(List<Item> &items)
+bool select_singlerow_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_singlerow_subselect::send_data");
Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
@@ -3085,7 +3087,7 @@ void select_max_min_finder_subselect::cleanup()
}
-int select_max_min_finder_subselect::send_data(List<Item> &items)
+bool select_max_min_finder_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_max_min_finder_subselect::send_data");
Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
@@ -3202,7 +3204,7 @@ bool select_max_min_finder_subselect::cmp_str()
return (sortcmp(val1, val2, cache->collation.collation) < 0);
}
-int select_exists_subselect::send_data(List<Item> &items)
+bool select_exists_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_exists_subselect::send_data");
Item_exists_subselect *it= (Item_exists_subselect *)item;
@@ -3585,7 +3587,7 @@ Statement_map::~Statement_map()
my_hash_free(&st_hash);
}
-int select_dumpvar::send_data(List<Item> &items)
+bool select_dumpvar::send_data(List<Item> &items)
{
List_iterator_fast<my_var> var_li(var_list);
List_iterator<Item> it(items);
@@ -3691,7 +3693,7 @@ void select_materialize_with_stats::cleanup()
@return FALSE on success
*/
-int select_materialize_with_stats::send_data(List<Item> &items)
+bool select_materialize_with_stats::send_data(List<Item> &items)
{
List_iterator_fast<Item> item_it(items);
Item *cur_item;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 81a4b52f887..f69468f0a99 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -121,6 +121,7 @@ enum enum_filetype { FILETYPE_CSV, FILETYPE_XML };
extern char internal_table_name[2];
extern char empty_c_string[1];
+extern LEX_STRING EMPTY_STR;
extern MYSQL_PLUGIN_IMPORT const char **errmesg;
extern bool volatile shutdown_in_progress;
@@ -3465,7 +3466,7 @@ public:
send_data returns 0 on ok, 1 on error and -1 if data was ignored, for
example for a duplicate row entry written to a temp table.
*/
- virtual int send_data(List<Item> &items)=0;
+ virtual bool send_data(List<Item> &items)=0;
virtual ~select_result_sink() {};
};
@@ -3557,7 +3558,7 @@ public:
TABLE *dst_table; /* table to write into */
/* The following is called in the child thread: */
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
};
@@ -3592,7 +3593,7 @@ class select_send :public select_result {
public:
select_send() :is_result_set_started(FALSE) {}
bool send_result_set_metadata(List<Item> &list, uint flags);
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
bool send_eof();
virtual bool check_simple_select() const { return FALSE; }
void abort_result_set();
@@ -3655,7 +3656,7 @@ public:
select_export(sql_exchange *ex) :select_to_file(ex) {}
~select_export();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
};
@@ -3663,7 +3664,7 @@ class select_dump :public select_to_file {
public:
select_dump(sql_exchange *ex) :select_to_file(ex) {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
};
@@ -3682,7 +3683,7 @@ class select_insert :public select_result_interceptor {
~select_insert();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
virtual int prepare2(void);
- virtual int send_data(List<Item> &items);
+ virtual bool send_data(List<Item> &items);
virtual void store_values(List<Item> &values);
virtual bool can_rollback_data() { return 0; }
void send_error(uint errcode,const char *err);
@@ -3865,7 +3866,7 @@ public:
select_union() :write_err(0), table(0), records(0) { tmp_table_param.init(); }
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
bool send_eof();
bool flush();
void cleanup();
@@ -3884,7 +3885,7 @@ protected:
Item_subselect *item;
public:
select_subselect(Item_subselect *item);
- int send_data(List<Item> &items)=0;
+ bool send_data(List<Item> &items)=0;
bool send_eof() { return 0; };
};
@@ -3895,7 +3896,7 @@ public:
select_singlerow_subselect(Item_subselect *item_arg)
:select_subselect(item_arg)
{}
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
};
@@ -3945,7 +3946,7 @@ public:
bool bit_fields_as_long,
bool create_table);
bool init_result_table(ulonglong select_options);
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
void cleanup();
ha_rows get_null_count_of_col(uint idx)
{
@@ -3979,7 +3980,7 @@ public:
:select_subselect(item_arg), cache(0), fmax(mx), is_all(all)
{}
void cleanup();
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
bool cmp_real();
bool cmp_int();
bool cmp_decimal();
@@ -3992,7 +3993,7 @@ class select_exists_subselect :public select_subselect
public:
select_exists_subselect(Item_subselect *item_arg)
:select_subselect(item_arg){}
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
};
@@ -4244,7 +4245,7 @@ public:
multi_delete(TABLE_LIST *dt, uint num_of_tables);
~multi_delete();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
bool initialize_tables (JOIN *join);
void send_error(uint errcode,const char *err);
int do_deletes();
@@ -4292,7 +4293,7 @@ public:
enum_duplicates handle_duplicates, bool ignore);
~multi_update();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
bool initialize_tables (JOIN *join);
void send_error(uint errcode,const char *err);
int do_updates();
@@ -4335,7 +4336,7 @@ public:
select_dumpvar() { var_list.empty(); row_count= 0;}
~select_dumpvar() {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- int send_data(List<Item> &items);
+ bool send_data(List<Item> &items);
bool send_eof();
virtual bool check_simple_select() const;
void cleanup();
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index d0a83eac189..af6c7a2db73 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -759,7 +759,7 @@ multi_delete::~multi_delete()
}
-int multi_delete::send_data(List<Item> &values)
+bool multi_delete::send_data(List<Item> &values)
{
int secure_counter= delete_while_scanning ? -1 : 0;
TABLE_LIST *del_table;
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index fc5beb31218..2fb16a49c2b 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -1001,3 +1001,32 @@ uint32 convert_error_message(char *to, uint32 to_length, CHARSET_INFO *to_cs,
*errors= error_count;
return (uint32) (to - to_start);
}
+
+
+/**
+ Sanity check for SQLSTATEs. The function does not check if it's really an
+ existing SQL-state (there are just too many), it just checks string length and
+ looks for bad characters.
+
+ @param sqlstate the condition SQLSTATE.
+
+ @retval true if it's ok.
+ @retval false if it's bad.
+*/
+
+bool is_sqlstate_valid(const LEX_STRING *sqlstate)
+{
+ if (sqlstate->length != 5)
+ return false;
+
+ for (int i= 0 ; i < 5 ; ++i)
+ {
+ char c = sqlstate->str[i];
+
+ if ((c < '0' || '9' < c) &&
+ (c < 'A' || 'Z' < c))
+ return false;
+ }
+
+ return true;
+}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 8c5fb96012d..21bf07cd653 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -3537,7 +3537,7 @@ select_insert::~select_insert()
}
-int select_insert::send_data(List<Item> &values)
+bool select_insert::send_data(List<Item> &values)
{
DBUG_ENTER("select_insert::send_data");
bool error=0;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 4649555a348..f3c6023de70 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -126,7 +126,7 @@ class Select_fetch_protocol_binary: public select_send
public:
Select_fetch_protocol_binary(THD *thd);
virtual bool send_result_set_metadata(List<Item> &list, uint flags);
- virtual int send_data(List<Item> &items);
+ virtual bool send_data(List<Item> &items);
virtual bool send_eof();
#ifdef EMBEDDED_LIBRARY
void begin_dataset()
@@ -3057,7 +3057,7 @@ bool Select_fetch_protocol_binary::send_eof()
}
-int
+bool
Select_fetch_protocol_binary::send_data(List<Item> &fields)
{
Protocol *save_protocol= thd->protocol;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index f3cb797226c..349d79900a0 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2367,7 +2367,7 @@ void Show_explain_request::call_in_target_thread()
}
-int select_result_explain_buffer::send_data(List<Item> &items)
+bool select_result_explain_buffer::send_data(List<Item> &items)
{
int res;
THD *cur_thd= current_thd;
@@ -5713,16 +5713,16 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
for (uint i= 0 ; i < params ; i++)
{
const char *tmp_buff;
- sp_variable_t *spvar= spcont->find_variable(i);
+ sp_variable *spvar= spcont->find_variable(i);
field_def= &spvar->field_def;
switch (spvar->mode) {
- case sp_param_in:
+ case sp_variable::MODE_IN:
tmp_buff= "IN";
break;
- case sp_param_out:
+ case sp_variable::MODE_OUT:
tmp_buff= "OUT";
break;
- case sp_param_inout:
+ case sp_variable::MODE_INOUT:
tmp_buff= "INOUT";
break;
default:
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
index 81e16cec774..ab5003fa86a 100644
--- a/sql/sql_signal.cc
+++ b/sql/sql_signal.cc
@@ -115,8 +115,8 @@ void Sql_cmd_common_signal::eval_defaults(THD *thd, Sql_condition *cond)
/*
SIGNAL is restricted in sql_yacc.yy to only signal SQLSTATE conditions.
*/
- DBUG_ASSERT(m_cond->type == sp_cond_type::state);
- sqlstate= m_cond->sqlstate;
+ DBUG_ASSERT(m_cond->type == sp_condition_value::SQLSTATE);
+ sqlstate= m_cond->sql_state;
cond->set_sqlstate(sqlstate);
}
else
@@ -488,8 +488,8 @@ bool Sql_cmd_signal::execute(THD *thd)
bool Sql_cmd_resignal::execute(THD *thd)
{
- Sql_condition_info *signaled;
Diagnostics_area *da= thd->get_stmt_da();
+ const sp_rcontext::Sql_condition_info *signaled;
int result= TRUE;
DBUG_ENTER("Resignal_statement::execute");
@@ -505,16 +505,31 @@ bool Sql_cmd_resignal::execute(THD *thd)
}
Sql_condition signaled_err(thd->mem_root);
- signaled_err.set(signaled->m_sql_errno,
- signaled->m_sql_state,
- signaled->m_level,
- signaled->m_message);
+ signaled_err.set(signaled->sql_errno,
+ signaled->sql_state,
+ signaled->level,
+ signaled->message);
if (m_cond == NULL)
{
- /* RESIGNAL without signal_value */
- result= raise_condition(thd, &signaled_err);
- DBUG_RETURN(result);
+ query_cache_abort(&thd->query_cache_tls);
+
+ /* Keep handled conditions. */
+ da->unmark_sql_conditions_from_removal();
+
+ /* Check if the old condition still exists. */
+ if (da->has_sql_condition(signaled->message, strlen(signaled->message)))
+ {
+ /* Make room for the new RESIGNAL condition. */
+ da->reserve_space(thd, 1);
+ }
+ else
+ {
+ /* Make room for old condition + the new RESIGNAL condition. */
+ da->reserve_space(thd, 2);
+
+ da->push_warning(thd, &signaled_err);
+ }
}
/* RESIGNAL with signal_value */
diff --git a/sql/sql_signal.h b/sql/sql_signal.h
index 6c77d4cb0bb..2a508eed5bf 100644
--- a/sql/sql_signal.h
+++ b/sql/sql_signal.h
@@ -29,7 +29,7 @@ protected:
@param cond the condition signaled if any, or NULL.
@param set collection of signal condition item assignments.
*/
- Sql_cmd_common_signal(const sp_cond_type *cond,
+ Sql_cmd_common_signal(const sp_condition_value *cond,
const Set_signal_information& set)
: Sql_cmd(),
m_cond(cond),
@@ -80,7 +80,7 @@ protected:
The condition to signal or resignal.
This member is optional and can be NULL (RESIGNAL).
*/
- const sp_cond_type *m_cond;
+ const sp_condition_value *m_cond;
/**
Collection of 'SET item = value' assignments in the
@@ -100,7 +100,7 @@ public:
@param cond the SQL condition to signal (required).
@param set the collection of signal informations to signal.
*/
- Sql_cmd_signal(const sp_cond_type *cond,
+ Sql_cmd_signal(const sp_condition_value *cond,
const Set_signal_information& set)
: Sql_cmd_common_signal(cond, set)
{}
@@ -127,7 +127,7 @@ public:
@param cond the SQL condition to resignal (optional, may be NULL).
@param set the collection of signal informations to resignal.
*/
- Sql_cmd_resignal(const sp_cond_type *cond,
+ Sql_cmd_resignal(const sp_condition_value *cond,
const Set_signal_information& set)
: Sql_cmd_common_signal(cond, set)
{}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 6a1e4d745e8..fe361801c35 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -52,7 +52,7 @@ int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
}
-int select_union::send_data(List<Item> &values)
+bool select_union::send_data(List<Item> &values)
{
if (unit->offset_limit_cnt)
{ // using limit offset,count
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 1dd83fa8865..cf853ffaed7 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1829,7 +1829,7 @@ multi_update::~multi_update()
}
-int multi_update::send_data(List<Item> &not_used_values)
+bool multi_update::send_data(List<Item> &not_used_values)
{
TABLE_LIST *cur_table;
DBUG_ENTER("multi_update::send_data");
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 521aed2e04a..ea2c51d0bba 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -284,7 +284,7 @@ void case_stmt_action_case(LEX *lex)
(Instruction 12 in the example)
*/
- lex->spcont->push_label((char *)"", lex->sphead->instructions());
+ lex->spcont->push_label(current_thd, EMPTY_STR, lex->sphead->instructions());
}
/**
@@ -353,7 +353,7 @@ int case_stmt_action_when(LEX *lex, Item *when, bool simple)
*/
return !test(i) ||
- sp->push_backpatch(i, ctx->push_label((char *)"", 0)) ||
+ sp->push_backpatch(i, ctx->push_label(current_thd, EMPTY_STR, 0)) ||
sp->add_cont_backpatch(i) ||
sp->add_instr(i);
}
@@ -469,7 +469,7 @@ set_system_variable(THD *thd, struct sys_var_with_base *tmp,
*/
static bool
-set_local_variable(THD *thd, sp_variable_t *spv, Item *val)
+set_local_variable(THD *thd, sp_variable *spv, Item *val)
{
Item *it;
LEX *lex= thd->lex;
@@ -477,8 +477,8 @@ set_local_variable(THD *thd, sp_variable_t *spv, Item *val)
if (val)
it= val;
- else if (spv->dflt)
- it= spv->dflt;
+ else if (spv->default_value)
+ it= spv->default_value;
else
{
it= new (thd->mem_root) Item_null();
@@ -559,7 +559,7 @@ set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val)
@return An Item_splocal object representing the SP variable, or NULL on error.
*/
static Item_splocal*
-create_item_for_sp_var(THD *thd, LEX_STRING name, sp_variable_t *spvar,
+create_item_for_sp_var(THD *thd, LEX_STRING name, sp_variable *spvar,
const char *start_in_q, const char *end_in_q)
{
Item_splocal *item;
@@ -569,7 +569,7 @@ create_item_for_sp_var(THD *thd, LEX_STRING name, sp_variable_t *spvar,
/* If necessary, look for the variable. */
if (spc && !spvar)
- spvar= spc->find_variable(&name);
+ spvar= spc->find_variable(name, false);
if (!spvar)
{
@@ -931,7 +931,7 @@ static bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
timestamp_type date_time_type;
st_select_lex *select_lex;
chooser_compare_func_creator boolfunc2creator;
- struct sp_cond_type *spcondtype;
+ class sp_condition_value *spcondvalue;
struct { int vars, conds, hndlrs, curs; } spblock;
sp_name *spname;
LEX *lex;
@@ -1857,7 +1857,7 @@ END_OF_INPUT
%type <NONE> case_stmt_specification simple_case_stmt searched_case_stmt
%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list
-%type <spcondtype> sp_cond sp_hcond sqlstate signal_value opt_signal_value
+%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
%type <spblock> sp_decls sp_decl
%type <lex> sp_cursor_stmt
%type <spname> sp_name
@@ -2822,14 +2822,16 @@ sp_fdparam:
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
- if (spc->find_variable(&$1, TRUE))
+ if (spc->find_variable($1, TRUE))
{
my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
MYSQL_YYABORT;
}
- sp_variable_t *spvar= spc->push_variable(&$1,
- (enum enum_field_types)$3,
- sp_param_in);
+
+ sp_variable *spvar= spc->add_variable(YYTHD,
+ $1,
+ (enum enum_field_types) $3,
+ sp_variable::MODE_IN);
if (lex->sphead->fill_field_definition(YYTHD, lex,
(enum enum_field_types) $3,
@@ -2859,14 +2861,15 @@ sp_pdparam:
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
- if (spc->find_variable(&$3, TRUE))
+ if (spc->find_variable($3, TRUE))
{
my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
MYSQL_YYABORT;
}
- sp_variable_t *spvar= spc->push_variable(&$3,
- (enum enum_field_types)$4,
- (sp_param_mode_t)$1);
+ sp_variable *spvar= spc->add_variable(YYTHD,
+ $3,
+ (enum enum_field_types) $4,
+ (sp_variable::enum_mode) $1);
if (lex->sphead->fill_field_definition(YYTHD, lex,
(enum enum_field_types) $4,
@@ -2880,10 +2883,10 @@ sp_pdparam:
;
sp_opt_inout:
- /* Empty */ { $$= sp_param_in; }
- | IN_SYM { $$= sp_param_in; }
- | OUT_SYM { $$= sp_param_out; }
- | INOUT_SYM { $$= sp_param_inout; }
+ /* Empty */ { $$= sp_variable::MODE_IN; }
+ | IN_SYM { $$= sp_variable::MODE_IN; }
+ | OUT_SYM { $$= sp_variable::MODE_OUT; }
+ | INOUT_SYM { $$= sp_variable::MODE_INOUT; }
;
sp_proc_stmts:
@@ -2955,13 +2958,13 @@ sp_decl:
for (uint i = num_vars-$2 ; i < num_vars ; i++)
{
uint var_idx= pctx->var_context2runtime(i);
- sp_variable_t *spvar= pctx->find_variable(var_idx);
+ sp_variable *spvar= pctx->find_variable(var_idx);
if (!spvar)
MYSQL_YYABORT;
spvar->type= var_type;
- spvar->dflt= dflt_value_item;
+ spvar->default_value= dflt_value_item;
if (lex->sphead->fill_field_definition(YYTHD, lex, var_type,
&spvar->field_def))
@@ -2997,36 +3000,41 @@ sp_decl:
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
- if (spc->find_cond(&$2, TRUE))
+ if (spc->find_condition($2, TRUE))
{
my_error(ER_SP_DUP_COND, MYF(0), $2.str);
MYSQL_YYABORT;
}
- if(YYTHD->lex->spcont->push_cond(&$2, $5))
+ if(spc->add_condition(YYTHD, $2, $5))
MYSQL_YYABORT;
$$.vars= $$.hndlrs= $$.curs= 0;
$$.conds= 1;
}
| DECLARE_SYM sp_handler_type HANDLER_SYM FOR_SYM
{
+ THD *thd= YYTHD;
LEX *lex= Lex;
sp_head *sp= lex->sphead;
- lex->spcont= lex->spcont->push_context(LABEL_HANDLER_SCOPE);
+ sp_handler *h= lex->spcont->add_handler(thd,
+ (sp_handler::enum_type) $2);
+
+ lex->spcont= lex->spcont->push_context(thd,
+ sp_pcontext::HANDLER_SCOPE);
sp_pcontext *ctx= lex->spcont;
sp_instr_hpush_jump *i=
- new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
- ctx->current_var_count());
+ new sp_instr_hpush_jump(sp->instructions(), ctx, h);
+
if (i == NULL || sp->add_instr(i))
MYSQL_YYABORT;
/* For continue handlers, mark end of handler scope. */
- if ($2 == SP_HANDLER_CONTINUE &&
+ if ($2 == sp_handler::CONTINUE &&
sp->push_backpatch(i, ctx->last_label()))
MYSQL_YYABORT;
- if (sp->push_backpatch(i, ctx->push_label(empty_c_string, 0)))
+ if (sp->push_backpatch(i, ctx->push_label(thd, EMPTY_STR, 0)))
MYSQL_YYABORT;
}
sp_hcond_list sp_proc_stmt
@@ -3034,20 +3042,19 @@ sp_decl:
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
- sp_label_t *hlab= lex->spcont->pop_label(); /* After this hdlr */
+ sp_label *hlab= lex->spcont->pop_label(); /* After this hdlr */
sp_instr_hreturn *i;
- if ($2 == SP_HANDLER_CONTINUE)
+ if ($2 == sp_handler::CONTINUE)
{
- i= new sp_instr_hreturn(sp->instructions(), ctx,
- ctx->current_var_count());
+ i= new sp_instr_hreturn(sp->instructions(), ctx);
if (i == NULL ||
sp->add_instr(i))
MYSQL_YYABORT;
}
else
{ /* EXIT or UNDO handler, just jump to the end of the block */
- i= new sp_instr_hreturn(sp->instructions(), ctx, 0);
+ i= new sp_instr_hreturn(sp->instructions(), ctx);
if (i == NULL ||
sp->add_instr(i) ||
sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */
@@ -3058,8 +3065,7 @@ sp_decl:
lex->spcont= ctx->pop_context();
$$.vars= $$.conds= $$.curs= 0;
- $$.hndlrs= $6;
- lex->spcont->add_handlers($6);
+ $$.hndlrs= 1;
}
| DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
{
@@ -3069,7 +3075,7 @@ sp_decl:
uint offp;
sp_instr_cpush *i;
- if (ctx->find_cursor(&$2, &offp, TRUE))
+ if (ctx->find_cursor($2, &offp, TRUE))
{
my_error(ER_SP_DUP_CURS, MYF(0), $2.str);
delete $5;
@@ -3079,7 +3085,7 @@ sp_decl:
ctx->current_cursor_count());
if (i == NULL ||
sp->add_instr(i) ||
- ctx->push_cursor(&$2))
+ ctx->add_cursor($2))
MYSQL_YYABORT;
$$.vars= $$.conds= $$.hndlrs= 0;
$$.curs= 1;
@@ -3110,9 +3116,9 @@ sp_cursor_stmt:
;
sp_handler_type:
- EXIT_SYM { $$= SP_HANDLER_EXIT; }
- | CONTINUE_SYM { $$= SP_HANDLER_CONTINUE; }
- /*| UNDO_SYM { QQ No yet } */
+ EXIT_SYM { $$= sp_handler::EXIT; }
+ | CONTINUE_SYM { $$= sp_handler::CONTINUE; }
+ /*| UNDO_SYM { QQ No yet } */
;
sp_hcond_list:
@@ -3129,7 +3135,7 @@ sp_hcond_element:
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont->parent_context();
- if (ctx->find_handler($1))
+ if (ctx->check_duplicate_handler($1))
{
my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
MYSQL_YYABORT;
@@ -3140,7 +3146,6 @@ sp_hcond_element:
(sp_instr_hpush_jump *)sp->last_instruction();
i->add_condition($1);
- ctx->push_handler($1);
}
}
;
@@ -3153,11 +3158,9 @@ sp_cond:
my_error(ER_WRONG_VALUE, MYF(0), "CONDITION", "0");
MYSQL_YYABORT;
}
- $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$= new (YYTHD->mem_root) sp_condition_value($1);
if ($$ == NULL)
MYSQL_YYABORT;
- $$->type= sp_cond_type_t::number;
- $$->mysqlerr= $1;
}
| sqlstate
;
@@ -3165,17 +3168,22 @@ sp_cond:
sqlstate:
SQLSTATE_SYM opt_value TEXT_STRING_literal
{ /* SQLSTATE */
- if (!sp_cond_check(&$3))
+
+ /*
+ An error is triggered:
+ - if the specified string is not a valid SQLSTATE,
+ - or if it represents the completion condition -- it is not
+ allowed to SIGNAL, or declare a handler for the completion
+ condition.
+ */
+ if (!is_sqlstate_valid(&$3) || is_sqlstate_completion($3.str))
{
my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str);
MYSQL_YYABORT;
}
- $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$= new (YYTHD->mem_root) sp_condition_value($3.str);
if ($$ == NULL)
MYSQL_YYABORT;
- $$->type= sp_cond_type_t::state;
- memcpy($$->sqlstate, $3.str, SQLSTATE_LENGTH);
- $$->sqlstate[SQLSTATE_LENGTH]= '\0';
}
;
@@ -3191,7 +3199,7 @@ sp_hcond:
}
| ident /* CONDITION name */
{
- $$= Lex->spcont->find_cond(&$1);
+ $$= Lex->spcont->find_condition($1, false);
if ($$ == NULL)
{
my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
@@ -3200,24 +3208,22 @@ sp_hcond:
}
| SQLWARNING_SYM /* SQLSTATEs 01??? */
{
- $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$= new (YYTHD->mem_root) sp_condition_value(sp_condition_value::WARNING);
if ($$ == NULL)
MYSQL_YYABORT;
- $$->type= sp_cond_type_t::warning;
}
| not FOUND_SYM /* SQLSTATEs 02??? */
{
- $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$= new (YYTHD->mem_root) sp_condition_value(sp_condition_value::NOT_FOUND);
if ($$ == NULL)
MYSQL_YYABORT;
- $$->type= sp_cond_type_t::notfound;
}
| SQLEXCEPTION_SYM /* All other SQLSTATEs */
{
- $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$= (sp_condition_value *)YYTHD->alloc(sizeof(sp_condition_value));
+ $$= new (YYTHD->mem_root) sp_condition_value(sp_condition_value::EXCEPTION);
if ($$ == NULL)
MYSQL_YYABORT;
- $$->type= sp_cond_type_t::exception;
}
;
@@ -3240,20 +3246,20 @@ signal_value:
ident
{
LEX *lex= Lex;
- sp_cond_type_t *cond;
+ sp_condition_value *cond;
if (lex->spcont == NULL)
{
/* SIGNAL foo cannot be used outside of stored programs */
my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
MYSQL_YYABORT;
}
- cond= lex->spcont->find_cond(&$1);
+ cond= lex->spcont->find_condition($1, false);
if (cond == NULL)
{
my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
MYSQL_YYABORT;
}
- if (cond->type != sp_cond_type_t::state)
+ if (cond->type != sp_condition_value::SQLSTATE)
{
my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0));
MYSQL_YYABORT;
@@ -3530,12 +3536,15 @@ sp_decl_idents:
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
- if (spc->find_variable(&$1, TRUE))
+ if (spc->find_variable($1, TRUE))
{
my_error(ER_SP_DUP_VAR, MYF(0), $1.str);
MYSQL_YYABORT;
}
- spc->push_variable(&$1, (enum_field_types)0, sp_param_in);
+ spc->add_variable(YYTHD,
+ $1,
+ MYSQL_TYPE_DECIMAL,
+ sp_variable::MODE_IN);
$$= 1;
}
| sp_decl_idents ',' ident
@@ -3545,12 +3554,15 @@ sp_decl_idents:
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
- if (spc->find_variable(&$3, TRUE))
+ if (spc->find_variable($3, TRUE))
{
my_error(ER_SP_DUP_VAR, MYF(0), $3.str);
MYSQL_YYABORT;
}
- spc->push_variable(&$3, (enum_field_types)0, sp_param_in);
+ spc->add_variable(YYTHD,
+ $3,
+ MYSQL_TYPE_DECIMAL,
+ sp_variable::MODE_IN);
$$= $1 + 1;
}
;
@@ -3672,7 +3684,9 @@ sp_proc_stmt_unlabeled:
{ /* Unlabeled controls get a secret label. */
LEX *lex= Lex;
- lex->spcont->push_label((char *)"", lex->sphead->instructions());
+ lex->spcont->push_label(YYTHD,
+ EMPTY_STR,
+ lex->sphead->instructions());
}
sp_unlabeled_control
{
@@ -3688,7 +3702,7 @@ sp_proc_stmt_leave:
LEX *lex= Lex;
sp_head *sp = lex->sphead;
sp_pcontext *ctx= lex->spcont;
- sp_label_t *lab= ctx->find_label($2.str);
+ sp_label *lab= ctx->find_label($2);
if (! lab)
{
@@ -3708,7 +3722,7 @@ sp_proc_stmt_leave:
there are no hpop/cpop at the jump destination,
so we should include the block context here for cleanup.
*/
- bool exclusive= (lab->type == SP_LAB_BEGIN);
+ bool exclusive= (lab->type == sp_label::BEGIN);
n= ctx->diff_handlers(lab->ctx, exclusive);
if (n)
@@ -3741,9 +3755,9 @@ sp_proc_stmt_iterate:
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
- sp_label_t *lab= ctx->find_label($2.str);
+ sp_label *lab= ctx->find_label($2);
- if (! lab || lab->type != SP_LAB_ITER)
+ if (! lab || lab->type != sp_label::ITERATION)
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str);
MYSQL_YYABORT;
@@ -3786,7 +3800,7 @@ sp_proc_stmt_open:
uint offset;
sp_instr_copen *i;
- if (! lex->spcont->find_cursor(&$2, &offset))
+ if (! lex->spcont->find_cursor($2, &offset, false))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
MYSQL_YYABORT;
@@ -3806,7 +3820,7 @@ sp_proc_stmt_fetch:
uint offset;
sp_instr_cfetch *i;
- if (! lex->spcont->find_cursor(&$3, &offset))
+ if (! lex->spcont->find_cursor($3, &offset, false))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $3.str);
MYSQL_YYABORT;
@@ -3828,7 +3842,7 @@ sp_proc_stmt_close:
uint offset;
sp_instr_cclose *i;
- if (! lex->spcont->find_cursor(&$2, &offset))
+ if (! lex->spcont->find_cursor($2, &offset, false))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
MYSQL_YYABORT;
@@ -3852,9 +3866,9 @@ sp_fetch_list:
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *spc= lex->spcont;
- sp_variable_t *spv;
+ sp_variable *spv;
- if (!spc || !(spv = spc->find_variable(&$1)))
+ if (!spc || !(spv = spc->find_variable($1, false)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
MYSQL_YYABORT;
@@ -3872,9 +3886,9 @@ sp_fetch_list:
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *spc= lex->spcont;
- sp_variable_t *spv;
+ sp_variable *spv;
- if (!spc || !(spv = spc->find_variable(&$3)))
+ if (!spc || !(spv = spc->find_variable($3, false)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str);
MYSQL_YYABORT;
@@ -3900,7 +3914,7 @@ sp_if:
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
$2, lex);
if (i == NULL ||
- sp->push_backpatch(i, ctx->push_label((char *)"", 0)) ||
+ sp->push_backpatch(i, ctx->push_label(YYTHD, EMPTY_STR, 0)) ||
sp->add_cont_backpatch(i) ||
sp->add_instr(i))
MYSQL_YYABORT;
@@ -3917,7 +3931,7 @@ sp_if:
sp->add_instr(i))
MYSQL_YYABORT;
sp->backpatch(ctx->pop_label());
- sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->push_backpatch(i, ctx->push_label(YYTHD, EMPTY_STR, 0));
}
sp_elseifs
{
@@ -4059,7 +4073,7 @@ sp_labeled_control:
{
LEX *lex= Lex;
sp_pcontext *ctx= lex->spcont;
- sp_label_t *lab= ctx->find_label($1.str);
+ sp_label *lab= ctx->find_label($1);
if (lab)
{
@@ -4068,19 +4082,18 @@ sp_labeled_control:
}
else
{
- lab= lex->spcont->push_label($1.str,
- lex->sphead->instructions());
- lab->type= SP_LAB_ITER;
+ lab= lex->spcont->push_label(YYTHD, $1, lex->sphead->instructions());
+ lab->type= sp_label::ITERATION;
}
}
sp_unlabeled_control sp_opt_label
{
LEX *lex= Lex;
- sp_label_t *lab= lex->spcont->pop_label();
+ sp_label *lab= lex->spcont->pop_label();
if ($5.str)
{
- if (my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
+ if (my_strcasecmp(system_charset_info, $5.str, lab->name.str) != 0)
{
my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
MYSQL_YYABORT;
@@ -4100,7 +4113,7 @@ sp_labeled_block:
{
LEX *lex= Lex;
sp_pcontext *ctx= lex->spcont;
- sp_label_t *lab= ctx->find_label($1.str);
+ sp_label *lab= ctx->find_label($1);
if (lab)
{
@@ -4108,18 +4121,17 @@ sp_labeled_block:
MYSQL_YYABORT;
}
- lab= lex->spcont->push_label($1.str,
- lex->sphead->instructions());
- lab->type= SP_LAB_BEGIN;
+ lab= lex->spcont->push_label(YYTHD, $1, lex->sphead->instructions());
+ lab->type= sp_label::BEGIN;
}
sp_block_content sp_opt_label
{
LEX *lex= Lex;
- sp_label_t *lab= lex->spcont->pop_label();
+ sp_label *lab= lex->spcont->pop_label();
if ($5.str)
{
- if (my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
+ if (my_strcasecmp(system_charset_info, $5.str, lab->name.str) != 0)
{
my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
MYSQL_YYABORT;
@@ -4132,8 +4144,8 @@ sp_unlabeled_block:
{ /* Unlabeled blocks get a secret label. */
LEX *lex= Lex;
uint ip= lex->sphead->instructions();
- sp_label_t *lab= lex->spcont->push_label((char *)"", ip);
- lab->type= SP_LAB_BEGIN;
+ sp_label *lab= lex->spcont->push_label(YYTHD, EMPTY_STR, ip);
+ lab->type= sp_label::BEGIN;
}
sp_block_content
{
@@ -4148,7 +4160,8 @@ sp_block_content:
together. No [[NOT] ATOMIC] yet, and we need to figure out how
make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
LEX *lex= Lex;
- lex->spcont= lex->spcont->push_context(LABEL_DEFAULT_SCOPE);
+ lex->spcont= lex->spcont->push_context(YYTHD,
+ sp_pcontext::REGULAR_SCOPE);
}
sp_decls
sp_proc_stmts
@@ -4184,7 +4197,7 @@ sp_unlabeled_control:
{
LEX *lex= Lex;
uint ip= lex->sphead->instructions();
- sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_label *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
if (i == NULL ||
lex->sphead->add_instr(i))
@@ -4212,7 +4225,7 @@ sp_unlabeled_control:
{
LEX *lex= Lex;
uint ip= lex->sphead->instructions();
- sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_label *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
if (i == NULL ||
lex->sphead->add_instr(i))
@@ -4225,7 +4238,7 @@ sp_unlabeled_control:
{
LEX *lex= Lex;
uint ip= lex->sphead->instructions();
- sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_label *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
$5, lab->ip,
lex);
@@ -11107,9 +11120,9 @@ limit_option:
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= & thd->m_parser_state->m_lip;
- sp_variable_t *spv;
+ sp_variable *spv;
sp_pcontext *spc = lex->spcont;
- if (spc && (spv = spc->find_variable(&$1)))
+ if (spc && (spv = spc->find_variable($1, false)))
{
splocal= new (thd->mem_root)
Item_splocal($1, spv->offset, spv->type,
@@ -11329,9 +11342,9 @@ select_var_ident:
| ident_or_text
{
LEX *lex=Lex;
- sp_variable_t *t;
+ sp_variable *t;
- if (!lex->spcont || !(t=lex->spcont->find_variable(&$1)))
+ if (!lex->spcont || !(t=lex->spcont->find_variable($1, false)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
MYSQL_YYABORT;
@@ -13255,9 +13268,9 @@ simple_ident:
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= YYLIP;
- sp_variable_t *spv;
+ sp_variable *spv;
sp_pcontext *spc = lex->spcont;
- if (spc && (spv = spc->find_variable(&$1)))
+ if (spc && (spv = spc->find_variable($1, false)))
{
/* We're compiling a stored procedure and found a variable */
if (! lex->parsing_options.allows_variable)
@@ -14224,12 +14237,11 @@ option_value_no_option_type:
{
THD *thd= YYTHD;
LEX *lex= Lex;
- LEX_STRING *name= &$1.base_name;
if ($1.var == trg_new_row_fake_var)
{
/* We are in trigger and assigning value to field of new row */
- if (set_trigger_new_row(YYTHD, name, $3))
+ if (set_trigger_new_row(YYTHD, &$1.base_name, $3))
MYSQL_YYABORT;
}
else if ($1.var)
@@ -14241,7 +14253,7 @@ option_value_no_option_type:
else
{
sp_pcontext *spc= lex->spcont;
- sp_variable *spv= spc->find_variable(name, false);
+ sp_variable *spv= spc->find_variable($1.base_name, false);
/* It is a local variable. */
if (set_local_variable(thd, spv, $3))
@@ -14294,7 +14306,7 @@ option_value_no_option_type:
names.str= (char *)"names";
names.length= 5;
- if (spc && spc->find_variable(&names, false))
+ if (spc && spc->find_variable(names, false))
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str);
else
my_parse_error(ER(ER_SYNTAX_ERROR));
@@ -14330,7 +14342,7 @@ option_value_no_option_type:
pw.str= (char *)"password";
pw.length= 8;
- if (spc && spc->find_variable(&pw, false))
+ if (spc && spc->find_variable(pw, false))
{
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
MYSQL_YYABORT;
@@ -14365,10 +14377,10 @@ internal_variable_name:
{
THD *thd= YYTHD;
sp_pcontext *spc= thd->lex->spcont;
- sp_variable_t *spv;
+ sp_variable *spv;
/* Best effort lookup for system variable. */
- if (!spc || !(spv = spc->find_variable(&$1)))
+ if (!spc || !(spv = spc->find_variable($1, false)))
{
struct sys_var_with_base tmp= {NULL, $1};