mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
WL#962: Added simple, read-only, non-scrolling, asensitive cursors in SPs, using the
(updated) Protocol_cursor class. Also did some bug fixes. Docs/sp-imp-spec.txt: Added CURSOR docs (and fixed typos) Docs/sp-implemented.txt: Updated for CURSORs include/mysqld_error.h: New error codes/messages for CURSORs libmysqld/Makefile.am: SP cursors now needs this. mysql-test/r/sp-error.result: New tests for cursors. mysql-test/r/sp.result: New tests for cursors. mysql-test/t/sp-error.test: New tests for cursors. mysql-test/t/sp.test: New tests for cursors. sql/protocol.cc: We now always have Protocol_cursor (SPs use it) sql/protocol.h: Fixed bugs in Protocol_cursor (for SPs) sql/protocol_cursor.cc: Fixed bugs in Protocol_cursor (for SPs) sql/share/czech/errmsg.txt: New error codes/messages for CURSORs sql/share/danish/errmsg.txt: New error codes/messages for CURSORs sql/share/dutch/errmsg.txt: New error codes/messages for CURSORs sql/share/english/errmsg.txt: New error codes/messages for CURSORs sql/share/estonian/errmsg.txt: New error codes/messages for CURSORs sql/share/french/errmsg.txt: New error codes/messages for CURSORs sql/share/german/errmsg.txt: New error codes/messages for CURSORs sql/share/greek/errmsg.txt: New error codes/messages for CURSORs sql/share/hungarian/errmsg.txt: New error codes/messages for CURSORs sql/share/italian/errmsg.txt: New error codes/messages for CURSORs sql/share/japanese/errmsg.txt: New error codes/messages for CURSORs sql/share/korean/errmsg.txt: New error codes/messages for CURSORs sql/share/norwegian-ny/errmsg.txt: New error codes/messages for CURSORs sql/share/norwegian/errmsg.txt: New error codes/messages for CURSORs sql/share/polish/errmsg.txt: New error codes/messages for CURSORs sql/share/portuguese/errmsg.txt: New error codes/messages for CURSORs sql/share/romanian/errmsg.txt: New error codes/messages for CURSORs sql/share/russian/errmsg.txt: New error codes/messages for CURSORs sql/share/serbian/errmsg.txt: New error codes/messages for CURSORs sql/share/slovak/errmsg.txt: New error codes/messages for CURSORs sql/share/spanish/errmsg.txt: New error codes/messages for CURSORs sql/share/swedish/errmsg.txt: New error codes/messages for CURSORs sql/share/ukrainian/errmsg.txt: New error codes/messages for CURSORs sql/sp_head.cc: Added cursor support. Also fixed problems with item_lists, where pointers and ref_pointer_arrays. sql/sp_head.h: Added cursor support sql/sp_pcontext.cc: Added cursor support sql/sp_pcontext.h: Added cursor support sql/sp_rcontext.cc: Added cursor support, in particular the new sp_cursor class. sql/sp_rcontext.h: Added cursor support, in particular the new sp_cursor class. sql/sql_lex.h: We sometimes need to copy item_lists in LEX when executing substatements in SPs sql/sql_yacc.yy: Added minimal cursor support (not the full syntax yet).
This commit is contained in:
parent
4379cbcf30
commit
04c6b9b8d8
42 changed files with 1290 additions and 71 deletions
|
@ -11,7 +11,7 @@
|
|||
which dispatches on the command code (in Lex) to the corresponding code for
|
||||
executing that particular query.
|
||||
|
||||
There are thre structures involved in the execution of a query which are of
|
||||
There are three structures involved in the execution of a query which are of
|
||||
interest to the stored procedure implementation:
|
||||
|
||||
- Lex (mentioned above) is the "compiled" query, that is the output from
|
||||
|
@ -186,7 +186,7 @@
|
|||
stored in the table mysql.proc with the name and type as the key, the
|
||||
type being one of the enum ("procedure","function").
|
||||
|
||||
A PROCEDURE is just stored int the mysql.proc table. A FUNCTION has an
|
||||
A PROCEDURE is just stored in the mysql.proc table. A FUNCTION has an
|
||||
additional requirement. They will be called in expressions with the same
|
||||
syntax as UDFs, so UDFs and stored FUNCTIONs share the namespace. Thus,
|
||||
we must make sure that we do not have UDFs and FUNCTIONs with the same
|
||||
|
@ -293,7 +293,7 @@
|
|||
So, stored functions must be handled in a simpilar way, and as a
|
||||
consequence, UDFs and functions must not have the same name.
|
||||
|
||||
- Detecting and parsing a FUNCTION invokation
|
||||
- Detecting and parsing a FUNCTION invocation
|
||||
|
||||
The existance of UDFs are checked during the lexical analysis (in
|
||||
sql_lex.cc:find_keyword()). This has the drawback that they must
|
||||
|
@ -319,7 +319,7 @@
|
|||
"on-the-fly" during the execution of *another* statement.
|
||||
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
|
||||
point of invokation; the server requires that all tables used are
|
||||
point of invocation; the server requires that all tables used are
|
||||
opened and locked at the beginning of the query execution.
|
||||
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
|
||||
|
@ -478,6 +478,67 @@
|
|||
7 sp_instr_hpop(2)
|
||||
|
||||
|
||||
- Cursors
|
||||
|
||||
For stored procedures to be really useful, you want to have cursors.
|
||||
MySQL doesn't yet have "real" cursor support (with API and ODBC support,
|
||||
allowing updating, arbitrary scrolling, etc), but a simple asensitive,
|
||||
non-scrolling, read-only cursor can be implemented in SPs using the
|
||||
class Protocol_cursor.
|
||||
This class intecepts the creation and sending of results sets and instead
|
||||
stores it in-memory, as MYSQL_FIELDS and MYSQL_ROWS (as in the client API).
|
||||
|
||||
To support this, we need the usual name binding support in sp_pcontext
|
||||
(similar to variables and conditions) to keep track on declared cursor
|
||||
names, and a corresponding run-time mechanism in sp_rcontext.
|
||||
Cursors are lexically scoped like everything with a body or BEGIN/END
|
||||
block, so they are pushed and poped as usual (see conditions and variables
|
||||
above).
|
||||
The basic operations on a cursor are OPEN, FETCH and CLOSE, which will
|
||||
each have a corresponding instruction. In addition, we need instructions
|
||||
to push a new cursor (this will encapsulate the LEX of the SELECT statement
|
||||
of the cursor), and a pop instruction:
|
||||
- sp_instr_cpush
|
||||
Push a cursor to the sp_rcontext. This instruction contains the LEX
|
||||
for the select statement
|
||||
- sp_instr_cpop
|
||||
Pop a number of cursors from the sp_rcontext.
|
||||
- sp_instr_copen
|
||||
Open a cursor: This will execute the select and get the result set
|
||||
in a sepeate memroot.
|
||||
- sp_instr_cfetch
|
||||
Fetch the next row from the in-memory result set. The instruction
|
||||
contains a list of the variables (frame offsets) to set.
|
||||
- sp_instr_cclose
|
||||
Free the result set.
|
||||
|
||||
A cursor is a separate class, sp_cursor (defined in sp_rcontex.h) which
|
||||
encapsulates the basic operations used by the above instructions.
|
||||
This class contains the LEX, Protocol_cursor object, and its memroot,
|
||||
as well as the cursor's current state.
|
||||
Compiling and executing is fairly straight-forward. sp_instr_copen is
|
||||
a subclass of sp_instr_stmt and uses its mechanism to execute a
|
||||
substatement.
|
||||
|
||||
- Example:
|
||||
|
||||
begin
|
||||
declare x int;
|
||||
declare c cursor for select a from t1;
|
||||
|
||||
open c;
|
||||
fetch c into x;
|
||||
close c;
|
||||
end
|
||||
|
||||
Pos. Instruction
|
||||
0 sp_instr_cpush('select a from ...')
|
||||
1 sp_instr_copen(0) # The 0'th cursor
|
||||
2 sp_instr_cfetch(0) # Contains the variable list
|
||||
3 sp_instr_cclose(0)
|
||||
4 sp_instr_cpop(1)
|
||||
|
||||
|
||||
- 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.
|
||||
|
@ -569,6 +630,18 @@
|
|||
|
||||
// Returns the handler count
|
||||
uint handlers();
|
||||
|
||||
// Push a cursor
|
||||
void push_cursor(LEX_STRING *name);
|
||||
|
||||
// Find a cursor
|
||||
my_bool find_cursor(LEX_STRING *name, uint *poff);
|
||||
|
||||
// Pop 'num' cursors
|
||||
void pop_cursor(uint num);
|
||||
|
||||
// Return the number of cursors
|
||||
uint cursors();
|
||||
}
|
||||
|
||||
|
||||
|
@ -589,8 +662,9 @@
|
|||
|
||||
class sp_rcontext
|
||||
{
|
||||
// 'fsize' is the max size of the context, 'hmax' the number of handlers
|
||||
sp_rcontext(uint fsize, uint hmax);
|
||||
// 'fsize' is the max size of the context, 'hmax' the number of handlers,
|
||||
// 'cmax' the number of cursors
|
||||
sp_rcontext(uint fsize, uint hmax, , uint cmax);
|
||||
|
||||
// Push value (parameter) 'i' to the frame
|
||||
void push_item(Item *i);
|
||||
|
@ -645,6 +719,18 @@
|
|||
// Restore saved variables from to frame index 'fp' and up.
|
||||
void restore_variables(uint fp);
|
||||
|
||||
// Push a cursor for the statement (lex)
|
||||
void push_cursor(LEX *lex);
|
||||
|
||||
// Pop 'count' cursors
|
||||
void pop_cursors(uint count);
|
||||
|
||||
// Pop all cursors
|
||||
void pop_all_cursors();
|
||||
|
||||
// Get the 'i'th cursor
|
||||
sp_cursor *get_cursor(uint i);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -709,6 +795,7 @@
|
|||
bool suid, char *comment, uint commentlen);
|
||||
}
|
||||
|
||||
|
||||
- Instructions
|
||||
|
||||
- The base class:
|
||||
|
@ -816,6 +903,55 @@
|
|||
int execute(THD *thd, uint *nextp);
|
||||
}
|
||||
|
||||
- Push a CURSOR
|
||||
class sp_instr_cpush : public sp_instr_stmt
|
||||
{
|
||||
// Push a cursor for statement 'lex'
|
||||
sp_instr_cpush(uint ip, LEX *lex)
|
||||
|
||||
int execute(THD *thd, uint *nextp);
|
||||
}
|
||||
|
||||
- Pop CURSORs
|
||||
class sp_instr_cpop : public sp_instr_stmt
|
||||
{
|
||||
// Pop 'count' cursors
|
||||
sp_instr_cpop(uint ip, uint count)
|
||||
|
||||
int execute(THD *thd, uint *nextp);
|
||||
}
|
||||
|
||||
- Open a CURSOR
|
||||
class sp_instr_copen : public sp_instr_stmt
|
||||
{
|
||||
// Open the 'c'th cursor
|
||||
sp_instr_copen(uint ip, uint c);
|
||||
|
||||
int execute(THD *thd, uint *nextp);
|
||||
}
|
||||
|
||||
- Close a CURSOR
|
||||
class sp_instr_cclose : public sp_instr
|
||||
{
|
||||
// Close the 'c'th cursor
|
||||
sp_instr_cclose(uint ip, uint c);
|
||||
|
||||
int execute(THD *thd, uint *nextp);
|
||||
}
|
||||
|
||||
- Fetch a row with CURSOR
|
||||
class sp_instr_cfetch : public sp_instr
|
||||
{
|
||||
// Fetch next with the 'c'th cursor
|
||||
sp_instr_cfetch(uint ip, uint c);
|
||||
|
||||
int execute(THD *thd, uint *nextp);
|
||||
|
||||
// Add a target variable for the fetch
|
||||
void add_to_varlist(struct sp_pvar *var);
|
||||
}
|
||||
|
||||
|
||||
- Utility functions: sp.h
|
||||
|
||||
#define SP_OK 0
|
||||
|
|
|
@ -8,8 +8,7 @@ Summary of Not Yet Implemented:
|
|||
- Access control
|
||||
- Routine characteristics (mostly used for external languages)
|
||||
- SQL-99 COMMIT (related to BEGIN/END)
|
||||
- DECLARE CURSOR ...
|
||||
- FOR-loops (as it requires cursors)
|
||||
- FOR-loops
|
||||
- CASCADE/RESTRICT for ALTER and DROP
|
||||
- ALTER/DROP METHOD (as it implies User Defined Types)
|
||||
- SIGNAL and RESIGNAL, and UNDO handlers
|
||||
|
@ -25,6 +24,7 @@ Summary of what's implemented:
|
|||
- "Non-query" FUNCTIONs only
|
||||
- Prepared SP caching
|
||||
- CONDITIONs and HANDLERs
|
||||
- Simple read-only CURSORs.
|
||||
|
||||
List of what's implemented:
|
||||
|
||||
|
@ -86,6 +86,11 @@ List of what's 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).
|
||||
- Simple read-only CURSORs are implemented, but not yet any of the
|
||||
optional arguments to DECLARE (SCROLL, SENSITIVE, etc) or FETCH
|
||||
(NEXT, PRIOR, etc). Cursors are ASENSITIVE, READ-ONLY, non-SCROLLing.
|
||||
(The additional syntax will be added for completeness, but for the
|
||||
most part unsupported with the current underlying cursor mechanism.)
|
||||
|
||||
Closed questions:
|
||||
|
||||
|
|
|
@ -314,4 +314,12 @@
|
|||
#define ER_SP_COND_MISMATCH 1295
|
||||
#define ER_SP_NORETURN 1296
|
||||
#define ER_SP_NORETURNEND 1297
|
||||
#define ER_ERROR_MESSAGES 298
|
||||
#define ER_SP_BAD_CURSOR_QUERY 1298
|
||||
#define ER_SP_BAD_CURSOR_SELECT 1299
|
||||
#define ER_SP_CURSOR_MISMATCH 1300
|
||||
#define ER_SP_CURSOR_ALREADY_OPEN 1301
|
||||
#define ER_SP_CURSOR_NOT_OPEN 1302
|
||||
#define ER_SP_UNDECLARED_VAR 1303
|
||||
#define ER_SP_WRONG_NO_OF_FETCH_ARGS 1304
|
||||
#define ER_SP_FETCH_NO_DATA 1305
|
||||
#define ER_ERROR_MESSAGES 306
|
||||
|
|
|
@ -56,7 +56,7 @@ sqlsources = derror.cc field.cc field_conv.cc filesort.cc \
|
|||
sql_string.cc sql_table.cc sql_test.cc sql_udf.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 \
|
||||
spatial.cc gstream.cc sql_help.cc \
|
||||
spatial.cc gstream.cc sql_help.cc protocol_cursor.cc \
|
||||
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc
|
||||
|
||||
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
|
||||
|
|
|
@ -138,3 +138,85 @@ end;
|
|||
select f(10);
|
||||
ERROR HY000: FUNCTION f ended without RETURN
|
||||
drop function f;
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for insert into test.t1 values ("foo", 42);
|
||||
open c;
|
||||
close c;
|
||||
end;
|
||||
ERROR HY000: Cursor statement must be a SELECT
|
||||
create procedure p()
|
||||
begin
|
||||
declare x int;
|
||||
declare c cursor for select * into x from test.t limit 1;
|
||||
open c;
|
||||
close c;
|
||||
end;
|
||||
ERROR HY000: Cursor SELECT must not have INTO
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from test.t;
|
||||
open cc;
|
||||
close c;
|
||||
end;
|
||||
ERROR HY000: Undefined CURSOR: cc
|
||||
drop table if exists t1;
|
||||
create table t1 (val int);
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from test.t1;
|
||||
open c;
|
||||
open c;
|
||||
close c;
|
||||
end;
|
||||
call p();
|
||||
ERROR HY000: Cursor is already open
|
||||
drop procedure p;
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from test.t1;
|
||||
open c;
|
||||
close c;
|
||||
close c;
|
||||
end;
|
||||
call p();
|
||||
ERROR HY000: Cursor is not open
|
||||
drop procedure p;
|
||||
drop table t1;
|
||||
drop table if exists t1;
|
||||
create table t1 (val int, x float);
|
||||
insert into t1 values (42, 3.1), (19, 1.2);
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from t1;
|
||||
declare x int;
|
||||
open c;
|
||||
fetch c into x, y;
|
||||
close c;
|
||||
end;
|
||||
ERROR HY000: Undeclared variable: y
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from t1;
|
||||
declare x int;
|
||||
open c;
|
||||
fetch c into x;
|
||||
close c;
|
||||
end;
|
||||
call p();
|
||||
ERROR HY000: Wrong number of FETCH variables
|
||||
drop procedure p;
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from t1;
|
||||
declare x int;
|
||||
declare y float;
|
||||
declare z int;
|
||||
open c;
|
||||
fetch c into x, y, z;
|
||||
close c;
|
||||
end;
|
||||
call p();
|
||||
ERROR HY000: Wrong number of FETCH variables
|
||||
drop procedure p;
|
||||
drop table t1;
|
||||
|
|
|
@ -500,6 +500,33 @@ id data
|
|||
hndlr3 13
|
||||
delete from t1;
|
||||
drop procedure hndlr3;
|
||||
create procedure cur1()
|
||||
begin
|
||||
declare done int default 0;
|
||||
declare continue handler for 1305 set done = 1;
|
||||
declare c cursor for select * from test.t2;
|
||||
declare a char(16);
|
||||
declare b int;
|
||||
declare c double;
|
||||
open c;
|
||||
repeat
|
||||
fetch c into a, b, c;
|
||||
if not done then
|
||||
insert into test.t1 values (a, b+c);
|
||||
end if;
|
||||
until done end repeat;
|
||||
close c;
|
||||
end;
|
||||
insert into t2 values ("foo", 42, -1.9), ("bar", 3, 12.1), ("zap", 666, -3.14);
|
||||
call cur1();
|
||||
select * from t1;
|
||||
id data
|
||||
foo 40
|
||||
bar 15
|
||||
zap 663
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
drop procedure cur1;
|
||||
create procedure bug822(a_id char(16), a_data int)
|
||||
begin
|
||||
declare n int;
|
||||
|
|
|
@ -194,4 +194,110 @@ select f(10)|
|
|||
|
||||
drop function f|
|
||||
|
||||
--error 1298
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for insert into test.t1 values ("foo", 42);
|
||||
|
||||
open c;
|
||||
close c;
|
||||
end|
|
||||
|
||||
--error 1299
|
||||
create procedure p()
|
||||
begin
|
||||
declare x int;
|
||||
declare c cursor for select * into x from test.t limit 1;
|
||||
|
||||
open c;
|
||||
close c;
|
||||
end|
|
||||
|
||||
--error 1300
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from test.t;
|
||||
|
||||
open cc;
|
||||
close c;
|
||||
end|
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1|
|
||||
--enable_warnings
|
||||
create table t1 (val int)|
|
||||
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from test.t1;
|
||||
|
||||
open c;
|
||||
open c;
|
||||
close c;
|
||||
end|
|
||||
--error 1301
|
||||
call p()|
|
||||
drop procedure p|
|
||||
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from test.t1;
|
||||
|
||||
open c;
|
||||
close c;
|
||||
close c;
|
||||
end|
|
||||
--error 1302
|
||||
call p()|
|
||||
drop procedure p|
|
||||
|
||||
drop table t1|
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1|
|
||||
--enable_warnings
|
||||
create table t1 (val int, x float)|
|
||||
insert into t1 values (42, 3.1), (19, 1.2)|
|
||||
|
||||
--error 1303
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from t1;
|
||||
declare x int;
|
||||
|
||||
open c;
|
||||
fetch c into x, y;
|
||||
close c;
|
||||
end|
|
||||
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from t1;
|
||||
declare x int;
|
||||
|
||||
open c;
|
||||
fetch c into x;
|
||||
close c;
|
||||
end|
|
||||
--error 1304
|
||||
call p()|
|
||||
drop procedure p|
|
||||
|
||||
create procedure p()
|
||||
begin
|
||||
declare c cursor for select * from t1;
|
||||
declare x int;
|
||||
declare y float;
|
||||
declare z int;
|
||||
|
||||
open c;
|
||||
fetch c into x, y, z;
|
||||
close c;
|
||||
end|
|
||||
--error 1304
|
||||
call p()|
|
||||
drop procedure p|
|
||||
|
||||
drop table t1|
|
||||
|
||||
delimiter ;|
|
||||
|
|
|
@ -588,7 +588,38 @@ select * from t1|
|
|||
delete from t1|
|
||||
drop procedure hndlr3|
|
||||
|
||||
#
|
||||
# Cursors
|
||||
#
|
||||
create procedure cur1()
|
||||
begin
|
||||
declare done int default 0;
|
||||
declare continue handler for 1305 set done = 1;
|
||||
declare c cursor for select * from test.t2;
|
||||
declare a char(16);
|
||||
declare b int;
|
||||
declare c double;
|
||||
|
||||
open c;
|
||||
repeat
|
||||
fetch c into a, b, c;
|
||||
if not done then
|
||||
insert into test.t1 values (a, b+c);
|
||||
end if;
|
||||
until done end repeat;
|
||||
close c;
|
||||
end|
|
||||
|
||||
insert into t2 values ("foo", 42, -1.9), ("bar", 3, 12.1), ("zap", 666, -3.14)|
|
||||
call cur1()|
|
||||
select * from t1|
|
||||
delete from t1|
|
||||
delete from t2|
|
||||
drop procedure cur1|
|
||||
|
||||
#
|
||||
# BUG#822
|
||||
#
|
||||
create procedure bug822(a_id char(16), a_data int)
|
||||
begin
|
||||
declare n int;
|
||||
|
|
|
@ -1145,12 +1145,3 @@ bool Protocol_prep::store_time(TIME *tm)
|
|||
buff[0]=(char) length; // Length is stored first
|
||||
return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC);
|
||||
}
|
||||
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
/* Should be removed when we define the Protocol_cursor's future */
|
||||
bool Protocol_cursor::write()
|
||||
{
|
||||
return Protocol_simple::write();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -47,17 +47,13 @@ public:
|
|||
Protocol(THD *thd) { init(thd); }
|
||||
virtual ~Protocol() {}
|
||||
void init(THD* thd);
|
||||
bool send_fields(List<Item> *list, uint flag);
|
||||
virtual bool send_fields(List<Item> *list, uint flag);
|
||||
bool send_records_num(List<Item> *list, ulonglong records);
|
||||
bool store(I_List<i_string> *str_list);
|
||||
bool store(const char *from, CHARSET_INFO *cs);
|
||||
String *storage_packet() { return packet; }
|
||||
inline void free() { packet->free(); }
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
bool write();
|
||||
#else
|
||||
virtual bool write();
|
||||
#endif
|
||||
inline bool store(uint32 from)
|
||||
{ return store_long((longlong) from); }
|
||||
inline bool store(longlong from)
|
||||
|
@ -158,6 +154,7 @@ public:
|
|||
Protocol_cursor(THD *thd, MEM_ROOT *ini_alloc) :Protocol_simple(thd), alloc(ini_alloc) {}
|
||||
bool prepare_for_send(List<Item> *item_list)
|
||||
{
|
||||
row_count= 0;
|
||||
fields= NULL;
|
||||
data= NULL;
|
||||
prev_record= &data;
|
||||
|
@ -165,6 +162,7 @@ public:
|
|||
}
|
||||
bool send_fields(List<Item> *list, uint flag);
|
||||
bool write();
|
||||
uint get_field_count() { return field_count; }
|
||||
};
|
||||
|
||||
void send_warning(THD *thd, uint sql_errno, const char *err=0);
|
||||
|
|
|
@ -51,6 +51,7 @@ bool Protocol_cursor::send_fields(List<Item> *list, uint flag)
|
|||
client_field->name= strdup_root(alloc, server_field.col_name);
|
||||
client_field->org_table= strdup_root(alloc, server_field.org_table_name);
|
||||
client_field->org_name= strdup_root(alloc, server_field.org_col_name);
|
||||
client_field->catalog= strdup_root(alloc, "");
|
||||
client_field->length= server_field.length;
|
||||
client_field->type= server_field.type;
|
||||
client_field->flags= server_field.flags;
|
||||
|
@ -60,6 +61,7 @@ bool Protocol_cursor::send_fields(List<Item> *list, uint flag)
|
|||
client_field->name_length= strlen(client_field->name);
|
||||
client_field->org_name_length= strlen(client_field->org_name);
|
||||
client_field->org_table_length= strlen(client_field->org_table);
|
||||
client_field->catalog_length= 0;
|
||||
client_field->charsetnr= server_field.charsetnr;
|
||||
|
||||
if (INTERNAL_NUM_FIELD(client_field))
|
||||
|
@ -100,17 +102,17 @@ bool Protocol_cursor::write()
|
|||
byte *to;
|
||||
|
||||
new_record= (MYSQL_ROWS *)alloc_root(alloc,
|
||||
sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length());
|
||||
sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length());
|
||||
if (!new_record)
|
||||
goto err;
|
||||
data= (byte **)(new_record + 1);
|
||||
new_record->data= (char **)data;
|
||||
|
||||
to= (byte *)(fields + field_count + 1);
|
||||
to= (byte *)data + (field_count + 1)*sizeof(char *);
|
||||
|
||||
for (; cur_field < fields_end; ++cur_field, ++data)
|
||||
{
|
||||
if ((len=net_field_length((uchar **)&cp)))
|
||||
if ((len= net_field_length((uchar **)&cp)) == 0)
|
||||
{
|
||||
*data= 0;
|
||||
}
|
||||
|
@ -121,6 +123,7 @@ bool Protocol_cursor::write()
|
|||
// TODO error signal send_error(thd, CR_MALFORMED_PACKET);
|
||||
return TRUE;
|
||||
}
|
||||
*data= to;
|
||||
memcpy(to,(char*) cp,len);
|
||||
to[len]=0;
|
||||
to+=len+1;
|
||||
|
@ -129,6 +132,7 @@ bool Protocol_cursor::write()
|
|||
cur_field->max_length=len;
|
||||
}
|
||||
}
|
||||
*data= 0;
|
||||
|
||||
*prev_record= new_record;
|
||||
prev_record= &new_record->next;
|
||||
|
@ -139,5 +143,3 @@ bool Protocol_cursor::write()
|
|||
// TODO error signal send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -310,3 +310,11 @@ character-set=latin2
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -304,3 +304,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -312,3 +312,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -301,3 +301,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -306,3 +306,11 @@ character-set=latin7
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -301,3 +301,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -310,3 +310,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -301,3 +301,11 @@ character-set=greek
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -303,3 +303,11 @@ character-set=latin2
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -301,3 +301,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -303,3 +303,11 @@ character-set=ujis
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -301,3 +301,11 @@ character-set=euckr
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -303,3 +303,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -303,3 +303,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -305,3 +305,11 @@ character-set=latin2
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -302,3 +302,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -305,3 +305,11 @@ character-set=latin2
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -303,3 +303,11 @@ character-set=koi8r
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -296,3 +296,11 @@ character-set=cp1250
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -309,3 +309,11 @@ character-set=latin2
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -303,3 +303,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -301,3 +301,11 @@ character-set=latin1
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
|
@ -306,3 +306,11 @@ character-set=koi8u
|
|||
"Undefined CONDITION: %s"
|
||||
"No RETURN found in FUNCTION %s"
|
||||
"FUNCTION %s ended without RETURN"
|
||||
"Cursor statement must be a SELECT"
|
||||
"Cursor SELECT must not have INTO"
|
||||
"Undefined CURSOR: %s"
|
||||
"Cursor is already open"
|
||||
"Cursor is not open"
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
|
|
153
sql/sp_head.cc
153
sql/sp_head.cc
|
@ -289,6 +289,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
|
|||
uint csize = m_pcont->max_framesize();
|
||||
uint params = m_pcont->params();
|
||||
uint hmax = m_pcont->handlers();
|
||||
uint cmax = m_pcont->cursors();
|
||||
sp_rcontext *octx = thd->spcont;
|
||||
sp_rcontext *nctx = NULL;
|
||||
uint i;
|
||||
|
@ -304,7 +305,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
|
|||
}
|
||||
|
||||
// QQ Should have some error checking here? (types, etc...)
|
||||
nctx= new sp_rcontext(csize, hmax);
|
||||
nctx= new sp_rcontext(csize, hmax, cmax);
|
||||
for (i= 0 ; i < params && i < argcount ; i++)
|
||||
{
|
||||
sp_pvar_t *pvar = m_pcont->find_pvar(i);
|
||||
|
@ -335,6 +336,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
|
|||
}
|
||||
}
|
||||
|
||||
nctx->pop_all_cursors(); // To avoid memory leaks after an error
|
||||
thd->spcont= octx;
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
@ -349,6 +351,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||
uint csize = m_pcont->max_framesize();
|
||||
uint params = m_pcont->params();
|
||||
uint hmax = m_pcont->handlers();
|
||||
uint cmax = m_pcont->cursors();
|
||||
sp_rcontext *octx = thd->spcont;
|
||||
sp_rcontext *nctx = NULL;
|
||||
my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
|
||||
|
@ -360,17 +363,17 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
if (csize > 0 || hmax > 0)
|
||||
if (csize > 0 || hmax > 0 || cmax > 0)
|
||||
{
|
||||
uint i;
|
||||
List_iterator_fast<Item> li(*args);
|
||||
Item *it;
|
||||
|
||||
nctx = new sp_rcontext(csize, hmax);
|
||||
nctx= new sp_rcontext(csize, hmax, cmax);
|
||||
if (! octx)
|
||||
{ // Create a temporary old context
|
||||
octx = new sp_rcontext(csize, hmax);
|
||||
tmp_octx = TRUE;
|
||||
octx= new sp_rcontext(csize, hmax, cmax);
|
||||
tmp_octx= TRUE;
|
||||
}
|
||||
// QQ: Should do type checking?
|
||||
for (i = 0 ; (it= li++) && i < params ; i++)
|
||||
|
@ -443,13 +446,14 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_octx)
|
||||
thd->spcont= NULL;
|
||||
else
|
||||
thd->spcont= octx;
|
||||
}
|
||||
|
||||
if (tmp_octx)
|
||||
octx= NULL;
|
||||
if (nctx)
|
||||
nctx->pop_all_cursors(); // To avoid memory leaks after an error
|
||||
thd->spcont= octx;
|
||||
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
|
@ -596,12 +600,20 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
|
|||
{
|
||||
DBUG_ENTER("sp_instr_stmt::execute");
|
||||
DBUG_PRINT("info", ("command: %d", m_lex->sql_command));
|
||||
int res= exec_stmt(thd, m_lex);
|
||||
*nextp = m_ip+1;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
int
|
||||
sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
|
||||
{
|
||||
LEX *olex; // The other lex
|
||||
Item *freelist;
|
||||
int res;
|
||||
|
||||
olex= thd->lex; // Save the other lex
|
||||
thd->lex= m_lex; // Use my own lex
|
||||
thd->lex= lex; // Use my own lex
|
||||
thd->lex->thd = thd; // QQ Not reentrant!
|
||||
thd->lex->unit.thd= thd; // QQ Not reentrant
|
||||
freelist= thd->free_list;
|
||||
|
@ -610,10 +622,19 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
|
|||
|
||||
// Copy WHERE clause pointers to avoid damaging by optimisation
|
||||
// Also clear ref_pointer_arrays.
|
||||
for (SELECT_LEX *sl= m_lex->all_selects_list ;
|
||||
for (SELECT_LEX *sl= lex->all_selects_list ;
|
||||
sl ;
|
||||
sl= sl->next_select_in_list())
|
||||
{
|
||||
List_iterator_fast<Item> li(sl->item_list);
|
||||
|
||||
if (sl->with_wild)
|
||||
{
|
||||
// Copy item_list
|
||||
sl->item_list_copy.empty();
|
||||
while (Item *it= li++)
|
||||
sl->item_list_copy.push_back(it);
|
||||
}
|
||||
sl->ref_pointer_array= 0;
|
||||
if (sl->prep_where)
|
||||
sl->where= sl->prep_where->copy_andor_structure(thd);
|
||||
|
@ -628,11 +649,22 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
|
|||
close_thread_tables(thd); /* Free tables */
|
||||
}
|
||||
|
||||
for (SELECT_LEX *sl= lex->all_selects_list ;
|
||||
sl ;
|
||||
sl= sl->next_select_in_list())
|
||||
{
|
||||
if (sl->with_wild)
|
||||
{
|
||||
// Restore item_list
|
||||
sl->item_list.empty();
|
||||
while (Item *it= sl->item_list_copy.pop())
|
||||
sl->item_list.push_back(it);
|
||||
}
|
||||
}
|
||||
thd->lex= olex; // Restore the other lex
|
||||
thd->free_list= freelist;
|
||||
|
||||
*nextp = m_ip+1;
|
||||
DBUG_RETURN(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -747,3 +779,96 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp)
|
|||
*nextp= thd->spcont->pop_hstack();
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
//
|
||||
// sp_instr_cpush
|
||||
//
|
||||
int
|
||||
sp_instr_cpush::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
DBUG_ENTER("sp_instr_cpush::execute");
|
||||
thd->spcont->push_cursor(m_lex);
|
||||
*nextp= m_ip+1;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
sp_instr_cpush::~sp_instr_cpush()
|
||||
{
|
||||
if (m_lex)
|
||||
delete m_lex;
|
||||
}
|
||||
|
||||
//
|
||||
// sp_instr_cpop
|
||||
//
|
||||
int
|
||||
sp_instr_cpop::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
DBUG_ENTER("sp_instr_cpop::execute");
|
||||
thd->spcont->pop_cursors(m_count);
|
||||
*nextp= m_ip+1;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
//
|
||||
// sp_instr_copen
|
||||
//
|
||||
int
|
||||
sp_instr_copen::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
|
||||
int res;
|
||||
DBUG_ENTER("sp_instr_copen::execute");
|
||||
|
||||
if (! c)
|
||||
res= -1;
|
||||
else
|
||||
{
|
||||
LEX *lex= c->pre_open(thd);
|
||||
|
||||
if (! lex)
|
||||
res= -1;
|
||||
else
|
||||
res= exec_stmt(thd, lex);
|
||||
c->post_open(thd, (res == 0 ? TRUE : FALSE));
|
||||
}
|
||||
|
||||
*nextp= m_ip+1;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
//
|
||||
// sp_instr_cclose
|
||||
//
|
||||
int
|
||||
sp_instr_cclose::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
|
||||
int res;
|
||||
DBUG_ENTER("sp_instr_cclose::execute");
|
||||
|
||||
if (! c)
|
||||
res= -1;
|
||||
else
|
||||
res= c->close(thd);
|
||||
*nextp= m_ip+1;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
//
|
||||
// sp_instr_cfetch
|
||||
//
|
||||
int
|
||||
sp_instr_cfetch::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
|
||||
int res;
|
||||
DBUG_ENTER("sp_instr_cfetch::execute");
|
||||
|
||||
if (! c)
|
||||
res= -1;
|
||||
else
|
||||
res= c->fetch(thd, &m_varlist);
|
||||
*nextp= m_ip+1;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
|
129
sql/sp_head.h
129
sql/sp_head.h
|
@ -33,10 +33,9 @@ Item_result
|
|||
sp_map_result_type(enum enum_field_types type);
|
||||
|
||||
struct sp_label;
|
||||
|
||||
class sp_instr;
|
||||
|
||||
struct sp_cond_type;
|
||||
struct sp_pvar;
|
||||
|
||||
class sp_head : public Sql_alloc
|
||||
{
|
||||
|
@ -278,6 +277,10 @@ public:
|
|||
return m_lex;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
int exec_stmt(THD *thd, LEX *lex); // Execute a statement
|
||||
|
||||
private:
|
||||
|
||||
LEX *m_lex; // My own lex
|
||||
|
@ -503,4 +506,126 @@ private:
|
|||
}; // class sp_instr_hreturn : public sp_instr
|
||||
|
||||
|
||||
class sp_instr_cpush : public sp_instr
|
||||
{
|
||||
sp_instr_cpush(const sp_instr_cpush &); /* Prevent use of these */
|
||||
void operator=(sp_instr_cpush &);
|
||||
|
||||
public:
|
||||
|
||||
sp_instr_cpush(uint ip, LEX *lex)
|
||||
: sp_instr(ip), m_lex(lex)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_cpush();
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
private:
|
||||
|
||||
LEX *m_lex;
|
||||
|
||||
}; // class sp_instr_cpush : public sp_instr
|
||||
|
||||
|
||||
class sp_instr_cpop : public sp_instr
|
||||
{
|
||||
sp_instr_cpop(const sp_instr_cpop &); /* Prevent use of these */
|
||||
void operator=(sp_instr_cpop &);
|
||||
|
||||
public:
|
||||
|
||||
sp_instr_cpop(uint ip, uint count)
|
||||
: sp_instr(ip), m_count(count)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_cpop()
|
||||
{}
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
private:
|
||||
|
||||
uint m_count;
|
||||
|
||||
}; // class sp_instr_cpop : public sp_instr
|
||||
|
||||
|
||||
class sp_instr_copen : public sp_instr_stmt
|
||||
{
|
||||
sp_instr_copen(const sp_instr_copen &); /* Prevent use of these */
|
||||
void operator=(sp_instr_copen &);
|
||||
|
||||
public:
|
||||
|
||||
sp_instr_copen(uint ip, uint c)
|
||||
: sp_instr_stmt(ip), m_cursor(c)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_copen()
|
||||
{}
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
private:
|
||||
|
||||
uint m_cursor; // Stack index
|
||||
|
||||
}; // class sp_instr_copen : public sp_instr_stmt
|
||||
|
||||
|
||||
class sp_instr_cclose : public sp_instr
|
||||
{
|
||||
sp_instr_cclose(const sp_instr_cclose &); /* Prevent use of these */
|
||||
void operator=(sp_instr_cclose &);
|
||||
|
||||
public:
|
||||
|
||||
sp_instr_cclose(uint ip, uint c)
|
||||
: sp_instr(ip), m_cursor(c)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_cclose()
|
||||
{}
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
private:
|
||||
|
||||
uint m_cursor;
|
||||
|
||||
}; // class sp_instr_cclose : public sp_instr
|
||||
|
||||
|
||||
class sp_instr_cfetch : public sp_instr
|
||||
{
|
||||
sp_instr_cfetch(const sp_instr_cfetch &); /* Prevent use of these */
|
||||
void operator=(sp_instr_cfetch &);
|
||||
|
||||
public:
|
||||
|
||||
sp_instr_cfetch(uint ip, uint c)
|
||||
: sp_instr(ip), m_cursor(c)
|
||||
{
|
||||
m_varlist.empty();
|
||||
}
|
||||
|
||||
virtual ~sp_instr_cfetch()
|
||||
{}
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
void add_to_varlist(struct sp_pvar *var)
|
||||
{
|
||||
m_varlist.push_back(var);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint m_cursor;
|
||||
List<struct sp_pvar> m_varlist;
|
||||
|
||||
}; // class sp_instr_cfetch : public sp_instr
|
||||
|
||||
|
||||
#endif /* _SP_HEAD_H_ */
|
||||
|
|
|
@ -27,10 +27,11 @@
|
|||
#include "sp_head.h"
|
||||
|
||||
sp_pcontext::sp_pcontext()
|
||||
: Sql_alloc(), m_params(0), m_framesize(0), m_handlers(0), m_genlab(0)
|
||||
: Sql_alloc(), m_params(0), m_framesize(0), m_handlers(0), m_cursmax(0)
|
||||
{
|
||||
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));
|
||||
VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8));
|
||||
m_label.empty();
|
||||
}
|
||||
|
||||
|
@ -39,6 +40,7 @@ sp_pcontext::destroy()
|
|||
{
|
||||
delete_dynamic(&m_pvar);
|
||||
delete_dynamic(&m_cond);
|
||||
delete_dynamic(&m_cursor);
|
||||
m_label.empty();
|
||||
}
|
||||
|
||||
|
@ -124,8 +126,6 @@ sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val)
|
|||
|
||||
if (p)
|
||||
{
|
||||
if (m_cond.elements == m_framesize)
|
||||
m_framesize += 1;
|
||||
p->name.str= name->str;
|
||||
p->name.length= name->length;
|
||||
p->val= val;
|
||||
|
@ -155,3 +155,39 @@ sp_pcontext::find_cond(LEX_STRING *name)
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
sp_pcontext::push_cursor(LEX_STRING *name)
|
||||
{
|
||||
LEX_STRING n;
|
||||
|
||||
n.str= name->str;
|
||||
n.length= name->length;
|
||||
insert_dynamic(&m_cursor, (gptr)&n);
|
||||
if (m_cursor.elements > m_cursmax)
|
||||
m_cursmax= m_cursor.elements;
|
||||
}
|
||||
|
||||
/*
|
||||
* See comment for find_pvar() above
|
||||
*/
|
||||
my_bool
|
||||
sp_pcontext::find_cursor(LEX_STRING *name, uint *poff)
|
||||
{
|
||||
uint i = m_cursor.elements;
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
LEX_STRING n;
|
||||
|
||||
get_dynamic(&m_cursor, (gptr)&n, i);
|
||||
if (my_strnncoll(system_charset_info,
|
||||
(const uchar *)name->str, name->length,
|
||||
(const uchar *)n.str, n.length) == 0)
|
||||
{
|
||||
*poff= i;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ typedef enum
|
|||
sp_param_inout
|
||||
} sp_param_mode_t;
|
||||
|
||||
typedef struct
|
||||
typedef struct sp_pvar
|
||||
{
|
||||
LEX_STRING name;
|
||||
enum enum_field_types type;
|
||||
|
@ -200,17 +200,41 @@ class sp_pcontext : public Sql_alloc
|
|||
return m_handlers;
|
||||
}
|
||||
|
||||
//
|
||||
// Cursors
|
||||
//
|
||||
|
||||
void
|
||||
push_cursor(LEX_STRING *name);
|
||||
|
||||
my_bool
|
||||
find_cursor(LEX_STRING *name, uint *poff);
|
||||
|
||||
inline void
|
||||
pop_cursor(uint num)
|
||||
{
|
||||
while (num--)
|
||||
pop_dynamic(&m_cursor);
|
||||
}
|
||||
|
||||
inline uint
|
||||
cursors()
|
||||
{
|
||||
return m_cursmax;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint m_params; // The number of parameters
|
||||
uint m_framesize; // The maximum framesize
|
||||
uint m_handlers; // The total number of handlers
|
||||
uint m_cursmax; // The maximum number of cursors
|
||||
|
||||
DYNAMIC_ARRAY m_pvar; // Parameters/variables
|
||||
DYNAMIC_ARRAY m_cond; // Conditions
|
||||
DYNAMIC_ARRAY m_cursor; // Cursors
|
||||
|
||||
List<sp_label_t> m_label; // The label list
|
||||
uint m_genlab; // Gen. label counter
|
||||
|
||||
}; // class sp_pcontext : public Sql_alloc
|
||||
|
||||
|
|
|
@ -23,16 +23,20 @@
|
|||
#endif
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "mysql.h"
|
||||
#include "sp_head.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)
|
||||
sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
|
||||
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
|
||||
m_hfound(-1), m_ccount(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_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *));
|
||||
m_saved.empty();
|
||||
}
|
||||
|
||||
|
@ -93,3 +97,141 @@ sp_rcontext::restore_variables(uint fp)
|
|||
while (i-- > fp)
|
||||
m_frame[i]= m_saved.pop();
|
||||
}
|
||||
|
||||
void
|
||||
sp_rcontext::push_cursor(LEX *lex)
|
||||
{
|
||||
m_cstack[m_ccount++]= new sp_cursor(lex);
|
||||
}
|
||||
|
||||
void
|
||||
sp_rcontext::pop_cursors(uint count)
|
||||
{
|
||||
while (count--)
|
||||
{
|
||||
delete m_cstack[--m_ccount];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* sp_cursor
|
||||
*
|
||||
*/
|
||||
|
||||
// We have split this in two to make it easy for sp_instr_copen
|
||||
// to reuse the sp_instr::exec_stmt() code.
|
||||
LEX *
|
||||
sp_cursor::pre_open(THD *thd)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (m_isopen)
|
||||
{
|
||||
send_error(thd, ER_SP_CURSOR_ALREADY_OPEN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bzero((char *)&m_mem_root, sizeof(m_mem_root));
|
||||
init_alloc_root(&m_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
||||
if ((m_prot= new Protocol_cursor(thd, &m_mem_root)) == NULL)
|
||||
return NULL;
|
||||
|
||||
m_oprot= thd->protocol; // Save the original protocol
|
||||
thd->protocol= m_prot;
|
||||
|
||||
m_ovio= thd->net.vio; // Prevent send_eof()
|
||||
thd->net.vio= 0;
|
||||
return m_lex;
|
||||
}
|
||||
|
||||
void
|
||||
sp_cursor::post_open(THD *thd, my_bool isopen)
|
||||
{
|
||||
thd->net.vio= m_ovio; // Restore the originals
|
||||
thd->protocol= m_oprot;
|
||||
m_isopen= isopen;
|
||||
m_current_row= m_prot->data;
|
||||
}
|
||||
|
||||
int
|
||||
sp_cursor::close(THD *thd)
|
||||
{
|
||||
if (! m_isopen)
|
||||
{
|
||||
send_error(thd, ER_SP_CURSOR_NOT_OPEN);
|
||||
return -1;
|
||||
}
|
||||
destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sp_cursor::destroy()
|
||||
{
|
||||
delete m_prot;
|
||||
m_prot= NULL;
|
||||
free_root(&m_mem_root, MYF(0));
|
||||
bzero((char *)&m_mem_root, sizeof(m_mem_root));
|
||||
m_isopen= FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
|
||||
{
|
||||
List_iterator_fast<struct sp_pvar> li(*vars);
|
||||
sp_pvar_t *pv;
|
||||
MYSQL_ROW row;
|
||||
uint fldcount;
|
||||
MYSQL_FIELD *fields= m_prot->fields;
|
||||
|
||||
if (! m_isopen)
|
||||
{
|
||||
send_error(thd, ER_SP_CURSOR_NOT_OPEN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (m_current_row == NULL)
|
||||
{
|
||||
send_error(thd, ER_SP_FETCH_NO_DATA);
|
||||
return -1;
|
||||
}
|
||||
|
||||
row= m_current_row->data;
|
||||
for (fldcount= 0 ; (pv= li++) ; fldcount++)
|
||||
{
|
||||
Item *it;
|
||||
const char *s;
|
||||
|
||||
if (fldcount >= m_prot->get_field_count())
|
||||
{
|
||||
send_error(thd, ER_SP_WRONG_NO_OF_FETCH_ARGS);
|
||||
return -1;
|
||||
}
|
||||
s= row[fldcount];
|
||||
switch (sp_map_result_type(pv->type))
|
||||
{
|
||||
case INT_RESULT:
|
||||
it= new Item_int(s);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
it= new Item_real(s, strlen(s));
|
||||
break;
|
||||
default:
|
||||
{
|
||||
uint len= strlen(s);
|
||||
it= new Item_string(thd->strmake(s, len), len, thd->db_charset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
thd->spcont->set_item(pv->offset, it);
|
||||
}
|
||||
if (fldcount < m_prot->get_field_count())
|
||||
{
|
||||
send_error(thd, ER_SP_WRONG_NO_OF_FETCH_ARGS);
|
||||
return -1;
|
||||
}
|
||||
m_current_row= m_current_row->next;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#endif
|
||||
|
||||
struct sp_cond_type;
|
||||
struct sp_cursor;
|
||||
struct sp_pvar;
|
||||
|
||||
#define SP_HANDLER_NONE 0
|
||||
#define SP_HANDLER_EXIT 1
|
||||
|
@ -44,7 +46,7 @@ class sp_rcontext : public Sql_alloc
|
|||
|
||||
public:
|
||||
|
||||
sp_rcontext(uint fsize, uint hmax);
|
||||
sp_rcontext(uint fsize, uint hmax, uint cmax);
|
||||
|
||||
~sp_rcontext()
|
||||
{
|
||||
|
@ -155,22 +157,93 @@ class sp_rcontext : public Sql_alloc
|
|||
void
|
||||
restore_variables(uint fp);
|
||||
|
||||
void
|
||||
push_cursor(LEX *lex);
|
||||
|
||||
void
|
||||
pop_cursors(uint count);
|
||||
|
||||
void
|
||||
pop_all_cursors()
|
||||
{
|
||||
pop_cursors(m_ccount);
|
||||
}
|
||||
|
||||
inline sp_cursor *
|
||||
get_cursor(uint i)
|
||||
{
|
||||
return m_cstack[i];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint m_count;
|
||||
uint m_fsize;
|
||||
Item **m_frame;
|
||||
int *m_outs;
|
||||
|
||||
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
|
||||
|
||||
sp_cursor **m_cstack;
|
||||
uint m_ccount;
|
||||
|
||||
}; // class sp_rcontext : public Sql_alloc
|
||||
|
||||
|
||||
class sp_cursor : public Sql_alloc
|
||||
{
|
||||
public:
|
||||
|
||||
sp_cursor(LEX *lex)
|
||||
: m_lex(lex), m_isopen(0), m_current_row(NULL)
|
||||
{
|
||||
/* Empty */
|
||||
}
|
||||
|
||||
virtual ~sp_cursor()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
// We have split this in two to make it easy for sp_instr_copen
|
||||
// to reuse the sp_instr::exec_stmt() code.
|
||||
LEX *
|
||||
pre_open(THD *thd);
|
||||
void
|
||||
post_open(THD *thd, my_bool isopen);
|
||||
|
||||
int
|
||||
close(THD *thd);
|
||||
|
||||
inline my_bool
|
||||
is_open()
|
||||
{
|
||||
return m_isopen;
|
||||
}
|
||||
|
||||
int
|
||||
fetch(THD *, List<struct sp_pvar> *vars);
|
||||
|
||||
private:
|
||||
|
||||
MEM_ROOT m_mem_root; // My own mem_root
|
||||
LEX *m_lex;
|
||||
Protocol_cursor *m_prot;
|
||||
my_bool m_isopen;
|
||||
Vio *m_ovio; // Original vio
|
||||
Protocol *m_oprot; // Original protcol
|
||||
MYSQL_ROWS *m_current_row;
|
||||
|
||||
void
|
||||
destroy();
|
||||
|
||||
}; // class sp_cursor : public Sql_alloc
|
||||
|
||||
#endif /* _SP_RCONTEXT_H_ */
|
||||
|
|
|
@ -348,6 +348,7 @@ public:
|
|||
enum olap_type olap;
|
||||
SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */
|
||||
List<Item> item_list; /* list of fields & expressions */
|
||||
List<Item> item_list_copy; /* For SPs */
|
||||
List<String> interval_list, use_index, *use_index_ptr,
|
||||
ignore_index, *ignore_index_ptr;
|
||||
/*
|
||||
|
|
155
sql/sql_yacc.yy
155
sql/sql_yacc.yy
|
@ -86,7 +86,8 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B)
|
|||
st_select_lex *select_lex;
|
||||
chooser_compare_func_creator boolfunc2creator;
|
||||
struct sp_cond_type *spcondtype;
|
||||
struct { int vars, conds, hndlrs; } spblock;
|
||||
struct { int vars, conds, hndlrs, curs; } spblock;
|
||||
struct st_lex *lex;
|
||||
}
|
||||
|
||||
%{
|
||||
|
@ -748,6 +749,7 @@ END_OF_INPUT
|
|||
%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 <lex> sp_cursor_stmt
|
||||
|
||||
%type <NONE>
|
||||
'-' '+' '*' '/' '%' '(' ')'
|
||||
|
@ -1189,13 +1191,14 @@ sp_proc_stmts:
|
|||
sp_decls:
|
||||
/* Empty */
|
||||
{
|
||||
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||
$$.vars= $$.conds= $$.hndlrs= $$.curs= 0;
|
||||
}
|
||||
| sp_decls sp_decl ';'
|
||||
{
|
||||
$$.vars= $1.vars + $2.vars;
|
||||
$$.conds= $1.conds + $2.conds;
|
||||
$$.hndlrs= $1.hndlrs + $2.hndlrs;
|
||||
$$.curs= $1.curs + $2.curs;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1222,12 +1225,12 @@ sp_decl:
|
|||
}
|
||||
}
|
||||
$$.vars= $2;
|
||||
$$.conds= $$.hndlrs= 0;
|
||||
$$.conds= $$.hndlrs= $$.curs= 0;
|
||||
}
|
||||
| DECLARE_SYM ident CONDITION_SYM FOR_SYM sp_cond
|
||||
{
|
||||
YYTHD->lex->spcont->push_cond(&$2, $5);
|
||||
$$.vars= $$.hndlrs= 0;
|
||||
$$.vars= $$.hndlrs= $$.curs= 0;
|
||||
$$.conds= 1;
|
||||
}
|
||||
| DECLARE_SYM sp_handler_type HANDLER_SYM FOR_SYM
|
||||
|
@ -1260,14 +1263,49 @@ sp_decl:
|
|||
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
|
||||
}
|
||||
lex->sphead->backpatch(hlab);
|
||||
$$.vars= $$.conds= 0;
|
||||
$$.vars= $$.conds= $$.curs= 0;
|
||||
$$.hndlrs= $6;
|
||||
}
|
||||
/* QQ Not yet
|
||||
| DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
sp_instr_cpush *i= new sp_instr_cpush(sp->instructions(), $5);
|
||||
|
||||
sp->add_instr(i);
|
||||
lex->spcont->push_cursor(&$2);
|
||||
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||
}*/
|
||||
$$.curs= 1;
|
||||
}
|
||||
;
|
||||
|
||||
sp_cursor_stmt:
|
||||
{
|
||||
Lex->sphead->reset_lex(YYTHD);
|
||||
|
||||
/* We use statement here just be able to get a better
|
||||
error message. Using 'select' works too, but will then
|
||||
result in a generic "syntax error" if a non-select
|
||||
statement is given. */
|
||||
}
|
||||
statement
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
|
||||
if (lex->sql_command != SQLCOM_SELECT)
|
||||
{
|
||||
send_error(YYTHD, ER_SP_BAD_CURSOR_QUERY);
|
||||
YYABORT;
|
||||
}
|
||||
if (lex->result)
|
||||
{
|
||||
send_error(YYTHD, ER_SP_BAD_CURSOR_SELECT);
|
||||
YYABORT;
|
||||
}
|
||||
lex->sp_lex_in_use= TRUE;
|
||||
$$= lex;
|
||||
lex->sphead->restore_lex(YYTHD);
|
||||
}
|
||||
;
|
||||
|
||||
sp_handler_type:
|
||||
|
@ -1506,11 +1544,96 @@ sp_proc_stmt:
|
|||
}
|
||||
}
|
||||
| OPEN_SYM ident
|
||||
{}
|
||||
| FETCH_SYM ident INTO select_var_list_init
|
||||
{}
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
uint offset;
|
||||
sp_instr_copen *i;
|
||||
|
||||
if (! lex->spcont->find_cursor(&$2, &offset))
|
||||
{
|
||||
net_printf(YYTHD, ER_SP_CURSOR_MISMATCH, $2.str);
|
||||
YYABORT;
|
||||
}
|
||||
i= new sp_instr_copen(sp->instructions(), offset);
|
||||
sp->add_instr(i);
|
||||
}
|
||||
| FETCH_SYM ident INTO
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
uint offset;
|
||||
sp_instr_cfetch *i;
|
||||
|
||||
if (! lex->spcont->find_cursor(&$2, &offset))
|
||||
{
|
||||
net_printf(YYTHD, ER_SP_CURSOR_MISMATCH, $2.str);
|
||||
YYABORT;
|
||||
}
|
||||
i= new sp_instr_cfetch(sp->instructions(), offset);
|
||||
sp->add_instr(i);
|
||||
}
|
||||
sp_fetch_list
|
||||
{ }
|
||||
| CLOSE_SYM ident
|
||||
{}
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
uint offset;
|
||||
sp_instr_cclose *i;
|
||||
|
||||
if (! lex->spcont->find_cursor(&$2, &offset))
|
||||
{
|
||||
net_printf(YYTHD, ER_SP_CURSOR_MISMATCH, $2.str);
|
||||
YYABORT;
|
||||
}
|
||||
i= new sp_instr_cclose(sp->instructions(), offset);
|
||||
sp->add_instr(i);
|
||||
}
|
||||
;
|
||||
|
||||
sp_fetch_list:
|
||||
ident
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
sp_pcontext *spc= lex->spcont;
|
||||
sp_pvar_t *spv;
|
||||
|
||||
if (!spc || !(spv = spc->find_pvar(&$1)))
|
||||
{
|
||||
net_printf(YYTHD, ER_SP_UNDECLARED_VAR, $1.str);
|
||||
YYABORT;
|
||||
}
|
||||
else
|
||||
{ /* An SP local variable */
|
||||
sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
|
||||
|
||||
i->add_to_varlist(spv);
|
||||
spv->isset= TRUE;
|
||||
}
|
||||
}
|
||||
|
|
||||
sp_fetch_list ',' ident
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
sp_pcontext *spc= lex->spcont;
|
||||
sp_pvar_t *spv;
|
||||
|
||||
if (!spc || !(spv = spc->find_pvar(&$3)))
|
||||
{
|
||||
net_printf(YYTHD, ER_SP_UNDECLARED_VAR, $3.str);
|
||||
YYABORT;
|
||||
}
|
||||
else
|
||||
{ /* An SP local variable */
|
||||
sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
|
||||
|
||||
i->add_to_varlist(spv);
|
||||
spv->isset= TRUE;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
sp_if:
|
||||
|
@ -1649,11 +1772,11 @@ sp_unlabeled_control:
|
|||
sp->backpatch(ctx->pop_label());
|
||||
ctx->pop_pvar($3.vars);
|
||||
ctx->pop_cond($3.conds);
|
||||
ctx->pop_cursor($3.curs);
|
||||
if ($3.hndlrs)
|
||||
{
|
||||
sp_instr_hpop *i= new sp_instr_hpop(sp->instructions(),$3.hndlrs);
|
||||
sp->add_instr(i);
|
||||
}
|
||||
sp->add_instr(new sp_instr_hpop(sp->instructions(),$3.hndlrs));
|
||||
if ($3.curs)
|
||||
sp->add_instr(new sp_instr_cpop(sp->instructions(), $3.curs));
|
||||
}
|
||||
| LOOP_SYM
|
||||
sp_proc_stmts END LOOP_SYM
|
||||
|
@ -4206,7 +4329,7 @@ select_var_ident:
|
|||
sp_pvar_t *t;
|
||||
if (!(t=lex->spcont->find_pvar(&$1)))
|
||||
{
|
||||
send_error(lex->thd, ER_SYNTAX_ERROR);
|
||||
send_error(lex->thd, ER_SP_UNDECLARED_VAR);
|
||||
YYABORT;
|
||||
}
|
||||
if (! lex->result)
|
||||
|
|
Loading…
Add table
Reference in a new issue