mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Implemented SP CONDITIONs and HANDLERs, with the extension of handling
MySQL error codes as well. (No UNDO HANDLERs yet, and no SIGNAL or RESIGNAL.) WL#850 Docs/sp-imp-spec.txt: Spec of CONDITIONs and HANDLERs (and updated some old stuff too). Docs/sp-implemented.txt: Updated info about caching, CONDITIONs and HANDLERs. include/mysqld_error.h: New error for undeclared CONDITION. libmysqld/Makefile.am: New file: sp_rcontext.cc. mysql-test/r/sp-error.result: New tests for CONDITIONs and HANDLERs. mysql-test/r/sp.result: New tests for CONDITIONs and HANDLERs. mysql-test/t/sp-error.test: New tests for CONDITIONs and HANDLERs. mysql-test/t/sp.test: New tests for CONDITIONs and HANDLERs. sql/Makefile.am: New file: sp_rcontext.cc. sql/lex.h: New symbols for CONDITIONs, HANDLERs and CURSORs. sql/mysqld.cc: Catch error if we have a handler for it. sql/protocol.cc: Catch error if we have a handler for it. sql/share/czech/errmsg.txt: New error for undeclared CONDITION. sql/share/danish/errmsg.txt: New error for undeclared CONDITION. sql/share/dutch/errmsg.txt: New error for undeclared CONDITION. sql/share/english/errmsg.txt: New error for undeclared CONDITION. sql/share/estonian/errmsg.txt: New error for undeclared CONDITION. sql/share/french/errmsg.txt: New error for undeclared CONDITION. sql/share/german/errmsg.txt: New error for undeclared CONDITION. sql/share/greek/errmsg.txt: New error for undeclared CONDITION. sql/share/hungarian/errmsg.txt: New error for undeclared CONDITION. sql/share/italian/errmsg.txt: New error for undeclared CONDITION. sql/share/japanese/errmsg.txt: New error for undeclared CONDITION. sql/share/korean/errmsg.txt: New error for undeclared CONDITION. sql/share/norwegian-ny/errmsg.txt: New error for undeclared CONDITION. sql/share/norwegian/errmsg.txt: New error for undeclared CONDITION. sql/share/polish/errmsg.txt: New error for undeclared CONDITION. sql/share/portuguese/errmsg.txt: New error for undeclared CONDITION. sql/share/romanian/errmsg.txt: New error for undeclared CONDITION. sql/share/russian/errmsg.txt: New error for undeclared CONDITION. sql/share/serbian/errmsg.txt: New error for undeclared CONDITION. sql/share/slovak/errmsg.txt: New error for undeclared CONDITION. sql/share/spanish/errmsg.txt: New error for undeclared CONDITION. sql/share/swedish/errmsg.txt: New error for undeclared CONDITION. sql/share/ukrainian/errmsg.txt: New error for undeclared CONDITION. sql/sp_head.cc: New HANDLER code. sql/sp_head.h: New HANDLER code. sql/sp_pcontext.cc: New CONDITION and HANDLER code. sql/sp_pcontext.h: New CONDITION and HANDLER code. sql/sp_rcontext.h: New CONDITION and HANDLER code. sql/sql_yacc.yy: New CONDITION and HANDLER code.
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
Implementation specification for Stored Procedures
|
Implementation specification for Stored Procedures
|
||||||
==================================================
|
==================================================
|
||||||
|
|
||||||
|
|
||||||
- How parsing and execution of queries work
|
- How parsing and execution of queries work
|
||||||
@ -45,7 +45,8 @@
|
|||||||
|
|
||||||
- class sp_instr (sp_head.{cc,h})
|
- class sp_instr (sp_head.{cc,h})
|
||||||
This is the base class for "instructions", that is, what is generated
|
This is the base class for "instructions", that is, what is generated
|
||||||
by the parser. It turns out that we only need 4 different sub classes:
|
by the parser. It turns out that we only need a minimum of 5 different
|
||||||
|
sub classes:
|
||||||
- sp_instr_stmt
|
- sp_instr_stmt
|
||||||
Execute a statement. This is the "call-out" any normal SQL statement,
|
Execute a statement. This is the "call-out" any normal SQL statement,
|
||||||
like a SELECT, INSERT etc. It contains the Lex structure for the
|
like a SELECT, INSERT etc. It contains the Lex structure for the
|
||||||
@ -58,6 +59,10 @@
|
|||||||
Jump if condition is not true. It turns out that the negative test is
|
Jump if condition is not true. It turns out that the negative test is
|
||||||
most convenient when generating the code for the flow control
|
most convenient when generating the code for the flow control
|
||||||
constructs.
|
constructs.
|
||||||
|
- sp_instr_freturn
|
||||||
|
Return a value from a FUNCTION and exit.
|
||||||
|
For condition HANDLERs some special instructions are also needed, see
|
||||||
|
that section below.
|
||||||
|
|
||||||
- class sp_rcontext (sp_rcontext.h)
|
- class sp_rcontext (sp_rcontext.h)
|
||||||
This is the runtime context in the THD structure.
|
This is the runtime context in the THD structure.
|
||||||
@ -120,7 +125,7 @@
|
|||||||
with an anonymous variable bound to the value to be tested.
|
with an anonymous variable bound to the value to be tested.
|
||||||
|
|
||||||
|
|
||||||
- An example
|
- A simple example
|
||||||
|
|
||||||
Parsing the procedure:
|
Parsing the procedure:
|
||||||
|
|
||||||
@ -258,8 +263,8 @@
|
|||||||
the actual database name.
|
the actual database name.
|
||||||
- It's possible to write procedures that work on a particular database
|
- It's possible to write procedures that work on a particular database
|
||||||
by calling USE, without having to use fully qualified table names
|
by calling USE, without having to use fully qualified table names
|
||||||
everywhere (which doesn't help if you want to call other, "general",
|
everywhere (which doesn't help if you want to call other, "general",
|
||||||
procedures anyway).
|
procedures anyway).
|
||||||
|
|
||||||
- Evaluating Items
|
- Evaluating Items
|
||||||
|
|
||||||
@ -315,7 +320,7 @@
|
|||||||
This makes things a lot more complicated compared to CALL:
|
This makes things a lot more complicated compared to CALL:
|
||||||
- We can't read and parse the FUNCTION from the mysql.proc table at the
|
- We can't read and parse the FUNCTION from the mysql.proc table at the
|
||||||
point of invokation; the server requires that all tables used are
|
point of invokation; the server requires that all tables used are
|
||||||
opened and locked at the beginning of the query execution.
|
opened and locked at the beginning of the query execution.
|
||||||
One "obvious" solution would be to simply push "mysql.proc" to the list
|
One "obvious" solution would be to simply push "mysql.proc" to the list
|
||||||
of tables used by the query, but this implies a "join" with this table
|
of tables used by the query, but this implies a "join" with this table
|
||||||
if the query is a select, so it doesn't work (and we can't exclude this
|
if the query is a select, so it doesn't work (and we can't exclude this
|
||||||
@ -341,9 +346,9 @@
|
|||||||
handled by the functions
|
handled by the functions
|
||||||
|
|
||||||
void sp_add_fun_to_lex(LEX *lex, LEX_STRING fun);
|
void sp_add_fun_to_lex(LEX *lex, LEX_STRING fun);
|
||||||
void sp_merge_funs(LEX *dst, LEX *src);
|
void sp_merge_funs(LEX *dst, LEX *src);
|
||||||
int sp_cache_functions(THD *thd, LEX *lex);
|
int sp_cache_functions(THD *thd, LEX *lex);
|
||||||
void sp_clear_function_cache(THD *thd);
|
void sp_clear_function_cache(THD *thd);
|
||||||
|
|
||||||
in sp.cc.
|
in sp.cc.
|
||||||
|
|
||||||
@ -361,82 +366,231 @@
|
|||||||
analogous to other DROP statements in MySQL.
|
analogous to other DROP statements in MySQL.
|
||||||
|
|
||||||
|
|
||||||
|
- Condition and Handlers
|
||||||
|
|
||||||
|
Condition names are lexical entities and are kept in the parser context
|
||||||
|
just like variables. But, condition are just "aliases" for SQLSTATE
|
||||||
|
strings, or mysqld error codes (which is a non-standard extension in
|
||||||
|
MySQL), and are only used during parsing.
|
||||||
|
|
||||||
|
Handlers comes in three types, CONTINUE, EXIT and UNDO. The latter is
|
||||||
|
like an EXIT handler with an implicit rollback, and is currently not
|
||||||
|
implemented.
|
||||||
|
The EXIT handler jumps to the end of its BEGIN-END block when finished.
|
||||||
|
The CONTINUE handler returns to the statement following that which
|
||||||
|
invoked the handler.
|
||||||
|
|
||||||
|
The handlers in effect at any point is part of each thread's runtime
|
||||||
|
state, so we need to push and pop handlers in the sp_rcontext during
|
||||||
|
execution. We use special instructions for this:
|
||||||
|
- sp_instr_hpush_jump
|
||||||
|
Push a handler. The instruction contains the necessary information,
|
||||||
|
like which conditions we handle and the location of the handler.
|
||||||
|
The jump takes us to the location after the handler code.
|
||||||
|
- sp_instr_hpop
|
||||||
|
Pop the handlers of the current frame (which we are just leaving).
|
||||||
|
|
||||||
|
It might seems strange to jump past the handlers like that, but there's
|
||||||
|
no extra cost in doing this, and for technical reasons it's easiest for
|
||||||
|
the parser to generate the handler instructions when they occur in the
|
||||||
|
source.
|
||||||
|
|
||||||
|
When an error occurs, one of the error routines is called and an error
|
||||||
|
message is normally sent back to the client immediately.
|
||||||
|
Catching a condition must be done in these error routines (there are
|
||||||
|
quite a few) to prevent them from doing this. We do this by calling
|
||||||
|
a method in the THD's sp_rcontext (if there is one). If a handler is
|
||||||
|
found, this is recorded in the context and the routine returns without
|
||||||
|
sending the error message.
|
||||||
|
The exectution loop (sp_head::execute()) checks for this after each
|
||||||
|
statement and invokes the handler that has been found. If several
|
||||||
|
errors or warnings occurs during one statement, only the first is
|
||||||
|
caught, the rest are ignored.
|
||||||
|
|
||||||
|
Invoking and returning from a handler is trivial in the EXIT case.
|
||||||
|
We simply jump to it, and it will have an sp_instr_jump as its last
|
||||||
|
instruction.
|
||||||
|
|
||||||
|
Calling and returning from a CONTINUE handler poses some special
|
||||||
|
problems. Since we need to return to the point after its invokation,
|
||||||
|
we push the return location on a stack in the sp_rcontext (this is
|
||||||
|
done by the exectution loop). The handler then ends with a special
|
||||||
|
instruction, sp_instr_hreturn, which returns to this location.
|
||||||
|
|
||||||
|
CONTINUE handlers have one additional problem: They are parsed at
|
||||||
|
the lexical level where they occur, so variable offsets will assume
|
||||||
|
that it's actually called at that level. However, a handler might be
|
||||||
|
invoked from a sub-block where additional local variables have been
|
||||||
|
declared, which will then share the location of any local variables
|
||||||
|
in the handler itself. So, when calling a CONTINUE handler, we need
|
||||||
|
to save any local variables above the handler's frame offset, and
|
||||||
|
restore them upon return. (This is not a problem for EXIT handlers,
|
||||||
|
since they will leave the block anyway.)
|
||||||
|
This is taken care of by the execution loop and the sp_instr_hreturn
|
||||||
|
instruction.
|
||||||
|
|
||||||
|
- Examples:
|
||||||
|
|
||||||
|
- EXIT handler
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
|
||||||
|
begin
|
||||||
|
declare exit handler for 'XXXXX' set x = 1;
|
||||||
|
|
||||||
|
(statement1);
|
||||||
|
(statement2);
|
||||||
|
end;
|
||||||
|
(statement3);
|
||||||
|
end
|
||||||
|
|
||||||
|
Pos. Instruction
|
||||||
|
0 sp_instr_set(0, '0')
|
||||||
|
1 sp_instr_hpush_jump(4, 1) # location and frame size
|
||||||
|
2 sp_instr_set(0, '1')
|
||||||
|
3 sp_instr_jump(6)
|
||||||
|
4 sp_instr_stmt('statement1')
|
||||||
|
5 sp_instr_stmt('statement2')
|
||||||
|
6 sp_instr_hpop(1)
|
||||||
|
7 sp_instr_stmt('statement3')
|
||||||
|
|
||||||
|
- CONTINUE handler
|
||||||
|
create procedure hndlr1(val int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare foo condition for 1146;
|
||||||
|
declare continue handler for foo set x = 1;
|
||||||
|
|
||||||
|
insert into t3 values ("hndlr1", val); # Non-existing table?
|
||||||
|
if x>0 then
|
||||||
|
insert into t1 values ("hndlr1", val); # This instead then
|
||||||
|
end if;
|
||||||
|
end|
|
||||||
|
|
||||||
|
Pos. Instruction
|
||||||
|
0 sp_instr_set(1, '0')
|
||||||
|
1 sp_instr_hpush_jump(4, 2)
|
||||||
|
2 sp_instr_set(1, '1')
|
||||||
|
3 sp_instr_hreturn(2) # frame size
|
||||||
|
4 sp_instr_stmt('insert ... t3 ...')
|
||||||
|
5 sp_instr_jump_if_not(7, 'x>0')
|
||||||
|
6 sp_instr_stmt('insert ... t1 ...')
|
||||||
|
7 sp_instr_hpop(2)
|
||||||
|
|
||||||
|
|
||||||
- Class and function APIs
|
- Class and function APIs
|
||||||
|
This is an outline of the key types. Some types and other details
|
||||||
|
in the actual files have been omitted for readability.
|
||||||
|
|
||||||
- The parser context: sp_pcontext.h
|
- The parser context: sp_pcontext.h
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
sp_param_in,
|
sp_param_in,
|
||||||
sp_param_out,
|
sp_param_out,
|
||||||
sp_param_inout
|
sp_param_inout
|
||||||
} sp_param_mode_t;
|
} sp_param_mode_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Item_string *name;
|
LEX_STRING name;
|
||||||
enum enum_field_types type;
|
enum enum_field_types type;
|
||||||
sp_param_mode_t mode;
|
sp_param_mode_t mode;
|
||||||
uint offset; // Offset in current frame
|
uint offset; // Offset in current frame
|
||||||
my_bool isset;
|
my_bool isset;
|
||||||
} sp_pvar_t;
|
} sp_pvar_t;
|
||||||
|
|
||||||
|
typedef struct sp_cond_type
|
||||||
|
{
|
||||||
|
enum { number, state, warning, notfound, exception } type;
|
||||||
|
char sqlstate[6];
|
||||||
|
uint mysqlerr;
|
||||||
|
} sp_cond_type_t;
|
||||||
|
|
||||||
class sp_pcontext
|
class sp_pcontext
|
||||||
{
|
{
|
||||||
sp_pcontext();
|
sp_pcontext();
|
||||||
|
|
||||||
// Return the maximum frame size
|
// Return the maximum frame size
|
||||||
uint max_framesize();
|
uint max_framesize();
|
||||||
|
|
||||||
// Return the current frame size
|
// Return the current frame size
|
||||||
uint current_framesize();
|
uint current_framesize();
|
||||||
|
|
||||||
// Return the number of parameters
|
// Return the number of parameters
|
||||||
uint params();
|
uint params();
|
||||||
|
|
||||||
// Set the number of parameters to the current frame size
|
// Set the number of parameters to the current frame size
|
||||||
void set_params();
|
void set_params();
|
||||||
|
|
||||||
// Set type of the variable at offset 'i' in the frame
|
// Set type of the variable at offset 'i' in the frame
|
||||||
void set_type(uint i, enum enum_field_types type);
|
void set_type(uint i, enum enum_field_types type);
|
||||||
|
|
||||||
// Mark the i:th variable to "set" (i.e. having a value) with
|
// Mark the i:th variable to "set" (i.e. having a value) with
|
||||||
// 'val' true.
|
// 'val' true.
|
||||||
void set_isset(uint i, my_bool val);
|
void set_isset(uint i, my_bool val);
|
||||||
|
|
||||||
// Push the variable 'name' to the frame.
|
// Push the variable 'name' to the frame.
|
||||||
void push(LEX_STRING *name,
|
void push_var(LEX_STRING *name,
|
||||||
enum enum_field_types type, sp_param_mode_t mode);
|
enum enum_field_types type, sp_param_mode_t mode);
|
||||||
|
|
||||||
// Pop 'num' variables from the frame.
|
// Pop 'num' variables from the frame.
|
||||||
void pop(uint num = 1);
|
void pop_var(uint num = 1);
|
||||||
|
|
||||||
// Find variable by name
|
// Find variable by name
|
||||||
sp_pvar_t *find_pvar(LEX_STRING *name);
|
sp_pvar_t *find_pvar(LEX_STRING *name);
|
||||||
|
|
||||||
// Find variable by index
|
// Find variable by index
|
||||||
sp_pvar_t *find_pvar(uint i);
|
sp_pvar_t *find_pvar(uint i);
|
||||||
|
|
||||||
// Push label 'name' of instruction index 'ip' to the label context
|
// Push label 'name' of instruction index 'ip' to the label context
|
||||||
sp_label_t *push_label(char *name, uint ip);
|
sp_label_t *push_label(char *name, uint ip);
|
||||||
|
|
||||||
// Find label 'name' in the context
|
// Find label 'name' in the context
|
||||||
sp_label_t *find_label(char *name);
|
sp_label_t *find_label(char *name);
|
||||||
|
|
||||||
// Return the last pushed label
|
// Return the last pushed label
|
||||||
sp_label_t *last_label();
|
sp_label_t *last_label();
|
||||||
|
|
||||||
// Return and remove the last pushed label.
|
// Return and remove the last pushed label.
|
||||||
sp_label_t *pop_label();
|
sp_label_t *pop_label();
|
||||||
|
|
||||||
|
// Push a condition to the context
|
||||||
|
void push_cond(LEX_STRING *name, sp_cond_type_t *val);
|
||||||
|
|
||||||
|
// Pop a 'num' condition from the context
|
||||||
|
void pop_cond(uint num);
|
||||||
|
|
||||||
|
// Find a condition in the context
|
||||||
|
sp_cond_type_t *find_cond(LEX_STRING *name);
|
||||||
|
|
||||||
|
// Increase the handler count
|
||||||
|
void add_handler();
|
||||||
|
|
||||||
|
// Returns the handler count
|
||||||
|
uint handlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- The run-time context (call frame): sp_rcontext.h
|
- The run-time context (call frame): sp_rcontext.h
|
||||||
|
|
||||||
|
#define SP_HANDLER_NONE 0
|
||||||
|
#define SP_HANDLER_EXIT 1
|
||||||
|
#define SP_HANDLER_CONTINUE 2
|
||||||
|
#define SP_HANDLER_UNDO 3
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct sp_cond_type *cond;
|
||||||
|
uint handler; // Location of handler
|
||||||
|
int type;
|
||||||
|
uint foffset; // Frame offset for the handlers declare level
|
||||||
|
} sp_handler_t;
|
||||||
|
|
||||||
class sp_rcontext
|
class sp_rcontext
|
||||||
{
|
{
|
||||||
// 'size' is the max size of the context
|
// 'fsize' is the max size of the context, 'hmax' the number of handlers
|
||||||
sp_rcontext(uint size);
|
sp_rcontext(uint fsize, uint hmax);
|
||||||
|
|
||||||
// Push value (parameter) 'i' to the frame
|
// Push value (parameter) 'i' to the frame
|
||||||
void push_item(Item *i);
|
void push_item(Item *i);
|
||||||
@ -459,6 +613,38 @@
|
|||||||
|
|
||||||
// Get the FUNCTION result
|
// Get the FUNCTION result
|
||||||
Item *get_result();
|
Item *get_result();
|
||||||
|
|
||||||
|
// Push handler at location 'h' for condition 'cond'. 'f' is the
|
||||||
|
// current variable frame size.
|
||||||
|
void push_handler(sp_cond_type_t *cond, uint h, int type, uint f);
|
||||||
|
|
||||||
|
// Pop 'count' handlers
|
||||||
|
void pop_handlers(uint count);
|
||||||
|
|
||||||
|
// Find a handler for this error. This sets the state for a found
|
||||||
|
// handler in the context. If called repeatedly without clearing,
|
||||||
|
// only the first call's state is kept.
|
||||||
|
int find_handler(uint sql_errno);
|
||||||
|
|
||||||
|
// Returns 1 if a handler has been found, with '*ip' and '*fp' set
|
||||||
|
// to the handler location and frame size respectively.
|
||||||
|
int found_handler(uint *ip, uint *fp);
|
||||||
|
|
||||||
|
// Clear the found handler state.
|
||||||
|
void clear_handler();
|
||||||
|
|
||||||
|
// Push a return address for a CONTINUE handler
|
||||||
|
void push_hstack(uint ip);
|
||||||
|
|
||||||
|
// Pop the CONTINUE handler return stack
|
||||||
|
uint pop_hstack();
|
||||||
|
|
||||||
|
// Save variables from frame index 'fp' and up.
|
||||||
|
void save_variables(uint fp);
|
||||||
|
|
||||||
|
// Restore saved variables from to frame index 'fp' and up.
|
||||||
|
void restore_variables(uint fp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -469,28 +655,33 @@
|
|||||||
|
|
||||||
class sp_head
|
class sp_head
|
||||||
{
|
{
|
||||||
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
|
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
|
||||||
|
|
||||||
sp_head(LEX_STRING *name, LEX*);
|
sp_head();
|
||||||
|
|
||||||
|
void init(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid);
|
||||||
|
|
||||||
// Store this procedure in the database. This is a wrapper around
|
// Store this procedure in the database. This is a wrapper around
|
||||||
// the function sp_create_procedure().
|
// the function sp_create_procedure().
|
||||||
int create(THD *);
|
int create(THD *);
|
||||||
|
|
||||||
// Invoke a FUNCTION
|
// Invoke a FUNCTION
|
||||||
int
|
int
|
||||||
execute_function(THD *thd, Item **args, uint argcount, Item **resp);
|
execute_function(THD *thd, Item **args, uint argcount, Item **resp);
|
||||||
|
|
||||||
// CALL a PROCEDURE
|
// CALL a PROCEDURE
|
||||||
int
|
int
|
||||||
execute_procedure(THD *thd, List<Item> *args);
|
execute_procedure(THD *thd, List<Item> *args);
|
||||||
|
|
||||||
// Add the instruction to this procedure.
|
// Add the instruction to this procedure.
|
||||||
void add_instr(sp_instr *);
|
void add_instr(sp_instr *);
|
||||||
|
|
||||||
// Return the number of instructions.
|
// Returns the number of instructions.
|
||||||
uint instructions();
|
uint instructions();
|
||||||
|
|
||||||
|
// Returns the last instruction
|
||||||
|
sp_instr *last_instruction();
|
||||||
|
|
||||||
// Resets lex in 'thd' and keeps a copy of the old one.
|
// Resets lex in 'thd' and keeps a copy of the old one.
|
||||||
void reset_lex(THD *);
|
void reset_lex(THD *);
|
||||||
|
|
||||||
@ -505,6 +696,17 @@
|
|||||||
// Update all instruction with this label in the backpatch list to
|
// Update all instruction with this label in the backpatch list to
|
||||||
// the current position.
|
// the current position.
|
||||||
void backpatch(struct sp_label *);
|
void backpatch(struct sp_label *);
|
||||||
|
|
||||||
|
// Returns the SP name (with optional length in '*lenp').
|
||||||
|
char *name(uint *lenp = 0);
|
||||||
|
|
||||||
|
// Returns the result type for a function
|
||||||
|
Item_result result();
|
||||||
|
|
||||||
|
// Sets various attributes
|
||||||
|
void sp_set_info(char *creator, uint creatorlen,
|
||||||
|
longlong created, longlong modified,
|
||||||
|
bool suid, char *comment, uint commentlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
- Instructions
|
- Instructions
|
||||||
@ -530,60 +732,89 @@
|
|||||||
|
|
||||||
int execute(THD *, uint *nextp);
|
int execute(THD *, uint *nextp);
|
||||||
|
|
||||||
// Set the statement's Lex
|
// Set the statement's Lex
|
||||||
void set_lex(LEX *);
|
void set_lex(LEX *);
|
||||||
|
|
||||||
// Return the statement's Lex
|
// Return the statement's Lex
|
||||||
LEX *get_lex();
|
LEX *get_lex();
|
||||||
}
|
}
|
||||||
|
|
||||||
- SET instruction:
|
- SET instruction:
|
||||||
class sp_instr_set : public sp_instr
|
class sp_instr_set : public sp_instr
|
||||||
{
|
{
|
||||||
// 'offset' is the variable's frame offset, 'val' the value,
|
// 'offset' is the variable's frame offset, 'val' the value,
|
||||||
// and 'type' the variable type.
|
// and 'type' the variable type.
|
||||||
sp_instr_set(uint ip,
|
sp_instr_set(uint ip,
|
||||||
uint offset, Item *val, enum enum_field_types type);
|
uint offset, Item *val, enum enum_field_types type);
|
||||||
|
|
||||||
int execute(THD *, uint *nextp);
|
int execute(THD *, uint *nextp);
|
||||||
}
|
}
|
||||||
|
|
||||||
- Unconditional jump
|
- Unconditional jump
|
||||||
class sp_instr_jump : public sp_instr
|
class sp_instr_jump : public sp_instr
|
||||||
{
|
{
|
||||||
// No destination, must be set.
|
// No destination, must be set.
|
||||||
sp_instr_jump(uint ip);
|
sp_instr_jump(uint ip);
|
||||||
|
|
||||||
// 'dest' is the destination instruction index.
|
// 'dest' is the destination instruction index.
|
||||||
sp_instr_jump(uint ip, uint dest);
|
sp_instr_jump(uint ip, uint dest);
|
||||||
|
|
||||||
int execute(THD *, uint *nextp);
|
int execute(THD *, uint *nextp);
|
||||||
|
|
||||||
// Set the destination instruction 'dest'.
|
// Set the destination instruction 'dest'.
|
||||||
void set_destination(uint dest);
|
void set_destination(uint dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
- Conditional jump
|
- Conditional jump
|
||||||
class sp_instr_jump_if_not : public sp_instr_jump
|
class sp_instr_jump_if_not : public sp_instr_jump
|
||||||
{
|
{
|
||||||
// Jump if 'i' evaluates to false. Destination not set yet.
|
// Jump if 'i' evaluates to false. Destination not set yet.
|
||||||
sp_instr_jump_if_not(uint ip, Item *i);
|
sp_instr_jump_if_not(uint ip, Item *i);
|
||||||
|
|
||||||
// Jump to 'dest' if 'i' evaluates to false.
|
// Jump to 'dest' if 'i' evaluates to false.
|
||||||
sp_instr_jump_if_not(uint ip, Item *i, uint dest)
|
sp_instr_jump_if_not(uint ip, Item *i, uint dest)
|
||||||
|
|
||||||
int execute(THD *, uint *nextp);
|
int execute(THD *, uint *nextp);
|
||||||
}
|
}
|
||||||
|
|
||||||
- Return a function value
|
- Return a function value
|
||||||
class sp_instr_return : public sp_instr
|
class sp_instr_freturn : public sp_instr
|
||||||
{
|
{
|
||||||
// Return the value 'val'
|
// Return the value 'val'
|
||||||
sp_instr_return(uint ip, Item *val, enum enum_field_types type);
|
sp_instr_freturn(uint ip, Item *val, enum enum_field_types type);
|
||||||
|
|
||||||
int execute(THD *thd, uint *nextp);
|
int execute(THD *thd, uint *nextp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- Push a handler and jump
|
||||||
|
class sp_instr_hpush_jump : public sp_instr_jump
|
||||||
|
{
|
||||||
|
// Push handler of type 'htype', with current frame size 'fp'
|
||||||
|
sp_instr_hpush_jump(uint ip, int htype, uint fp);
|
||||||
|
|
||||||
|
int execute(THD *thd, uint *nextp);
|
||||||
|
|
||||||
|
// Add condition for this handler
|
||||||
|
void add_condition(struct sp_cond_type *cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
- Pops handlers
|
||||||
|
class sp_instr_hpop : public sp_instr
|
||||||
|
{
|
||||||
|
// Pop 'count' handlers
|
||||||
|
sp_instr_hpop(uint ip, uint count);
|
||||||
|
|
||||||
|
int execute(THD *thd, uint *nextp);
|
||||||
|
}
|
||||||
|
|
||||||
|
- Return from a CONTINUE handler
|
||||||
|
class sp_instr_hreturn : public sp_instr
|
||||||
|
{
|
||||||
|
// Return from handler, and restore variables to 'fp'.
|
||||||
|
sp_instr_hreturn(uint ip, uint fp);
|
||||||
|
|
||||||
|
int execute(THD *thd, uint *nextp);
|
||||||
|
}
|
||||||
|
|
||||||
- Utility functions: sp.h
|
- Utility functions: sp.h
|
||||||
|
|
||||||
@ -602,7 +833,8 @@
|
|||||||
// definition string ("create procedure ...").
|
// definition string ("create procedure ...").
|
||||||
int sp_create_procedure(THD *,
|
int sp_create_procedure(THD *,
|
||||||
char *name, uint namelen,
|
char *name, uint namelen,
|
||||||
char *def, uint deflen);
|
char *def, uint deflen,
|
||||||
|
char *comment, uint commentlen, bool suid);
|
||||||
|
|
||||||
// Drop the procedure 'name' from the database.
|
// Drop the procedure 'name' from the database.
|
||||||
int sp_drop_procedure(THD *, char *name, uint namelen);
|
int sp_drop_procedure(THD *, char *name, uint namelen);
|
||||||
@ -614,9 +846,28 @@
|
|||||||
// definition string ("create function ...").
|
// definition string ("create function ...").
|
||||||
int sp_create_function(THD *,
|
int sp_create_function(THD *,
|
||||||
char *name, uint namelen,
|
char *name, uint namelen,
|
||||||
char *def, uint deflen);
|
char *def, uint deflen,
|
||||||
|
char *comment, uint commentlen, bool suid);
|
||||||
|
|
||||||
// Drop the function 'name' from the database.
|
// Drop the function 'name' from the database.
|
||||||
int sp_drop_function(THD *, char *name, uint namelen);
|
int sp_drop_function(THD *, char *name, uint namelen);
|
||||||
|
|
||||||
|
|
||||||
|
- The cache: sp_cache.h
|
||||||
|
|
||||||
|
class sp_cache
|
||||||
|
{
|
||||||
|
sp_cache();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
void insert(sp_head *sp);
|
||||||
|
|
||||||
|
sp_head *lookup(char *name, uint namelen);
|
||||||
|
|
||||||
|
void remove(sp_head *sp);
|
||||||
|
}
|
||||||
|
|
||||||
--
|
--
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Stored Procedures implemented 2003-03-07:
|
Stored Procedures implemented 2003-09-16:
|
||||||
|
|
||||||
|
|
||||||
Summary of Not Yet Implemented:
|
Summary of Not Yet Implemented:
|
||||||
@ -7,13 +7,12 @@ Summary of Not Yet Implemented:
|
|||||||
- External languages
|
- External languages
|
||||||
- Access control
|
- Access control
|
||||||
- Routine characteristics (mostly used for external languages)
|
- Routine characteristics (mostly used for external languages)
|
||||||
- Prepared SP caching; SPs are fetched and reparsed at each call
|
|
||||||
- SQL-99 COMMIT (related to BEGIN/END)
|
- SQL-99 COMMIT (related to BEGIN/END)
|
||||||
- DECLARE CURSOR ...
|
- DECLARE CURSOR ...
|
||||||
- FOR-loops (as it requires cursors)
|
- FOR-loops (as it requires cursors)
|
||||||
- CASCADE/RESTRICT for ALTER and DROP
|
- CASCADE/RESTRICT for ALTER and DROP
|
||||||
- ALTER/DROP METHOD (as it implies User Defined Types)
|
- ALTER/DROP METHOD (as it implies User Defined Types)
|
||||||
- CONDITIONs, HANDLERs, SIGNAL and RESIGNAL (will probably not be implemented)
|
- SIGNAL and RESIGNAL, and UNDO handlers
|
||||||
|
|
||||||
|
|
||||||
Summary of what's implemented:
|
Summary of what's implemented:
|
||||||
@ -24,7 +23,8 @@ Summary of what's implemented:
|
|||||||
- BEGIN/END, SET, CASE, IF, LOOP, WHILE, REPEAT, ITERATE, LEAVE
|
- BEGIN/END, SET, CASE, IF, LOOP, WHILE, REPEAT, ITERATE, LEAVE
|
||||||
- SELECT INTO local variables
|
- SELECT INTO local variables
|
||||||
- "Non-query" FUNCTIONs only
|
- "Non-query" FUNCTIONs only
|
||||||
|
- Prepared SP caching
|
||||||
|
- CONDITIONs and HANDLERs
|
||||||
|
|
||||||
List of what's implemented:
|
List of what's implemented:
|
||||||
|
|
||||||
@ -75,7 +75,17 @@ List of what's implemented:
|
|||||||
query (unlike a PROCEDURE, which is called as a statement). The table
|
query (unlike a PROCEDURE, which is called as a statement). The table
|
||||||
locking scheme used makes it difficult to allow "subqueries" during
|
locking scheme used makes it difficult to allow "subqueries" during
|
||||||
FUNCTION invokation.
|
FUNCTION invokation.
|
||||||
|
- SPs are cached, but with a separate cache for each thread (THD).
|
||||||
|
There are still quite a few non-reentrant constructs in the lexical
|
||||||
|
context which makes sharing prepared SPs impossible. And, even when
|
||||||
|
this is resolved, it's not necessarily the case that it will be faster
|
||||||
|
than a cache per thread. A global cache requires locks, which might
|
||||||
|
become a buttleneck. (It would save memory though.)
|
||||||
|
- CONDITIONs and HANDLERs are implemented, but not the SIGNAL and
|
||||||
|
RESIGNAL statements. (It's unclear if these can be implemented.)
|
||||||
|
The semantics of CONDITIONs is expanded to allow catching MySQL error
|
||||||
|
codes as well. UNDO handlers are not implemented (since we don't have
|
||||||
|
SQL-99 style transaction control yet).
|
||||||
|
|
||||||
Closed questions:
|
Closed questions:
|
||||||
|
|
||||||
|
@ -305,4 +305,5 @@
|
|||||||
#define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1286
|
#define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1286
|
||||||
#define ER_QUERY_INTERRUPTED 1287
|
#define ER_QUERY_INTERRUPTED 1287
|
||||||
#define ER_SP_WRONG_NO_OF_ARGS 1288
|
#define ER_SP_WRONG_NO_OF_ARGS 1288
|
||||||
#define ER_ERROR_MESSAGES 289
|
#define ER_SP_COND_MISMATCH 1289
|
||||||
|
#define ER_ERROR_MESSAGES 290
|
||||||
|
@ -57,7 +57,7 @@ sqlsources = derror.cc field.cc field_conv.cc filesort.cc \
|
|||||||
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
|
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
|
||||||
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
|
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
|
||||||
spatial.cc gstream.cc sql_help.cc \
|
spatial.cc gstream.cc sql_help.cc \
|
||||||
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc
|
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc
|
||||||
|
|
||||||
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
|
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
|
||||||
libmysqld_a_SOURCES=
|
libmysqld_a_SOURCES=
|
||||||
|
@ -96,3 +96,28 @@ select f(1, 2);
|
|||||||
ERROR HY000: Wrong number of arguments for FUNCTION f, expected 1, got 2
|
ERROR HY000: Wrong number of arguments for FUNCTION f, expected 1, got 2
|
||||||
drop procedure p;
|
drop procedure p;
|
||||||
drop function f;
|
drop function f;
|
||||||
|
create procedure p(val int, out res int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare continue handler for foo set x = 1;
|
||||||
|
insert into test.t1 values (val);
|
||||||
|
if (x) then
|
||||||
|
set res = 0;
|
||||||
|
else
|
||||||
|
set res = 1;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
ERROR HY000: Undefined CONDITION: foo
|
||||||
|
create procedure p(val int, out res int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare foo condition for 1146;
|
||||||
|
declare continue handler for bar set x = 1;
|
||||||
|
insert into test.t1 values (val);
|
||||||
|
if (x) then
|
||||||
|
set res = 0;
|
||||||
|
else
|
||||||
|
set res = 1;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
ERROR HY000: Undefined CONDITION: bar
|
||||||
|
@ -443,6 +443,63 @@ drop function inc;
|
|||||||
drop function mul;
|
drop function mul;
|
||||||
drop function append;
|
drop function append;
|
||||||
drop function fun;
|
drop function fun;
|
||||||
|
create procedure hndlr1(val int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare foo condition for 1146;
|
||||||
|
declare continue handler for foo set x = 1;
|
||||||
|
insert into test.t666 values ("hndlr1", val); # Non-existing table
|
||||||
|
if (x) then
|
||||||
|
insert into test.t1 values ("hndlr1", val); # This instead then
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
call hndlr1(42);
|
||||||
|
select * from t1;
|
||||||
|
id data
|
||||||
|
hndlr1 42
|
||||||
|
delete from t1;
|
||||||
|
drop procedure hndlr1;
|
||||||
|
create procedure hndlr2(val int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
begin
|
||||||
|
declare exit handler for '42S02' set x = 1;
|
||||||
|
insert into test.t666 values ("hndlr2", val); # Non-existing table
|
||||||
|
end;
|
||||||
|
insert into test.t1 values ("hndlr2", x);
|
||||||
|
end;
|
||||||
|
call hndlr2(42);
|
||||||
|
select * from t1;
|
||||||
|
id data
|
||||||
|
hndlr2 1
|
||||||
|
delete from t1;
|
||||||
|
drop procedure hndlr2;
|
||||||
|
create procedure hndlr3(val int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare continue handler for sqlexception # Any error
|
||||||
|
begin
|
||||||
|
declare z int;
|
||||||
|
set z = 2 * val;
|
||||||
|
set x = 1;
|
||||||
|
end;
|
||||||
|
if val < 10 then
|
||||||
|
begin
|
||||||
|
declare y int;
|
||||||
|
set y = val + 10;
|
||||||
|
insert into test.t666 values ("hndlr3", y); # Non-existing table
|
||||||
|
if x then
|
||||||
|
insert into test.t1 values ("hndlr3", y);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
call hndlr3(3);
|
||||||
|
select * from t1;
|
||||||
|
id data
|
||||||
|
hndlr3 13
|
||||||
|
delete from t1;
|
||||||
|
drop procedure hndlr3;
|
||||||
drop table if exists fac;
|
drop table if exists fac;
|
||||||
create table fac (n int unsigned not null primary key, f bigint unsigned);
|
create table fac (n int unsigned not null primary key, f bigint unsigned);
|
||||||
create procedure ifac(n int unsigned)
|
create procedure ifac(n int unsigned)
|
||||||
|
@ -142,4 +142,33 @@ select f(1, 2)|
|
|||||||
drop procedure p|
|
drop procedure p|
|
||||||
drop function f|
|
drop function f|
|
||||||
|
|
||||||
|
--error 1289
|
||||||
|
create procedure p(val int, out res int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare continue handler for foo set x = 1;
|
||||||
|
|
||||||
|
insert into test.t1 values (val);
|
||||||
|
if (x) then
|
||||||
|
set res = 0;
|
||||||
|
else
|
||||||
|
set res = 1;
|
||||||
|
end if;
|
||||||
|
end|
|
||||||
|
|
||||||
|
--error 1289
|
||||||
|
create procedure p(val int, out res int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare foo condition for 1146;
|
||||||
|
declare continue handler for bar set x = 1;
|
||||||
|
|
||||||
|
insert into test.t1 values (val);
|
||||||
|
if (x) then
|
||||||
|
set res = 0;
|
||||||
|
else
|
||||||
|
set res = 1;
|
||||||
|
end if;
|
||||||
|
end|
|
||||||
|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
|
@ -519,6 +519,76 @@ drop function append|
|
|||||||
drop function fun|
|
drop function fun|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# CONDITIONs and HANDLERs
|
||||||
|
#
|
||||||
|
|
||||||
|
create procedure hndlr1(val int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare foo condition for 1146;
|
||||||
|
declare continue handler for foo set x = 1;
|
||||||
|
|
||||||
|
insert into test.t666 values ("hndlr1", val); # Non-existing table
|
||||||
|
if (x) then
|
||||||
|
insert into test.t1 values ("hndlr1", val); # This instead then
|
||||||
|
end if;
|
||||||
|
end|
|
||||||
|
|
||||||
|
call hndlr1(42)|
|
||||||
|
select * from t1|
|
||||||
|
delete from t1|
|
||||||
|
drop procedure hndlr1|
|
||||||
|
|
||||||
|
create procedure hndlr2(val int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
|
||||||
|
begin
|
||||||
|
declare exit handler for '42S02' set x = 1;
|
||||||
|
|
||||||
|
insert into test.t666 values ("hndlr2", val); # Non-existing table
|
||||||
|
end;
|
||||||
|
|
||||||
|
insert into test.t1 values ("hndlr2", x);
|
||||||
|
end|
|
||||||
|
|
||||||
|
call hndlr2(42)|
|
||||||
|
select * from t1|
|
||||||
|
delete from t1|
|
||||||
|
drop procedure hndlr2|
|
||||||
|
|
||||||
|
|
||||||
|
create procedure hndlr3(val int)
|
||||||
|
begin
|
||||||
|
declare x int default 0;
|
||||||
|
declare continue handler for sqlexception # Any error
|
||||||
|
begin
|
||||||
|
declare z int;
|
||||||
|
|
||||||
|
set z = 2 * val;
|
||||||
|
set x = 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if val < 10 then
|
||||||
|
begin
|
||||||
|
declare y int;
|
||||||
|
|
||||||
|
set y = val + 10;
|
||||||
|
insert into test.t666 values ("hndlr3", y); # Non-existing table
|
||||||
|
if x then
|
||||||
|
insert into test.t1 values ("hndlr3", y);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end|
|
||||||
|
|
||||||
|
call hndlr3(3)|
|
||||||
|
select * from t1|
|
||||||
|
delete from t1|
|
||||||
|
drop procedure hndlr3|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Some "real" examples
|
# Some "real" examples
|
||||||
#
|
#
|
||||||
|
@ -88,7 +88,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
|||||||
client.c sql_client.cc mini_client_errors.c pack.c\
|
client.c sql_client.cc mini_client_errors.c pack.c\
|
||||||
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
|
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
|
||||||
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
|
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
|
||||||
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc
|
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
|
||||||
|
sp_cache.cc
|
||||||
gen_lex_hash_SOURCES = gen_lex_hash.cc
|
gen_lex_hash_SOURCES = gen_lex_hash.cc
|
||||||
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
||||||
|
|
||||||
|
12
sql/lex.h
12
sql/lex.h
@ -104,8 +104,10 @@ static SYMBOL symbols[] = {
|
|||||||
{ "COMMITTED", SYM(COMMITTED_SYM),0,0},
|
{ "COMMITTED", SYM(COMMITTED_SYM),0,0},
|
||||||
{ "COMPRESSED", SYM(COMPRESSED_SYM),0,0},
|
{ "COMPRESSED", SYM(COMPRESSED_SYM),0,0},
|
||||||
{ "CONCURRENT", SYM(CONCURRENT),0,0},
|
{ "CONCURRENT", SYM(CONCURRENT),0,0},
|
||||||
|
{ "CONDITION", SYM(CONDITION_SYM),0,0},
|
||||||
{ "CONNECTION", SYM(CONNECTION_SYM),0,0},
|
{ "CONNECTION", SYM(CONNECTION_SYM),0,0},
|
||||||
{ "CONSTRAINT", SYM(CONSTRAINT),0,0},
|
{ "CONSTRAINT", SYM(CONSTRAINT),0,0},
|
||||||
|
{ "CONTINUE", SYM(CONTINUE_SYM),0,0},
|
||||||
{ "CREATE", SYM(CREATE),0,0},
|
{ "CREATE", SYM(CREATE),0,0},
|
||||||
{ "CROSS", SYM(CROSS),0,0},
|
{ "CROSS", SYM(CROSS),0,0},
|
||||||
{ "CUBE", SYM(CUBE_SYM),0,0},
|
{ "CUBE", SYM(CUBE_SYM),0,0},
|
||||||
@ -156,10 +158,13 @@ static SYMBOL symbols[] = {
|
|||||||
{ "ENUM", SYM(ENUM),0,0},
|
{ "ENUM", SYM(ENUM),0,0},
|
||||||
{ "EVENTS", SYM(EVENTS_SYM),0,0},
|
{ "EVENTS", SYM(EVENTS_SYM),0,0},
|
||||||
{ "EXECUTE", SYM(EXECUTE_SYM),0,0},
|
{ "EXECUTE", SYM(EXECUTE_SYM),0,0},
|
||||||
{ "EXPLAIN", SYM(DESCRIBE),0,0},
|
|
||||||
{ "EXISTS", SYM(EXISTS),0,0},
|
{ "EXISTS", SYM(EXISTS),0,0},
|
||||||
|
{ "EXIT", SYM(EXIT_SYM),0,0},
|
||||||
|
{ "EXPLAIN", SYM(DESCRIBE),0,0},
|
||||||
{ "EXTENDED", SYM(EXTENDED_SYM),0,0},
|
{ "EXTENDED", SYM(EXTENDED_SYM),0,0},
|
||||||
|
{ "FALSE", SYM(FALSE_SYM),0,0},
|
||||||
{ "FAST", SYM(FAST_SYM),0,0},
|
{ "FAST", SYM(FAST_SYM),0,0},
|
||||||
|
{ "FETCH", SYM(FETCH_SYM),0,0},
|
||||||
{ "FIELDS", SYM(COLUMNS),0,0},
|
{ "FIELDS", SYM(COLUMNS),0,0},
|
||||||
{ "FILE", SYM(FILE_SYM),0,0},
|
{ "FILE", SYM(FILE_SYM),0,0},
|
||||||
{ "FIRST", SYM(FIRST_SYM),0,0},
|
{ "FIRST", SYM(FIRST_SYM),0,0},
|
||||||
@ -168,9 +173,9 @@ static SYMBOL symbols[] = {
|
|||||||
{ "FLOAT4", SYM(FLOAT_SYM),0,0},
|
{ "FLOAT4", SYM(FLOAT_SYM),0,0},
|
||||||
{ "FLOAT8", SYM(DOUBLE_SYM),0,0},
|
{ "FLOAT8", SYM(DOUBLE_SYM),0,0},
|
||||||
{ "FLUSH", SYM(FLUSH_SYM),0,0},
|
{ "FLUSH", SYM(FLUSH_SYM),0,0},
|
||||||
{ "FALSE", SYM(FALSE_SYM),0,0},
|
|
||||||
{ "FOREIGN", SYM(FOREIGN),0,0},
|
{ "FOREIGN", SYM(FOREIGN),0,0},
|
||||||
{ "FORCE", SYM(FORCE_SYM),0,0},
|
{ "FORCE", SYM(FORCE_SYM),0,0},
|
||||||
|
{ "FOUND", SYM(FOUND_SYM),0,0},
|
||||||
{ "RAID_TYPE", SYM(RAID_TYPE),0,0},
|
{ "RAID_TYPE", SYM(RAID_TYPE),0,0},
|
||||||
{ "RAID_CHUNKS", SYM(RAID_CHUNKS),0,0},
|
{ "RAID_CHUNKS", SYM(RAID_CHUNKS),0,0},
|
||||||
{ "RAID_CHUNKSIZE", SYM(RAID_CHUNKSIZE),0,0},
|
{ "RAID_CHUNKSIZE", SYM(RAID_CHUNKSIZE),0,0},
|
||||||
@ -375,6 +380,8 @@ static SYMBOL symbols[] = {
|
|||||||
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
|
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
|
||||||
{ "SPATIAL", SYM(SPATIAL_SYM),0,0},
|
{ "SPATIAL", SYM(SPATIAL_SYM),0,0},
|
||||||
{ "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
|
{ "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
|
||||||
|
{ "SQLEXCEPTION", SYM(SQLEXCEPTION_SYM),0,0},
|
||||||
|
{ "SQLWARNING", SYM(SQLWARNING_SYM),0,0},
|
||||||
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
|
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
|
||||||
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
|
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
|
||||||
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
|
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
|
||||||
@ -412,6 +419,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "TYPE", SYM(TYPE_SYM),0,0},
|
{ "TYPE", SYM(TYPE_SYM),0,0},
|
||||||
{ "TYPES", SYM(TYPES_SYM),0,0},
|
{ "TYPES", SYM(TYPES_SYM),0,0},
|
||||||
{ "UNCOMMITTED", SYM(UNCOMMITTED_SYM),0,0},
|
{ "UNCOMMITTED", SYM(UNCOMMITTED_SYM),0,0},
|
||||||
|
{ "UNDO", SYM(UNDO_SYM),0,0},
|
||||||
{ "UNICODE", SYM(UNICODE_SYM),0,0},
|
{ "UNICODE", SYM(UNICODE_SYM),0,0},
|
||||||
{ "UNION", SYM(UNION_SYM),0,0},
|
{ "UNION", SYM(UNION_SYM),0,0},
|
||||||
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
|
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <thr_alarm.h>
|
#include <thr_alarm.h>
|
||||||
#include <ft_global.h>
|
#include <ft_global.h>
|
||||||
#include <errmsg.h>
|
#include <errmsg.h>
|
||||||
|
#include "sp_rcontext.h"
|
||||||
|
|
||||||
#define mysqld_charset &my_charset_latin1
|
#define mysqld_charset &my_charset_latin1
|
||||||
|
|
||||||
@ -1846,6 +1847,10 @@ extern "C" int my_message_sql(uint error, const char *str,
|
|||||||
DBUG_PRINT("error", ("Message: '%s'", str));
|
DBUG_PRINT("error", ("Message: '%s'", str));
|
||||||
if ((thd= current_thd))
|
if ((thd= current_thd))
|
||||||
{
|
{
|
||||||
|
if (thd->spcont && thd->spcont->find_handler(error))
|
||||||
|
{
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
thd->lex.current_select equel to zero if lex structure is not inited
|
thd->lex.current_select equel to zero if lex structure is not inited
|
||||||
(not query command (COM_QUERY))
|
(not query command (COM_QUERY))
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
|
#include "sp_rcontext.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
@ -60,6 +61,10 @@ void send_error(THD *thd, uint sql_errno, const char *err)
|
|||||||
err ? err : net->last_error[0] ?
|
err ? err : net->last_error[0] ?
|
||||||
net->last_error : "NULL"));
|
net->last_error : "NULL"));
|
||||||
|
|
||||||
|
if (thd->spcont && thd->spcont->find_handler(sql_errno))
|
||||||
|
{
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
|
#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
|
||||||
query_cache_abort(net);
|
query_cache_abort(net);
|
||||||
#endif
|
#endif
|
||||||
@ -139,6 +144,10 @@ void send_error(THD *thd, uint sql_errno, const char *err)
|
|||||||
void send_warning(THD *thd, uint sql_errno, const char *err)
|
void send_warning(THD *thd, uint sql_errno, const char *err)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("send_warning");
|
DBUG_ENTER("send_warning");
|
||||||
|
if (thd->spcont && thd->spcont->find_handler(sql_errno))
|
||||||
|
{
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno,
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno,
|
||||||
err ? err : ER(sql_errno));
|
err ? err : ER(sql_errno));
|
||||||
send_ok(thd);
|
send_ok(thd);
|
||||||
@ -169,6 +178,10 @@ net_printf(THD *thd, uint errcode, ...)
|
|||||||
DBUG_ENTER("net_printf");
|
DBUG_ENTER("net_printf");
|
||||||
DBUG_PRINT("enter",("message: %u",errcode));
|
DBUG_PRINT("enter",("message: %u",errcode));
|
||||||
|
|
||||||
|
if (thd->spcont && thd->spcont->find_handler(errcode))
|
||||||
|
{
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
thd->query_error= 1; // needed to catch query errors during replication
|
thd->query_error= 1; // needed to catch query errors during replication
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
query_cache_abort(net); // Safety
|
query_cache_abort(net); // Safety
|
||||||
|
@ -294,3 +294,4 @@ v/*
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -288,3 +288,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -296,3 +296,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -290,3 +290,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -290,3 +290,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -285,3 +285,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -294,3 +294,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -285,3 +285,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -287,3 +287,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -285,3 +285,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -287,3 +287,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -285,3 +285,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -287,3 +287,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -287,3 +287,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -289,3 +289,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -285,3 +285,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -289,3 +289,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -287,3 +287,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -280,3 +280,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -293,3 +293,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -286,3 +286,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -285,3 +285,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -290,3 +290,4 @@
|
|||||||
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
|
||||||
"Query execution was interrupted"
|
"Query execution was interrupted"
|
||||||
"Wrong number of arguments for %s %s, expected %u, got %u"
|
"Wrong number of arguments for %s %s, expected %u, got %u"
|
||||||
|
"Undefined CONDITION: %s"
|
||||||
|
@ -213,6 +213,7 @@ sp_head::execute(THD *thd)
|
|||||||
DBUG_ENTER("sp_head::execute");
|
DBUG_ENTER("sp_head::execute");
|
||||||
char olddbname[128];
|
char olddbname[128];
|
||||||
char *olddbptr= thd->db;
|
char *olddbptr= thd->db;
|
||||||
|
sp_rcontext *ctx= thd->spcont;
|
||||||
int ret= 0;
|
int ret= 0;
|
||||||
uint ip= 0;
|
uint ip= 0;
|
||||||
|
|
||||||
@ -229,15 +230,38 @@ sp_head::execute(THD *thd)
|
|||||||
olddbname[i]= '\0';
|
olddbname[i]= '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx)
|
||||||
|
ctx->clear_handler();
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
sp_instr *i;
|
sp_instr *i;
|
||||||
|
uint hip; // Handler ip
|
||||||
|
|
||||||
i = get_instr(ip); // Returns NULL when we're done.
|
i = get_instr(ip); // Returns NULL when we're done.
|
||||||
if (i == NULL)
|
if (i == NULL)
|
||||||
break;
|
break;
|
||||||
DBUG_PRINT("execute", ("Instruction %u", ip));
|
DBUG_PRINT("execute", ("Instruction %u", ip));
|
||||||
ret= i->execute(thd, &ip);
|
ret= i->execute(thd, &ip);
|
||||||
|
// Check if an exception has occurred and a handler has been found
|
||||||
|
if (ret && !thd->killed && ctx)
|
||||||
|
{
|
||||||
|
uint hf;
|
||||||
|
|
||||||
|
switch (ctx->found_handler(&hip, &hf))
|
||||||
|
{
|
||||||
|
case SP_HANDLER_NONE:
|
||||||
|
break;
|
||||||
|
case SP_HANDLER_CONTINUE:
|
||||||
|
ctx->save_variables(hf);
|
||||||
|
ctx->push_hstack(ip);
|
||||||
|
// Fall through
|
||||||
|
default:
|
||||||
|
ip= hip;
|
||||||
|
ret= 0;
|
||||||
|
ctx->clear_handler();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
} while (ret == 0 && !thd->killed);
|
} while (ret == 0 && !thd->killed);
|
||||||
|
|
||||||
DBUG_PRINT("info", ("ret=%d killed=%d", ret, thd->killed));
|
DBUG_PRINT("info", ("ret=%d killed=%d", ret, thd->killed));
|
||||||
@ -263,6 +287,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
|
|||||||
DBUG_PRINT("info", ("function %s", m_name.str));
|
DBUG_PRINT("info", ("function %s", m_name.str));
|
||||||
uint csize = m_pcont->max_framesize();
|
uint csize = m_pcont->max_framesize();
|
||||||
uint params = m_pcont->params();
|
uint params = m_pcont->params();
|
||||||
|
uint hmax = m_pcont->handlers();
|
||||||
sp_rcontext *octx = thd->spcont;
|
sp_rcontext *octx = thd->spcont;
|
||||||
sp_rcontext *nctx = NULL;
|
sp_rcontext *nctx = NULL;
|
||||||
uint i;
|
uint i;
|
||||||
@ -278,7 +303,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// QQ Should have some error checking here? (types, etc...)
|
// QQ Should have some error checking here? (types, etc...)
|
||||||
nctx= new sp_rcontext(csize);
|
nctx= new sp_rcontext(csize, hmax);
|
||||||
for (i= 0 ; i < params && i < argcount ; i++)
|
for (i= 0 ; i < params && i < argcount ; i++)
|
||||||
{
|
{
|
||||||
sp_pvar_t *pvar = m_pcont->find_pvar(i);
|
sp_pvar_t *pvar = m_pcont->find_pvar(i);
|
||||||
@ -311,6 +336,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
sp_instr *p;
|
sp_instr *p;
|
||||||
uint csize = m_pcont->max_framesize();
|
uint csize = m_pcont->max_framesize();
|
||||||
uint params = m_pcont->params();
|
uint params = m_pcont->params();
|
||||||
|
uint hmax = m_pcont->handlers();
|
||||||
sp_rcontext *octx = thd->spcont;
|
sp_rcontext *octx = thd->spcont;
|
||||||
sp_rcontext *nctx = NULL;
|
sp_rcontext *nctx = NULL;
|
||||||
my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
|
my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
|
||||||
@ -322,16 +348,16 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csize > 0)
|
if (csize > 0 || hmax > 0)
|
||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
List_iterator_fast<Item> li(*args);
|
List_iterator_fast<Item> li(*args);
|
||||||
Item *it;
|
Item *it;
|
||||||
|
|
||||||
nctx = new sp_rcontext(csize);
|
nctx = new sp_rcontext(csize, hmax);
|
||||||
if (! octx)
|
if (! octx)
|
||||||
{ // Create a temporary old context
|
{ // Create a temporary old context
|
||||||
octx = new sp_rcontext(csize);
|
octx = new sp_rcontext(csize, hmax);
|
||||||
tmp_octx = TRUE;
|
tmp_octx = TRUE;
|
||||||
}
|
}
|
||||||
// QQ: Should do type checking?
|
// QQ: Should do type checking?
|
||||||
@ -633,13 +659,54 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// sp_instr_return
|
// sp_instr_freturn
|
||||||
//
|
//
|
||||||
int
|
int
|
||||||
sp_instr_return::execute(THD *thd, uint *nextp)
|
sp_instr_freturn::execute(THD *thd, uint *nextp)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("sp_instr_return::execute");
|
DBUG_ENTER("sp_instr_freturn::execute");
|
||||||
thd->spcont->set_result(eval_func_item(thd, m_value, m_type));
|
thd->spcont->set_result(eval_func_item(thd, m_value, m_type));
|
||||||
*nextp= UINT_MAX;
|
*nextp= UINT_MAX;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// sp_instr_hpush_jump
|
||||||
|
//
|
||||||
|
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_handler, m_type, m_frame);
|
||||||
|
|
||||||
|
*nextp= m_dest;
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// sp_instr_hpop
|
||||||
|
//
|
||||||
|
int
|
||||||
|
sp_instr_hpop::execute(THD *thd, uint *nextp)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_instr_hpop::execute");
|
||||||
|
thd->spcont->pop_handlers(m_count);
|
||||||
|
*nextp= m_ip+1;
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// sp_instr_hreturn
|
||||||
|
//
|
||||||
|
int
|
||||||
|
sp_instr_hreturn::execute(THD *thd, uint *nextp)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_instr_hreturn::execute");
|
||||||
|
thd->spcont->restore_variables(m_frame);
|
||||||
|
*nextp= thd->spcont->pop_hstack();
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
106
sql/sp_head.h
106
sql/sp_head.h
@ -36,6 +36,8 @@ struct sp_label;
|
|||||||
|
|
||||||
class sp_instr;
|
class sp_instr;
|
||||||
|
|
||||||
|
struct sp_cond_type;
|
||||||
|
|
||||||
class sp_head : public Sql_alloc
|
class sp_head : public Sql_alloc
|
||||||
{
|
{
|
||||||
sp_head(const sp_head &); /* Prevent use of these */
|
sp_head(const sp_head &); /* Prevent use of these */
|
||||||
@ -93,6 +95,15 @@ public:
|
|||||||
return m_instr.elements;
|
return m_instr.elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline sp_instr *
|
||||||
|
last_instruction()
|
||||||
|
{
|
||||||
|
sp_instr *i;
|
||||||
|
|
||||||
|
get_dynamic(&m_instr, (gptr)&i, m_instr.elements-1);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
// Resets lex in 'thd' and keeps a copy of the old one.
|
// Resets lex in 'thd' and keeps a copy of the old one.
|
||||||
void
|
void
|
||||||
reset_lex(THD *thd);
|
reset_lex(THD *thd);
|
||||||
@ -385,18 +396,18 @@ private:
|
|||||||
}; // class sp_instr_jump_if_not : public sp_instr_jump
|
}; // class sp_instr_jump_if_not : public sp_instr_jump
|
||||||
|
|
||||||
|
|
||||||
class sp_instr_return : public sp_instr
|
class sp_instr_freturn : public sp_instr
|
||||||
{
|
{
|
||||||
sp_instr_return(const sp_instr_return &); /* Prevent use of these */
|
sp_instr_freturn(const sp_instr_freturn &); /* Prevent use of these */
|
||||||
void operator=(sp_instr_return &);
|
void operator=(sp_instr_freturn &);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
sp_instr_return(uint ip, Item *val, enum enum_field_types type)
|
sp_instr_freturn(uint ip, Item *val, enum enum_field_types type)
|
||||||
: sp_instr(ip), m_value(val), m_type(type)
|
: sp_instr(ip), m_value(val), m_type(type)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~sp_instr_return()
|
virtual ~sp_instr_freturn()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual int execute(THD *thd, uint *nextp);
|
virtual int execute(THD *thd, uint *nextp);
|
||||||
@ -406,6 +417,89 @@ protected:
|
|||||||
Item *m_value;
|
Item *m_value;
|
||||||
enum enum_field_types m_type;
|
enum enum_field_types m_type;
|
||||||
|
|
||||||
}; // class sp_instr_return : public sp_instr
|
}; // class sp_instr_freturn : public sp_instr
|
||||||
|
|
||||||
|
|
||||||
|
class sp_instr_hpush_jump : public sp_instr_jump
|
||||||
|
{
|
||||||
|
sp_instr_hpush_jump(const sp_instr_hpush_jump &); /* Prevent use of these */
|
||||||
|
void operator=(sp_instr_hpush_jump &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
sp_instr_hpush_jump(uint ip, int htype, uint fp)
|
||||||
|
: sp_instr_jump(ip), m_type(htype), m_frame(fp)
|
||||||
|
{
|
||||||
|
m_handler= ip+1;
|
||||||
|
m_cond.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~sp_instr_hpush_jump()
|
||||||
|
{
|
||||||
|
m_cond.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int execute(THD *thd, uint *nextp);
|
||||||
|
|
||||||
|
inline void add_condition(struct sp_cond_type *cond)
|
||||||
|
{
|
||||||
|
m_cond.push_front(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int m_type; // Handler type
|
||||||
|
uint m_frame;
|
||||||
|
uint m_handler; // Location of handler
|
||||||
|
List<struct sp_cond_type> m_cond;
|
||||||
|
|
||||||
|
}; // class sp_instr_hpush_jump : public sp_instr_jump
|
||||||
|
|
||||||
|
|
||||||
|
class sp_instr_hpop : public sp_instr
|
||||||
|
{
|
||||||
|
sp_instr_hpop(const sp_instr_hpop &); /* Prevent use of these */
|
||||||
|
void operator=(sp_instr_hpop &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
sp_instr_hpop(uint ip, uint count)
|
||||||
|
: sp_instr(ip), m_count(count)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~sp_instr_hpop()
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual int execute(THD *thd, uint *nextp);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint m_count;
|
||||||
|
|
||||||
|
}; // class sp_instr_hpop : public sp_instr
|
||||||
|
|
||||||
|
|
||||||
|
class sp_instr_hreturn : public sp_instr
|
||||||
|
{
|
||||||
|
sp_instr_hreturn(const sp_instr_hreturn &); /* Prevent use of these */
|
||||||
|
void operator=(sp_instr_hreturn &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
sp_instr_hreturn(uint ip, uint fp)
|
||||||
|
: sp_instr(ip), m_frame(fp)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~sp_instr_hreturn()
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual int execute(THD *thd, uint *nextp);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint m_frame;
|
||||||
|
|
||||||
|
}; // class sp_instr_hreturn : public sp_instr
|
||||||
|
|
||||||
|
|
||||||
#endif /* _SP_HEAD_H_ */
|
#endif /* _SP_HEAD_H_ */
|
||||||
|
@ -27,9 +27,10 @@
|
|||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
|
|
||||||
sp_pcontext::sp_pcontext()
|
sp_pcontext::sp_pcontext()
|
||||||
: Sql_alloc(), m_params(0), m_framesize(0), m_genlab(0)
|
: Sql_alloc(), m_params(0), m_framesize(0), m_handlers(0), m_genlab(0)
|
||||||
{
|
{
|
||||||
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
|
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
|
||||||
|
VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8));
|
||||||
m_label.empty();
|
m_label.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ void
|
|||||||
sp_pcontext::destroy()
|
sp_pcontext::destroy()
|
||||||
{
|
{
|
||||||
delete_dynamic(&m_pvar);
|
delete_dynamic(&m_pvar);
|
||||||
|
delete_dynamic(&m_cond);
|
||||||
m_label.empty();
|
m_label.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +57,9 @@ sp_pcontext::find_pvar(LEX_STRING *name)
|
|||||||
|
|
||||||
while (i-- > 0)
|
while (i-- > 0)
|
||||||
{
|
{
|
||||||
sp_pvar_t *p= find_pvar(i);
|
sp_pvar_t *p;
|
||||||
|
|
||||||
|
get_dynamic(&m_pvar, (gptr)&p, i);
|
||||||
if (my_strnncoll(system_charset_info,
|
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)
|
(const uchar *)p->name.str, p->name.length) == 0)
|
||||||
@ -68,8 +71,8 @@ sp_pcontext::find_pvar(LEX_STRING *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sp_pcontext::push(LEX_STRING *name, enum enum_field_types type,
|
sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type,
|
||||||
sp_param_mode_t mode)
|
sp_param_mode_t mode)
|
||||||
{
|
{
|
||||||
sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
|
sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
|
||||||
|
|
||||||
@ -113,3 +116,42 @@ sp_pcontext::find_label(char *name)
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val)
|
||||||
|
{
|
||||||
|
sp_cond_t *p= (sp_cond_t *)sql_alloc(sizeof(sp_cond_t));
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
if (m_cond.elements == m_framesize)
|
||||||
|
m_framesize += 1;
|
||||||
|
p->name.str= name->str;
|
||||||
|
p->name.length= name->length;
|
||||||
|
p->val= val;
|
||||||
|
insert_dynamic(&m_cond, (gptr)&p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See comment for find_pvar() above
|
||||||
|
*/
|
||||||
|
sp_cond_type_t *
|
||||||
|
sp_pcontext::find_cond(LEX_STRING *name)
|
||||||
|
{
|
||||||
|
uint i = m_cond.elements;
|
||||||
|
|
||||||
|
while (i-- > 0)
|
||||||
|
{
|
||||||
|
sp_cond_t *p;
|
||||||
|
|
||||||
|
get_dynamic(&m_cond, (gptr)&p, i);
|
||||||
|
if (my_strnncoll(system_charset_info,
|
||||||
|
(const uchar *)name->str, name->length,
|
||||||
|
(const uchar *)p->name.str, p->name.length) == 0)
|
||||||
|
{
|
||||||
|
return p->val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -44,6 +44,19 @@ typedef struct sp_label
|
|||||||
uint ip; // Instruction index
|
uint ip; // Instruction index
|
||||||
} sp_label_t;
|
} sp_label_t;
|
||||||
|
|
||||||
|
typedef struct sp_cond_type
|
||||||
|
{
|
||||||
|
enum { number, state, warning, notfound, exception } type;
|
||||||
|
char sqlstate[6];
|
||||||
|
uint mysqlerr;
|
||||||
|
} sp_cond_type_t;
|
||||||
|
|
||||||
|
typedef struct sp_cond
|
||||||
|
{
|
||||||
|
LEX_STRING name;
|
||||||
|
sp_cond_type_t *val;
|
||||||
|
} sp_cond_t;
|
||||||
|
|
||||||
class sp_pcontext : public Sql_alloc
|
class sp_pcontext : public Sql_alloc
|
||||||
{
|
{
|
||||||
sp_pcontext(const sp_pcontext &); /* Prevent use of these */
|
sp_pcontext(const sp_pcontext &); /* Prevent use of these */
|
||||||
@ -57,6 +70,10 @@ class sp_pcontext : public Sql_alloc
|
|||||||
void
|
void
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parameters and variables
|
||||||
|
//
|
||||||
|
|
||||||
inline uint
|
inline uint
|
||||||
max_framesize()
|
max_framesize()
|
||||||
{
|
{
|
||||||
@ -101,11 +118,11 @@ class sp_pcontext : public Sql_alloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
push(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
|
push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
|
||||||
|
|
||||||
// Pop the last 'num' slots of the frame
|
// Pop the last 'num' slots of the frame
|
||||||
inline void
|
inline void
|
||||||
pop(uint num = 1)
|
pop_pvar(uint num = 1)
|
||||||
{
|
{
|
||||||
while (num--)
|
while (num--)
|
||||||
pop_dynamic(&m_pvar);
|
pop_dynamic(&m_pvar);
|
||||||
@ -128,6 +145,10 @@ class sp_pcontext : public Sql_alloc
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Labels
|
||||||
|
//
|
||||||
|
|
||||||
sp_label_t *
|
sp_label_t *
|
||||||
push_label(char *name, uint ip);
|
push_label(char *name, uint ip);
|
||||||
|
|
||||||
@ -146,12 +167,47 @@ class sp_pcontext : public Sql_alloc
|
|||||||
return m_label.pop();
|
return m_label.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Conditions
|
||||||
|
//
|
||||||
|
|
||||||
|
void
|
||||||
|
push_cond(LEX_STRING *name, sp_cond_type_t *val);
|
||||||
|
|
||||||
|
inline void
|
||||||
|
pop_cond(uint num)
|
||||||
|
{
|
||||||
|
while (num--)
|
||||||
|
pop_dynamic(&m_cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
sp_cond_type_t *
|
||||||
|
find_cond(LEX_STRING *name);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handlers
|
||||||
|
//
|
||||||
|
|
||||||
|
inline void
|
||||||
|
add_handler()
|
||||||
|
{
|
||||||
|
m_handlers+= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint
|
||||||
|
handlers()
|
||||||
|
{
|
||||||
|
return m_handlers;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint m_params; // The number of parameters
|
uint m_params; // The number of parameters
|
||||||
uint m_framesize; // The maximum framesize
|
uint m_framesize; // The maximum framesize
|
||||||
|
uint m_handlers; // The total number of handlers
|
||||||
|
|
||||||
DYNAMIC_ARRAY m_pvar;
|
DYNAMIC_ARRAY m_pvar; // Parameters/variables
|
||||||
|
DYNAMIC_ARRAY m_cond; // Conditions
|
||||||
|
|
||||||
List<sp_label_t> m_label; // The label list
|
List<sp_label_t> m_label; // The label list
|
||||||
uint m_genlab; // Gen. label counter
|
uint m_genlab; // Gen. label counter
|
||||||
|
95
sql/sp_rcontext.cc
Normal file
95
sql/sp_rcontext.cc
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/* Copyright (C) 2002 MySQL AB
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma implementation
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(__WIN__)
|
||||||
|
#undef SAFEMALLOC /* Problems with threads */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mysql_priv.h"
|
||||||
|
#include "sp_rcontext.h"
|
||||||
|
#include "sp_pcontext.h"
|
||||||
|
|
||||||
|
sp_rcontext::sp_rcontext(uint fsize, uint hmax)
|
||||||
|
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0)
|
||||||
|
{
|
||||||
|
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
|
||||||
|
m_outs= (int *)sql_alloc(fsize * sizeof(int));
|
||||||
|
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
|
||||||
|
m_hstack= (uint *)sql_alloc(hmax * sizeof(uint));
|
||||||
|
m_saved.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sp_rcontext::find_handler(uint sql_errno)
|
||||||
|
{
|
||||||
|
if (m_hfound >= 0)
|
||||||
|
return 1; // Already got one
|
||||||
|
|
||||||
|
const char *sqlstate= mysql_errno_to_sqlstate(sql_errno);
|
||||||
|
int i= m_hcount, found= 0;
|
||||||
|
|
||||||
|
while (!found && i--)
|
||||||
|
{
|
||||||
|
sp_cond_type_t *cond= m_handler[i].cond;
|
||||||
|
|
||||||
|
switch (cond->type)
|
||||||
|
{
|
||||||
|
case sp_cond_type_t::number:
|
||||||
|
if (sql_errno == cond->mysqlerr)
|
||||||
|
found= 1;
|
||||||
|
break;
|
||||||
|
case sp_cond_type_t::state:
|
||||||
|
if (strcmp(sqlstate, cond->sqlstate) == 0)
|
||||||
|
found= 1;
|
||||||
|
break;
|
||||||
|
case sp_cond_type_t::warning:
|
||||||
|
if (sqlstate[0] == '0' && sqlstate[0] == '1')
|
||||||
|
found= 1;
|
||||||
|
break;
|
||||||
|
case sp_cond_type_t::notfound:
|
||||||
|
if (sqlstate[0] == '0' && sqlstate[0] == '2')
|
||||||
|
found= 1;
|
||||||
|
break;
|
||||||
|
case sp_cond_type_t::exception:
|
||||||
|
if (sqlstate[0] != '0' || sqlstate[0] > '2')
|
||||||
|
found= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
m_hfound= i;
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_rcontext::save_variables(uint fp)
|
||||||
|
{
|
||||||
|
while (fp < m_count)
|
||||||
|
m_saved.push_front(m_frame[fp++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_rcontext::restore_variables(uint fp)
|
||||||
|
{
|
||||||
|
uint i= m_count;
|
||||||
|
|
||||||
|
while (i-- > fp)
|
||||||
|
m_frame[i]= m_saved.pop();
|
||||||
|
}
|
@ -18,6 +18,25 @@
|
|||||||
#ifndef _SP_RCONTEXT_H_
|
#ifndef _SP_RCONTEXT_H_
|
||||||
#define _SP_RCONTEXT_H_
|
#define _SP_RCONTEXT_H_
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma interface /* gcc class implementation */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct sp_cond_type;
|
||||||
|
|
||||||
|
#define SP_HANDLER_NONE 0
|
||||||
|
#define SP_HANDLER_EXIT 1
|
||||||
|
#define SP_HANDLER_CONTINUE 2
|
||||||
|
#define SP_HANDLER_UNDO 3
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct sp_cond_type *cond;
|
||||||
|
uint handler; // Location of handler
|
||||||
|
int type;
|
||||||
|
uint foffset; // Frame offset for the handlers declare level
|
||||||
|
} sp_handler_t;
|
||||||
|
|
||||||
class sp_rcontext : public Sql_alloc
|
class sp_rcontext : public Sql_alloc
|
||||||
{
|
{
|
||||||
sp_rcontext(const sp_rcontext &); /* Prevent use of these */
|
sp_rcontext(const sp_rcontext &); /* Prevent use of these */
|
||||||
@ -25,23 +44,19 @@ class sp_rcontext : public Sql_alloc
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
sp_rcontext(uint size)
|
sp_rcontext(uint fsize, uint hmax);
|
||||||
: m_count(0), m_size(size), m_result(NULL)
|
|
||||||
{
|
|
||||||
m_frame = (Item **)sql_alloc(size * sizeof(Item*));
|
|
||||||
m_outs = (int *)sql_alloc(size * sizeof(int));
|
|
||||||
}
|
|
||||||
|
|
||||||
~sp_rcontext()
|
~sp_rcontext()
|
||||||
{
|
{
|
||||||
// Not needed?
|
// Not needed?
|
||||||
//sql_element_free(m_frame);
|
//sql_element_free(m_frame);
|
||||||
|
//m_saved.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
push_item(Item *i)
|
push_item(Item *i)
|
||||||
{
|
{
|
||||||
if (m_count < m_size)
|
if (m_count < m_fsize)
|
||||||
m_frame[m_count++] = i;
|
m_frame[m_count++] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,13 +97,79 @@ class sp_rcontext : public Sql_alloc
|
|||||||
return m_result;
|
return m_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
push_handler(struct sp_cond_type *cond, uint h, int type, uint f)
|
||||||
|
{
|
||||||
|
m_handler[m_hcount].cond= cond;
|
||||||
|
m_handler[m_hcount].handler= h;
|
||||||
|
m_handler[m_hcount].type= type;
|
||||||
|
m_handler[m_hcount].foffset= f;
|
||||||
|
m_hcount+= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
pop_handlers(uint count)
|
||||||
|
{
|
||||||
|
m_hcount-= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 1 if a handler was found, 0 otherwise.
|
||||||
|
int
|
||||||
|
find_handler(uint sql_errno);
|
||||||
|
|
||||||
|
// Returns handler type and sets *ip to location if one was found
|
||||||
|
inline int
|
||||||
|
found_handler(uint *ip, uint *fp)
|
||||||
|
{
|
||||||
|
if (m_hfound < 0)
|
||||||
|
return SP_HANDLER_NONE;
|
||||||
|
*ip= m_handler[m_hfound].handler;
|
||||||
|
*fp= m_handler[m_hfound].foffset;
|
||||||
|
return m_handler[m_hfound].type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears the handler find state
|
||||||
|
inline void
|
||||||
|
clear_handler()
|
||||||
|
{
|
||||||
|
m_hfound= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
push_hstack(uint h)
|
||||||
|
{
|
||||||
|
m_hstack[m_hsp++]= h;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint
|
||||||
|
pop_hstack()
|
||||||
|
{
|
||||||
|
return m_hstack[--m_hsp];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save variables starting at fp and up
|
||||||
|
void
|
||||||
|
save_variables(uint fp);
|
||||||
|
|
||||||
|
// Restore variables down to fp
|
||||||
|
void
|
||||||
|
restore_variables(uint fp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint m_count;
|
uint m_count;
|
||||||
uint m_size;
|
uint m_fsize;
|
||||||
Item **m_frame;
|
Item **m_frame;
|
||||||
int *m_outs;
|
int *m_outs;
|
||||||
Item *m_result; // For FUNCTIONs
|
Item *m_result; // For FUNCTIONs
|
||||||
|
sp_handler_t *m_handler;
|
||||||
|
uint m_hcount;
|
||||||
|
uint *m_hstack;
|
||||||
|
uint m_hsp;
|
||||||
|
|
||||||
|
int m_hfound; // Set by find_handler; -1 if not found
|
||||||
|
|
||||||
|
List<Item> m_saved; // Saved variables
|
||||||
|
|
||||||
}; // class sp_rcontext : public Sql_alloc
|
}; // class sp_rcontext : public Sql_alloc
|
||||||
|
|
||||||
|
194
sql/sql_yacc.yy
194
sql/sql_yacc.yy
@ -37,6 +37,7 @@
|
|||||||
#include "item_create.h"
|
#include "item_create.h"
|
||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
#include "sp_pcontext.h"
|
#include "sp_pcontext.h"
|
||||||
|
#include "sp_rcontext.h"
|
||||||
#include "sp.h"
|
#include "sp.h"
|
||||||
#include <myisam.h>
|
#include <myisam.h>
|
||||||
#include <myisammrg.h>
|
#include <myisammrg.h>
|
||||||
@ -84,6 +85,8 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B)
|
|||||||
interval_type interval;
|
interval_type interval;
|
||||||
st_select_lex *select_lex;
|
st_select_lex *select_lex;
|
||||||
chooser_compare_func_creator boolfunc2creator;
|
chooser_compare_func_creator boolfunc2creator;
|
||||||
|
struct sp_cond_type *spcondtype;
|
||||||
|
struct { int vars, conds, hndlrs; } spblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
%{
|
%{
|
||||||
@ -204,8 +207,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token COLUMNS
|
%token COLUMNS
|
||||||
%token COLUMN_SYM
|
%token COLUMN_SYM
|
||||||
%token CONCURRENT
|
%token CONCURRENT
|
||||||
|
%token CONDITION_SYM
|
||||||
%token CONNECTION_SYM
|
%token CONNECTION_SYM
|
||||||
%token CONSTRAINT
|
%token CONSTRAINT
|
||||||
|
%token CONTINUE_SYM
|
||||||
%token CONVERT_SYM
|
%token CONVERT_SYM
|
||||||
%token DATABASES
|
%token DATABASES
|
||||||
%token DATA_SYM
|
%token DATA_SYM
|
||||||
@ -226,14 +231,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token DIRECTORY_SYM
|
%token DIRECTORY_SYM
|
||||||
%token ESCAPE_SYM
|
%token ESCAPE_SYM
|
||||||
%token EXISTS
|
%token EXISTS
|
||||||
|
%token EXIT_SYM
|
||||||
%token EXTENDED_SYM
|
%token EXTENDED_SYM
|
||||||
%token FALSE_SYM
|
%token FALSE_SYM
|
||||||
|
%token FETCH_SYM
|
||||||
%token FILE_SYM
|
%token FILE_SYM
|
||||||
%token FIRST_SYM
|
%token FIRST_SYM
|
||||||
%token FIXED_SYM
|
%token FIXED_SYM
|
||||||
%token FLOAT_NUM
|
%token FLOAT_NUM
|
||||||
%token FORCE_SYM
|
%token FORCE_SYM
|
||||||
%token FOREIGN
|
%token FOREIGN
|
||||||
|
%token FOUND_SYM
|
||||||
%token FROM
|
%token FROM
|
||||||
%token FULL
|
%token FULL
|
||||||
%token FULLTEXT_SYM
|
%token FULLTEXT_SYM
|
||||||
@ -356,6 +364,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token SHUTDOWN
|
%token SHUTDOWN
|
||||||
%token SPATIAL_SYM
|
%token SPATIAL_SYM
|
||||||
%token SPECIFIC_SYM
|
%token SPECIFIC_SYM
|
||||||
|
%token SQLEXCEPTION_SYM
|
||||||
|
%token SQLWARNING_SYM
|
||||||
%token SSL_SYM
|
%token SSL_SYM
|
||||||
%token STARTING
|
%token STARTING
|
||||||
%token STATUS_SYM
|
%token STATUS_SYM
|
||||||
@ -382,6 +392,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token FUNCTION_SYM
|
%token FUNCTION_SYM
|
||||||
%token UNCOMMITTED_SYM
|
%token UNCOMMITTED_SYM
|
||||||
%token UNDERSCORE_CHARSET
|
%token UNDERSCORE_CHARSET
|
||||||
|
%token UNDO_SYM
|
||||||
%token UNICODE_SYM
|
%token UNICODE_SYM
|
||||||
%token UNION_SYM
|
%token UNION_SYM
|
||||||
%token UNIQUE_SYM
|
%token UNIQUE_SYM
|
||||||
@ -725,7 +736,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
END_OF_INPUT
|
END_OF_INPUT
|
||||||
|
|
||||||
%type <NONE> call sp_proc_stmts sp_proc_stmt
|
%type <NONE> call sp_proc_stmts sp_proc_stmt
|
||||||
%type <num> sp_decls sp_decl sp_decl_idents sp_opt_inout
|
%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list
|
||||||
|
%type <spcondtype> sp_cond sp_hcond
|
||||||
|
%type <spblock> sp_decls sp_decl
|
||||||
|
|
||||||
%type <NONE>
|
%type <NONE>
|
||||||
'-' '+' '*' '/' '%' '(' ')'
|
'-' '+' '*' '/' '%' '(' ')'
|
||||||
@ -1096,7 +1109,7 @@ sp_fdparams:
|
|||||||
sp_fdparam:
|
sp_fdparam:
|
||||||
ident type sp_opt_locator
|
ident type sp_opt_locator
|
||||||
{
|
{
|
||||||
Lex->spcont->push(&$1, (enum enum_field_types)$2, sp_param_in);
|
Lex->spcont->push_pvar(&$1, (enum enum_field_types)$2, sp_param_in);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -1114,9 +1127,9 @@ sp_pdparams:
|
|||||||
sp_pdparam:
|
sp_pdparam:
|
||||||
sp_opt_inout ident type sp_opt_locator
|
sp_opt_inout ident type sp_opt_locator
|
||||||
{
|
{
|
||||||
Lex->spcont->push(&$2,
|
Lex->spcont->push_pvar(&$2,
|
||||||
(enum enum_field_types)$3,
|
(enum enum_field_types)$3,
|
||||||
(sp_param_mode_t)$1);
|
(sp_param_mode_t)$1);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -1140,11 +1153,13 @@ sp_proc_stmts:
|
|||||||
sp_decls:
|
sp_decls:
|
||||||
/* Empty */
|
/* Empty */
|
||||||
{
|
{
|
||||||
$$= 0;
|
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||||
}
|
}
|
||||||
| sp_decls sp_decl ';'
|
| sp_decls sp_decl ';'
|
||||||
{
|
{
|
||||||
$$= $1 + $2;
|
$$.vars= $1.vars + $2.vars;
|
||||||
|
$$.conds= $1.conds + $2.conds;
|
||||||
|
$$.hndlrs= $1.hndlrs + $2.hndlrs;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -1170,19 +1185,141 @@ sp_decl:
|
|||||||
lex->spcont->set_isset(i, TRUE);
|
lex->spcont->set_isset(i, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$$= $2;
|
$$.vars= $2;
|
||||||
|
$$.conds= $$.hndlrs= 0;
|
||||||
|
}
|
||||||
|
| DECLARE_SYM ident CONDITION_SYM FOR_SYM sp_cond
|
||||||
|
{
|
||||||
|
YYTHD->lex->spcont->push_cond(&$2, $5);
|
||||||
|
$$.vars= $$.hndlrs= 0;
|
||||||
|
$$.conds= 1;
|
||||||
|
}
|
||||||
|
| DECLARE_SYM sp_handler_type HANDLER_SYM FOR_SYM
|
||||||
|
{
|
||||||
|
LEX *lex= Lex;
|
||||||
|
sp_head *sp= lex->sphead;
|
||||||
|
sp_pcontext *ctx= lex->spcont;
|
||||||
|
sp_instr_hpush_jump *i=
|
||||||
|
new sp_instr_hpush_jump(sp->instructions(), $2,
|
||||||
|
ctx->current_framesize());
|
||||||
|
|
||||||
|
sp->add_instr(i);
|
||||||
|
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||||||
|
ctx->add_handler();
|
||||||
|
}
|
||||||
|
sp_hcond_list sp_proc_stmt
|
||||||
|
{
|
||||||
|
LEX *lex= Lex;
|
||||||
|
sp_head *sp= lex->sphead;
|
||||||
|
sp_label_t *hlab= lex->spcont->pop_label(); /* After this hdlr */
|
||||||
|
|
||||||
|
if ($2 == SP_HANDLER_CONTINUE)
|
||||||
|
sp->add_instr(new sp_instr_hreturn(sp->instructions(),
|
||||||
|
lex->spcont->current_framesize()));
|
||||||
|
else
|
||||||
|
{ /* EXIT or UNDO handler, just jump to the end of the block */
|
||||||
|
sp_instr_jump *i= new sp_instr_jump(sp->instructions());
|
||||||
|
|
||||||
|
sp->add_instr(i);
|
||||||
|
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
|
||||||
|
}
|
||||||
|
lex->sphead->backpatch(hlab);
|
||||||
|
$$.vars= $$.conds= 0;
|
||||||
|
$$.hndlrs= $6;
|
||||||
|
}
|
||||||
|
/* QQ Not yet
|
||||||
|
| DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
|
||||||
|
{
|
||||||
|
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||||
|
}*/
|
||||||
|
;
|
||||||
|
|
||||||
|
sp_handler_type:
|
||||||
|
EXIT_SYM { $$= SP_HANDLER_EXIT; }
|
||||||
|
| CONTINUE_SYM { $$= SP_HANDLER_CONTINUE; }
|
||||||
|
/* | UNDO_SYM { QQ No yet } */
|
||||||
|
;
|
||||||
|
|
||||||
|
sp_hcond_list:
|
||||||
|
sp_hcond
|
||||||
|
{
|
||||||
|
LEX *lex= Lex;
|
||||||
|
sp_head *sp= lex->sphead;
|
||||||
|
sp_instr_hpush_jump *i= (sp_instr_hpush_jump *)sp->last_instruction();
|
||||||
|
|
||||||
|
i->add_condition($1);
|
||||||
|
$$= 1;
|
||||||
|
}
|
||||||
|
| sp_hcond_list ',' sp_hcond
|
||||||
|
{
|
||||||
|
LEX *lex= Lex;
|
||||||
|
sp_head *sp= lex->sphead;
|
||||||
|
sp_instr_hpush_jump *i= (sp_instr_hpush_jump *)sp->last_instruction();
|
||||||
|
|
||||||
|
i->add_condition($3);
|
||||||
|
$$= $1 + 1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
sp_cond:
|
||||||
|
ULONG_NUM
|
||||||
|
{ /* mysql errno */
|
||||||
|
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||||||
|
$$->type= sp_cond_type_t::number;
|
||||||
|
$$->mysqlerr= $1;
|
||||||
|
}
|
||||||
|
| TEXT_STRING_literal
|
||||||
|
{ /* SQLSTATE */
|
||||||
|
uint len= ($1.length < sizeof($$->sqlstate)-1 ?
|
||||||
|
$1.length : sizeof($$->sqlstate)-1);
|
||||||
|
|
||||||
|
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||||||
|
$$->type= sp_cond_type_t::state;
|
||||||
|
memcpy($$->sqlstate, $1.str, len);
|
||||||
|
$$->sqlstate[len]= '\0';
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
sp_hcond:
|
||||||
|
sp_cond
|
||||||
|
{
|
||||||
|
$$= $1;
|
||||||
|
}
|
||||||
|
| ident /* CONDITION name */
|
||||||
|
{
|
||||||
|
$$= Lex->spcont->find_cond(&$1);
|
||||||
|
if ($$ == NULL)
|
||||||
|
{
|
||||||
|
net_printf(YYTHD, ER_SP_COND_MISMATCH, $1.str);
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| SQLWARNING_SYM /* SQLSTATEs 01??? */
|
||||||
|
{
|
||||||
|
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||||||
|
$$->type= sp_cond_type_t::warning;
|
||||||
|
}
|
||||||
|
| NOT FOUND_SYM /* SQLSTATEs 02??? */
|
||||||
|
{
|
||||||
|
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||||||
|
$$->type= sp_cond_type_t::notfound;
|
||||||
|
}
|
||||||
|
| SQLEXCEPTION_SYM /* All other SQLSTATEs */
|
||||||
|
{
|
||||||
|
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||||||
|
$$->type= sp_cond_type_t::exception;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_decl_idents:
|
sp_decl_idents:
|
||||||
ident
|
ident
|
||||||
{
|
{
|
||||||
Lex->spcont->push(&$1, (enum_field_types)0, sp_param_in);
|
Lex->spcont->push_pvar(&$1, (enum_field_types)0, sp_param_in);
|
||||||
$$= 1;
|
$$= 1;
|
||||||
}
|
}
|
||||||
| sp_decl_idents ',' ident
|
| sp_decl_idents ',' ident
|
||||||
{
|
{
|
||||||
Lex->spcont->push(&$3, (enum_field_types)0, sp_param_in);
|
Lex->spcont->push_pvar(&$3, (enum_field_types)0, sp_param_in);
|
||||||
$$= $1 + 1;
|
$$= $1 + 1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -1246,9 +1383,9 @@ sp_proc_stmt:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sp_instr_return *i=
|
sp_instr_freturn *i=
|
||||||
new sp_instr_return(lex->sphead->instructions(),
|
new sp_instr_freturn(lex->sphead->instructions(),
|
||||||
$2, lex->sphead->m_returns);
|
$2, lex->sphead->m_returns);
|
||||||
|
|
||||||
lex->sphead->add_instr(i);
|
lex->sphead->add_instr(i);
|
||||||
}
|
}
|
||||||
@ -1273,13 +1410,13 @@ sp_proc_stmt:
|
|||||||
|
|
||||||
dummy.str= (char *)"";
|
dummy.str= (char *)"";
|
||||||
dummy.length= 0;
|
dummy.length= 0;
|
||||||
lex->spcont->push(&dummy, MYSQL_TYPE_STRING, sp_param_in);
|
lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
|
||||||
lex->sphead->add_instr(i);
|
lex->sphead->add_instr(i);
|
||||||
lex->sphead->m_simple_case= TRUE;
|
lex->sphead->m_simple_case= TRUE;
|
||||||
}
|
}
|
||||||
sp_case END CASE_SYM
|
sp_case END CASE_SYM
|
||||||
{
|
{
|
||||||
Lex->spcont->pop();
|
Lex->spcont->pop_pvar();
|
||||||
}
|
}
|
||||||
| sp_labeled_control
|
| sp_labeled_control
|
||||||
{}
|
{}
|
||||||
@ -1331,6 +1468,12 @@ sp_proc_stmt:
|
|||||||
lex->sphead->add_instr(i);
|
lex->sphead->add_instr(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
| OPEN_SYM ident
|
||||||
|
{}
|
||||||
|
| FETCH_SYM ident INTO select_var_list_init
|
||||||
|
{}
|
||||||
|
| CLOSE_SYM ident
|
||||||
|
{}
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_if:
|
sp_if:
|
||||||
@ -1452,13 +1595,26 @@ sp_labeled_control:
|
|||||||
|
|
||||||
sp_unlabeled_control:
|
sp_unlabeled_control:
|
||||||
BEGIN_SYM
|
BEGIN_SYM
|
||||||
sp_decls
|
|
||||||
sp_proc_stmts
|
|
||||||
END
|
|
||||||
{ /* QQ This is just a dummy for grouping declarations and statements
|
{ /* QQ This is just a dummy for grouping declarations and statements
|
||||||
together. No [[NOT] ATOMIC] yet, and we need to figure out how
|
together. No [[NOT] ATOMIC] yet, and we need to figure out how
|
||||||
make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
|
make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
|
||||||
Lex->spcont->pop($2);
|
|
||||||
|
Lex->spcont->push_label((char *)"", 0); /* For end of block */
|
||||||
|
}
|
||||||
|
sp_decls
|
||||||
|
sp_proc_stmts
|
||||||
|
END
|
||||||
|
{
|
||||||
|
LEX *lex= Lex;
|
||||||
|
sp_head *sp= lex->sphead;
|
||||||
|
sp_pcontext *ctx= lex->spcont;
|
||||||
|
sp_instr_hpop *i;
|
||||||
|
|
||||||
|
sp->backpatch(ctx->pop_label());
|
||||||
|
ctx->pop_pvar($3.vars);
|
||||||
|
ctx->pop_cond($3.conds);
|
||||||
|
i= new sp_instr_hpop(sp->instructions(), $3.hndlrs);
|
||||||
|
sp->add_instr(i);
|
||||||
}
|
}
|
||||||
| LOOP_SYM
|
| LOOP_SYM
|
||||||
sp_proc_stmts END LOOP_SYM
|
sp_proc_stmts END LOOP_SYM
|
||||||
|
Reference in New Issue
Block a user