Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
ed1b5c59
Commit
ed1b5c59
authored
Oct 10, 2003
by
pem@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge mysql.com:/usr/local/bk/mysql-5.0
into mysql.com:/home/pem/work/mysql-5.0
parents
311964f5
689bb84f
Changes
42
Hide whitespace changes
Inline
Side-by-side
Showing
42 changed files
with
1290 additions
and
71 deletions
+1290
-71
Docs/sp-imp-spec.txt
Docs/sp-imp-spec.txt
+142
-6
Docs/sp-implemented.txt
Docs/sp-implemented.txt
+7
-2
include/mysqld_error.h
include/mysqld_error.h
+9
-1
libmysqld/Makefile.am
libmysqld/Makefile.am
+1
-1
mysql-test/r/sp-error.result
mysql-test/r/sp-error.result
+82
-0
mysql-test/r/sp.result
mysql-test/r/sp.result
+27
-0
mysql-test/t/sp-error.test
mysql-test/t/sp-error.test
+106
-0
mysql-test/t/sp.test
mysql-test/t/sp.test
+31
-0
sql/protocol.cc
sql/protocol.cc
+0
-9
sql/protocol.h
sql/protocol.h
+3
-5
sql/protocol_cursor.cc
sql/protocol_cursor.cc
+7
-5
sql/share/czech/errmsg.txt
sql/share/czech/errmsg.txt
+8
-0
sql/share/danish/errmsg.txt
sql/share/danish/errmsg.txt
+8
-0
sql/share/dutch/errmsg.txt
sql/share/dutch/errmsg.txt
+8
-0
sql/share/english/errmsg.txt
sql/share/english/errmsg.txt
+8
-0
sql/share/estonian/errmsg.txt
sql/share/estonian/errmsg.txt
+8
-0
sql/share/french/errmsg.txt
sql/share/french/errmsg.txt
+8
-0
sql/share/german/errmsg.txt
sql/share/german/errmsg.txt
+8
-0
sql/share/greek/errmsg.txt
sql/share/greek/errmsg.txt
+8
-0
sql/share/hungarian/errmsg.txt
sql/share/hungarian/errmsg.txt
+8
-0
sql/share/italian/errmsg.txt
sql/share/italian/errmsg.txt
+8
-0
sql/share/japanese/errmsg.txt
sql/share/japanese/errmsg.txt
+8
-0
sql/share/korean/errmsg.txt
sql/share/korean/errmsg.txt
+8
-0
sql/share/norwegian-ny/errmsg.txt
sql/share/norwegian-ny/errmsg.txt
+8
-0
sql/share/norwegian/errmsg.txt
sql/share/norwegian/errmsg.txt
+8
-0
sql/share/polish/errmsg.txt
sql/share/polish/errmsg.txt
+8
-0
sql/share/portuguese/errmsg.txt
sql/share/portuguese/errmsg.txt
+8
-0
sql/share/romanian/errmsg.txt
sql/share/romanian/errmsg.txt
+8
-0
sql/share/russian/errmsg.txt
sql/share/russian/errmsg.txt
+8
-0
sql/share/serbian/errmsg.txt
sql/share/serbian/errmsg.txt
+8
-0
sql/share/slovak/errmsg.txt
sql/share/slovak/errmsg.txt
+8
-0
sql/share/spanish/errmsg.txt
sql/share/spanish/errmsg.txt
+8
-0
sql/share/swedish/errmsg.txt
sql/share/swedish/errmsg.txt
+8
-0
sql/share/ukrainian/errmsg.txt
sql/share/ukrainian/errmsg.txt
+8
-0
sql/sp_head.cc
sql/sp_head.cc
+139
-14
sql/sp_head.h
sql/sp_head.h
+127
-2
sql/sp_pcontext.cc
sql/sp_pcontext.cc
+39
-3
sql/sp_pcontext.h
sql/sp_pcontext.h
+26
-2
sql/sp_rcontext.cc
sql/sp_rcontext.cc
+144
-2
sql/sp_rcontext.h
sql/sp_rcontext.h
+76
-3
sql/sql_lex.h
sql/sql_lex.h
+1
-0
sql/sql_yacc.yy
sql/sql_yacc.yy
+139
-16
No files found.
Docs/sp-imp-spec.txt
View file @
ed1b5c59
...
...
@@ -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 thre
e
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 in
t
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 invo
k
ation
- Detecting and parsing a FUNCTION invo
c
ation
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 invo
k
ation; the server requires that all tables used are
point of invo
c
ation; 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
...
...
Docs/sp-implemented.txt
View file @
ed1b5c59
...
...
@@ -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:
...
...
include/mysqld_error.h
View file @
ed1b5c59
...
...
@@ -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
libmysqld/Makefile.am
View file @
ed1b5c59
...
...
@@ -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)
...
...
mysql-test/r/sp-error.result
View file @
ed1b5c59
...
...
@@ -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;
mysql-test/r/sp.result
View file @
ed1b5c59
...
...
@@ -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;
...
...
mysql-test/t/sp-error.test
View file @
ed1b5c59
...
...
@@ -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
;
|
mysql-test/t/sp.test
View file @
ed1b5c59
...
...
@@ -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
;
...
...
sql/protocol.cc
View file @
ed1b5c59
...
...
@@ -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
sql/protocol.h
View file @
ed1b5c59
...
...
@@ -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
);
...
...
sql/protocol_cursor.cc
View file @
ed1b5c59
...
...
@@ -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
;
}
sql/share/czech/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/danish/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/dutch/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/english/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/estonian/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/french/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/german/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/greek/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/hungarian/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/italian/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/japanese/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/korean/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/norwegian-ny/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/norwegian/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/polish/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/portuguese/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/romanian/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/russian/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/serbian/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/slovak/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/spanish/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/swedish/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/share/ukrainian/errmsg.txt
View file @
ed1b5c59
...
...
@@ -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"
sql/sp_head.cc
View file @
ed1b5c59
...
...
@@ -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
,
h
max
);
nctx
=
new
sp_rcontext
(
csize
,
hmax
,
c
max
);
if
(
!
octx
)
{
// Create a temporary old context
octx
=
new
sp_rcontext
(
csize
,
h
max
);
tmp_octx
=
TRUE
;
octx
=
new
sp_rcontext
(
csize
,
hmax
,
c
max
);
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
);
}
sql/sp_head.h
View file @
ed1b5c59
...
...
@@ -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_ */
sql/sp_pcontext.cc
View file @
ed1b5c59
...
...
@@ -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
;
}
sql/sp_pcontext.h
View file @
ed1b5c59
...
...
@@ -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
...
...
sql/sp_rcontext.cc
View file @
ed1b5c59
...
...
@@ -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
;
}
sql/sp_rcontext.h
View file @
ed1b5c59
...
...
@@ -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_ */
sql/sql_lex.h
View file @
ed1b5c59
...
...
@@ -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
;
/*
...
...
sql/sql_yacc.yy
View file @
ed1b5c59
...
...
@@ -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;
}
%{
...
...
@@ -749,6 +750,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>
'-' '+' '*' '/' '%' '(' ')'
...
...
@@ -1190,13 +1192,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;
}
;
...
...
@@ -1223,12 +1226,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
...
...
@@ -1261,14 +1264,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:
...
...
@@ -1507,11 +1545,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:
...
...
@@ -1650,11 +1773,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
...
...
@@ -4240,7 +4363,7 @@ select_var_ident:
sp_pvar_t *t;
if (!(t=lex->spcont->find_pvar(&$1)))
{
send_error(lex->thd, ER_S
YNTAX_ERRO
R);
send_error(lex->thd, ER_S
P_UNDECLARED_VA
R);
YYABORT;
}
if (! lex->result)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment