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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
c4b76c26
Commit
c4b76c26
authored
Mar 03, 2003
by
pem@mysql.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New FUNCTION documentation, and a minor test case modification.
parent
8049daf2
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
151 additions
and
105 deletions
+151
-105
Docs/sp-imp-spec.txt
Docs/sp-imp-spec.txt
+61
-3
Docs/sp-implemented.txt
Docs/sp-implemented.txt
+19
-6
mysql-test/r/sp.result
mysql-test/r/sp.result
+42
-54
mysql-test/t/sp.test
mysql-test/t/sp.test
+29
-42
No files found.
Docs/sp-imp-spec.txt
View file @
c4b76c26
...
...
@@ -172,8 +172,9 @@ calling a PROCEDURE.
with the addition that a FUNCTION has a return type and a RETURN
statement, but no OUT or INOUT parameters.
[QQ - More details here; sp_head needs a result slot and a type flag
indicating if it's a function or procedure]
The main difference during parsing is that we store the result type
in the sp_head. However, there are big differences when it comes to
invoking a FUNCTION. (See below.)
- Storing, caching, dropping...
...
...
@@ -273,7 +274,64 @@ calling a PROCEDURE.
So, stored functions must be handled in a simpilar way, and as a
consequence, UDFs and functions must not have the same name.
[QQ - Details of how function calls works here]
- Detecting and parsing a FUNCTION invokation
The existance of UDFs are checked during the lexical analysis (in
sql_lex.cc:find_keyword()). This has the drawback that they must
exist before they are refered to, which was ok before SPs existed,
but then it becomes a problem. The first implementation of SP FUNCTIONs
will work the same way, but this should be fixed a.s.a.p. (This will
required some reworking of the way UDFs are handled, which is why it's
not done from the start.)
For the time being, a FUNCTION is detected the same way, and returns
the token SP_FUNC. During the parsing we only check for the *existance*
of the function, we don't parse it, since wa can't call the parser
recursively.
When encountering a SP_FUNC with parameters in the expression parser,
an instance of the new Item_func_sp class is created. Unlike UDFs, we
don't have different classes for different return types, since we at
this point don't know the type.
- Collecting FUNCTIONs to invoke
A FUNCTION differs from a PROCEDURE in one important aspect: Whereas a
PROCEDURE is CALLed as statement by itself, a FUNCTION is invoked
"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
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
if the query is a select, so it doesn't work (and we can't exclude this
table easily; since a priviledged used might in fact want to search
the proc table).
Another solution would of course be to allow the opening and closing
of the mysql.proc table during a query execution, but this it not
possible at the present.
So, the solution is to collect the names of the refered FUNCTIONs during
parsing in the lex.
Then, before doing anything else in mysql_execute_command(), read all
functions from the database an keep them in the THD, where the function
sp_find_function() can find them during the execution.
Note: Even when a global in-memory cache is implemented, we must still
make sure that the functions are indeed read and cached at this point.
The code that read and cache functions from the database must also be
invoked recursively for each read FUNCTION to make sure we have *all* the
functions we need.
In the absence of the real in-memory cache for SPs, a temporary solution
has been implemented with a per-THD cache for just FUNCTIONs. This is
handled by the functions
void sp_add_fun_to_lex(LEX *lex, LEX_STRING fun);
void sp_merge_funs(LEX *dst, LEX *src);
int sp_cache_functions(THD *thd, LEX *lex);
void sp_clear_function_cache(THD *thd);
in sp.cc.
- Parsing DROP PROCEDURE/FUNCTION
...
...
Docs/sp-implemented.txt
View file @
c4b76c26
...
...
@@ -3,7 +3,6 @@ Stored Procedures implemented 2003-02-02:
Summary of Not Yet Implemented:
- FUNCTIONs
- Routine characteristics
- External languages
- Access control
...
...
@@ -26,14 +25,14 @@ Summary of what's implemented:
List of what's implemented:
- CREATE PROCEDURE name ( args ) body
- CREATE PROCEDURE
|FUNCTION
name ( args ) body
No routine characteristics yet.
- ALTER PROCEDURE name ...
- ALTER PROCEDURE
|FUNCTION
name ...
Is parsed, but a no-op (as there are no characteristics implemented yet).
CASCADE/RESTRICT is not implemented (and CASCADE probably will not be).
- DROP PROCEDURE name
- DROP PROCEDURE
|FUNCTION
name
CASCADE/RESTRICT is not implemented (and CASCADE probably will not be).
- CALL name (args)
...
...
@@ -45,7 +44,7 @@ List of what's implemented:
will either generate an error message, or it might even work to
call all procedures from the top-level.
- Procedure body:
-
Function/
Procedure body:
- BEGIN/END
Is parsed, but not the real thing with (optional) transaction
control, it only serves as block syntax for multiple statements (and
...
...
@@ -82,9 +81,23 @@ Closed questions:
Answer: Same tables, with an additional key-field for the type.
Open questions:
Open questions
/issues
:
- SQL-99 variables and parameters are typed. For the present we don't do
any type checking, since this is the way MySQL works. I still don't know
if we should keep it this way, or implement type checking. Possibly we
should have optional, uset-settable, type checking.
- FUNCTIONs do not work correctly in all circumstances yet.
For instance a function like:
create function s() returns int
begin
declare s int;
select sum(test.t.y) into s from test.t;
return s;
end
do not work. Invoking this in queries like "SELECT * FROM t2 WHERE x = s()"
will make things very complicated. And, in fact, even "SET @s=s()" and
"SELECT s()" fail, although the exact reasons in these cases are a bit
obscure; part of the problem might be the way the lex structure is
bit-copied (a not completely sound thing to do).
mysql-test/r/sp.result
View file @
c4b76c26
...
...
@@ -277,59 +277,6 @@ h1 1
h? 17
delete from t1;
drop procedure h;
drop table if exists fac;
create table fac (n int unsigned not null primary key, f bigint unsigned);
create procedure ifac(n int unsigned)
begin
declare i int unsigned;
set i = 1;
if n > 20 then
set n = 20;
end if;
while i <= n do
begin
declare f bigint unsigned;
set f = 0; # Temp. fix, this should not be needed in the future.
call fac(i, f);
insert into test.fac values (i, f);
set i = i + 1;
end;
end while;
end;
create procedure fac(n int unsigned, out f bigint unsigned)
begin
set f = 1;
while n > 1 do
set f = f * n;
set n = n - 1;
end while;
end;
call ifac(20);
select * from fac;
n f
1 1
2 2
3 6
4 24
5 120
6 720
7 5040
8 40320
9 362880
10 3628800
11 39916800
12 479001600
13 6227020800
14 87178291200
15 1307674368000
16 20922789888000
17 355687428096000
18 6402373705728000
19 121645100408832000
20 2432902008176640000
drop table fac;
drop procedure ifac;
drop procedure fac;
create procedure into_test(x char(16), y int)
begin
insert into test.t1 values (x, y);
...
...
@@ -441,7 +388,48 @@ drop function e;
drop function inc;
drop function mul;
drop function append;
drop function fac;
drop function fun;
drop table if exists fac;
create table fac (n int unsigned not null primary key, f bigint unsigned);
create procedure ifac(n int unsigned)
begin
declare i int unsigned;
set i = 1;
if n > 20 then
set n = 20; # bigint overflow otherwise
end if;
while i <= n do
begin
insert into test.fac values (i, fac(i));
set i = i + 1;
end;
end while;
end;
call ifac(20);
select * from fac;
n f
1 1
2 2
3 6
4 24
5 120
6 720
7 5040
8 40320
9 362880
10 3628800
11 39916800
12 479001600
13 6227020800
14 87178291200
15 1307674368000
16 20922789888000
17 355687428096000
18 6402373705728000
19 121645100408832000
20 2432902008176640000
drop table fac;
drop procedure ifac;
drop function fac;
drop table t1;
drop table t2;
mysql-test/t/sp.test
View file @
c4b76c26
...
...
@@ -325,47 +325,6 @@ delete from t1|
drop
procedure
h
|
# A "real" procedure example
--
disable_warnings
drop
table
if
exists
fac
|
--
enable_warnings
create
table
fac
(
n
int
unsigned
not
null
primary
key
,
f
bigint
unsigned
)
|
create
procedure
ifac
(
n
int
unsigned
)
begin
declare
i
int
unsigned
;
set
i
=
1
;
if
n
>
20
then
set
n
=
20
;
end
if
;
while
i
<=
n
do
begin
declare
f
bigint
unsigned
;
set
f
=
0
;
# Temp. fix, this should not be needed in the future.
call
fac
(
i
,
f
);
insert
into
test
.
fac
values
(
i
,
f
);
set
i
=
i
+
1
;
end
;
end
while
;
end
|
create
procedure
fac
(
n
int
unsigned
,
out
f
bigint
unsigned
)
begin
set
f
=
1
;
while
n
>
1
do
set
f
=
f
*
n
;
set
n
=
n
-
1
;
end
while
;
end
|
call
ifac
(
20
)
|
select
*
from
fac
|
drop
table
fac
|
drop
procedure
ifac
|
drop
procedure
fac
|
# SELECT INTO local variables
create
procedure
into_test
(
x
char
(
16
),
y
int
)
begin
...
...
@@ -510,9 +469,37 @@ drop function e|
drop
function
inc
|
drop
function
mul
|
drop
function
append
|
drop
function
fac
|
drop
function
fun
|
# A "real" procedure and function example
--
disable_warnings
drop
table
if
exists
fac
|
--
enable_warnings
create
table
fac
(
n
int
unsigned
not
null
primary
key
,
f
bigint
unsigned
)
|
create
procedure
ifac
(
n
int
unsigned
)
begin
declare
i
int
unsigned
;
set
i
=
1
;
if
n
>
20
then
set
n
=
20
;
# bigint overflow otherwise
end
if
;
while
i
<=
n
do
begin
insert
into
test
.
fac
values
(
i
,
fac
(
i
));
set
i
=
i
+
1
;
end
;
end
while
;
end
|
call
ifac
(
20
)
|
select
*
from
fac
|
drop
table
fac
|
drop
procedure
ifac
|
drop
function
fac
|
delimiter
;
|
drop
table
t1
;
drop
table
t2
;
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