mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
Most of the groundwork for sprint task 729 (implement FUNCTIONs).
Expanded the mysql.proc table, reworked the find/create/drop functions completely, added new functions for FUNCTIONs (lotta functions here :), got rid of some unnecessary use of Item_strings while at it. Extended the parser correspondingly, and fiddled around a bit to make SP FUNCTIONs coexist with UDFs. Can now CREATE and DROP FUNCTIONs. Invoking yet to come...
This commit is contained in:
@@ -11,6 +11,8 @@ Summary of Not Yet Implemented:
|
|||||||
- SQL-99 COMMIT (related to BEGIN/END)
|
- SQL-99 COMMIT (related to BEGIN/END)
|
||||||
- DECLARE CURSOR ...
|
- DECLARE CURSOR ...
|
||||||
- FOR-loops (as it requires cursors)
|
- FOR-loops (as it requires cursors)
|
||||||
|
- CASCADE/RESTRICT for ALTER and DROP
|
||||||
|
- ALTER/DROP METHOD (as it implies User Defined Types)
|
||||||
|
|
||||||
|
|
||||||
Summary of what's implemented:
|
Summary of what's implemented:
|
||||||
@@ -66,15 +68,23 @@ List of what's implemented:
|
|||||||
databases.)
|
databases.)
|
||||||
|
|
||||||
|
|
||||||
Open questions:
|
Closed questions:
|
||||||
|
|
||||||
- What is the expected result when creating a procedure with a name that
|
- What is the expected result when creating a procedure with a name that
|
||||||
already exists? An error or overwrite?
|
already exists? An error or overwrite?
|
||||||
|
Answer: Error
|
||||||
|
|
||||||
- Do PROCEDUREs and FUNCTIONs share namespace or not? I think not, but the
|
- Do PROCEDUREs and FUNCTIONs share namespace or not? I think not, but the
|
||||||
we need to flag the type in the mysql.proc table and the name alone is
|
we need to flag the type in the mysql.proc table and the name alone is
|
||||||
not a unique key any more, or, we have separate tables.
|
not a unique key any more, or, we have separate tables.
|
||||||
(Unfortunately, mysql.func is already taken. Use "sfunc" and maybe even
|
(Unfortunately, mysql.func is already taken. Use "sfunc" and maybe even
|
||||||
rename "proc" into "sproc" while we still can, for consistency?)
|
rename "proc" into "sproc" while we still can, for consistency?)
|
||||||
|
Answer: Same tables, with an additional key-field for the type.
|
||||||
|
|
||||||
|
|
||||||
|
Open questions:
|
||||||
|
|
||||||
- SQL-99 variables and parameters are typed. For the present we don't do
|
- 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
|
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.
|
if we should keep it this way, or implement type checking. Possibly we
|
||||||
|
should have optional, uset-settable, type checking.
|
||||||
|
@@ -276,5 +276,5 @@
|
|||||||
#define ER_SP_LABEL_MISMATCH 1257
|
#define ER_SP_LABEL_MISMATCH 1257
|
||||||
#define ER_SP_UNINIT_VAR 1258
|
#define ER_SP_UNINIT_VAR 1258
|
||||||
#define ER_SP_BADSELECT 1259
|
#define ER_SP_BADSELECT 1259
|
||||||
#define ER_ERROR_MESSAGES 260
|
#define ER_SP_BADRETURN 1260
|
||||||
|
#define ER_ERROR_MESSAGES 261
|
||||||
|
@@ -251,8 +251,9 @@ if test ! -f $mdata/proc.frm
|
|||||||
then
|
then
|
||||||
c_p="$c_p CREATE TABLE proc ("
|
c_p="$c_p CREATE TABLE proc ("
|
||||||
c_p="$c_p name char(64) binary DEFAULT '' NOT NULL,"
|
c_p="$c_p name char(64) binary DEFAULT '' NOT NULL,"
|
||||||
|
c_p="$c_p type enum('function','procedure') NOT NULL,"
|
||||||
c_p="$c_p body blob DEFAULT '' NOT NULL,"
|
c_p="$c_p body blob DEFAULT '' NOT NULL,"
|
||||||
c_p="$c_p PRIMARY KEY (name)"
|
c_p="$c_p PRIMARY KEY (name,type)"
|
||||||
c_p="$c_p )"
|
c_p="$c_p )"
|
||||||
c_p="$c_p comment='Stored Procedures';"
|
c_p="$c_p comment='Stored Procedures';"
|
||||||
fi
|
fi
|
||||||
|
@@ -375,4 +375,20 @@ create table test.t2 select * from test.t1;
|
|||||||
insert into test.t2 values (concat(x, "2"), y+2);
|
insert into test.t2 values (concat(x, "2"), y+2);
|
||||||
end;
|
end;
|
||||||
drop procedure create_select;
|
drop procedure create_select;
|
||||||
|
create function foo returns real soname "foo.so";
|
||||||
|
Can't open shared library 'foo.so' (errno: 22 foo.so: cannot open shared object file: No such file or director)
|
||||||
|
create function e() returns double
|
||||||
|
return 2.7182818284590452354;
|
||||||
|
drop function e;
|
||||||
|
create function fac(n int unsigned) returns bigint unsigned
|
||||||
|
begin
|
||||||
|
declare f bigint unsigned;
|
||||||
|
set f = 1;
|
||||||
|
while n > 1 do
|
||||||
|
set f = f * n;
|
||||||
|
set n = n - 1;
|
||||||
|
end while;
|
||||||
|
return f;
|
||||||
|
end;
|
||||||
|
drop function fac;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
@@ -433,5 +433,32 @@ end|
|
|||||||
#drop table t2|
|
#drop table t2|
|
||||||
drop procedure create_select|
|
drop procedure create_select|
|
||||||
|
|
||||||
|
# Check that we get the right error, i.e. UDF declaration parses correctly,
|
||||||
|
# but foo.so doesn't exist.
|
||||||
|
--error 1126
|
||||||
|
create function foo returns real soname "foo.so"|
|
||||||
|
|
||||||
|
# A minimal, constant FUNCTION.
|
||||||
|
create function e() returns double
|
||||||
|
return 2.7182818284590452354|
|
||||||
|
|
||||||
|
drop function e|
|
||||||
|
|
||||||
|
|
||||||
|
# A function with flow control and a RETURN statement
|
||||||
|
create function fac(n int unsigned) returns bigint unsigned
|
||||||
|
begin
|
||||||
|
declare f bigint unsigned;
|
||||||
|
|
||||||
|
set f = 1;
|
||||||
|
while n > 1 do
|
||||||
|
set f = f * n;
|
||||||
|
set n = n - 1;
|
||||||
|
end while;
|
||||||
|
return f;
|
||||||
|
end|
|
||||||
|
|
||||||
|
drop function fac|
|
||||||
|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
@@ -312,8 +312,9 @@ then
|
|||||||
|
|
||||||
c_p="$c_p CREATE TABLE proc ("
|
c_p="$c_p CREATE TABLE proc ("
|
||||||
c_p="$c_p name char(64) binary DEFAULT '' NOT NULL,"
|
c_p="$c_p name char(64) binary DEFAULT '' NOT NULL,"
|
||||||
|
c_p="$c_p type enum('function','procedure') NOT NULL,"
|
||||||
c_p="$c_p body blob DEFAULT '' NOT NULL,"
|
c_p="$c_p body blob DEFAULT '' NOT NULL,"
|
||||||
c_p="$c_p PRIMARY KEY (name)"
|
c_p="$c_p PRIMARY KEY (name,type)"
|
||||||
c_p="$c_p )"
|
c_p="$c_p )"
|
||||||
c_p="$c_p comment='Stored Procedures';"
|
c_p="$c_p comment='Stored Procedures';"
|
||||||
fi
|
fi
|
||||||
|
@@ -175,7 +175,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "FOR", SYM(FOR_SYM),0,0},
|
{ "FOR", SYM(FOR_SYM),0,0},
|
||||||
{ "FULL", SYM(FULL),0,0},
|
{ "FULL", SYM(FULL),0,0},
|
||||||
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
|
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
|
||||||
{ "FUNCTION", SYM(UDF_SYM),0,0},
|
{ "FUNCTION", SYM(FUNCTION_SYM),0,0},
|
||||||
{ "GEOMETRY", SYM(GEOMETRY_SYM),0,0},
|
{ "GEOMETRY", SYM(GEOMETRY_SYM),0,0},
|
||||||
{ "GLOBAL", SYM(GLOBAL_SYM),0,0},
|
{ "GLOBAL", SYM(GLOBAL_SYM),0,0},
|
||||||
{ "GRANT", SYM(GRANT),0,0},
|
{ "GRANT", SYM(GRANT),0,0},
|
||||||
@@ -332,7 +332,8 @@ static SYMBOL symbols[] = {
|
|||||||
{ "USER_RESOURCES", SYM(RESOURCES),0,0},
|
{ "USER_RESOURCES", SYM(RESOURCES),0,0},
|
||||||
{ "RESTORE", SYM(RESTORE_SYM),0,0},
|
{ "RESTORE", SYM(RESTORE_SYM),0,0},
|
||||||
{ "RESTRICT", SYM(RESTRICT),0,0},
|
{ "RESTRICT", SYM(RESTRICT),0,0},
|
||||||
{ "RETURNS", SYM(UDF_RETURNS_SYM),0,0},
|
{ "RETURN", SYM(RETURN_SYM),0,0},
|
||||||
|
{ "RETURNS", SYM(RETURNS_SYM),0,0},
|
||||||
{ "REVOKE", SYM(REVOKE),0,0},
|
{ "REVOKE", SYM(REVOKE),0,0},
|
||||||
{ "RIGHT", SYM(RIGHT),0,0},
|
{ "RIGHT", SYM(RIGHT),0,0},
|
||||||
{ "RLIKE", SYM(REGEXP),0,0}, /* Like in mSQL2 */
|
{ "RLIKE", SYM(REGEXP),0,0}, /* Like in mSQL2 */
|
||||||
|
@@ -270,3 +270,4 @@ v/*
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -264,3 +264,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -272,3 +272,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -261,3 +261,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -266,3 +266,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -261,3 +261,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -271,3 +271,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -261,3 +261,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -263,3 +263,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -261,3 +261,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -263,3 +263,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -261,3 +261,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -263,3 +263,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -263,3 +263,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -265,3 +265,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -261,3 +261,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -265,3 +265,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -264,3 +264,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -257,3 +257,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -269,3 +269,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -262,3 +262,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -261,3 +261,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
@@ -266,3 +266,4 @@
|
|||||||
"End-label without match"
|
"End-label without match"
|
||||||
"Referring to uninitialized variable"
|
"Referring to uninitialized variable"
|
||||||
"SELECT in a stored procedure must have INTO"
|
"SELECT in a stored procedure must have INTO"
|
||||||
|
"RETURN is only allowed in a stored FUNCTION"
|
||||||
|
248
sql/sp.cc
248
sql/sp.cc
@@ -19,48 +19,158 @@
|
|||||||
#include "sp.h"
|
#include "sp.h"
|
||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
|
|
||||||
// Finds the SP 'name'. Currently this always reads from the database
|
/*
|
||||||
// and prepares (parse) it, but in the future it will first look in
|
*
|
||||||
// the in-memory cache for SPs. (And store newly prepared SPs there of
|
* DB storage of Stored PROCEDUREs and FUNCTIONs
|
||||||
// course.)
|
*
|
||||||
sp_head *
|
*/
|
||||||
sp_find_procedure(THD *thd, Item_string *iname)
|
|
||||||
|
static int
|
||||||
|
db_find_routine_aux(THD *thd, int type, char *name, uint namelen,
|
||||||
|
enum thr_lock_type ltype, TABLE **tablep)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("sp_find_procedure");
|
DBUG_ENTER("db_find_routine_aux");
|
||||||
extern int yyparse(void *thd);
|
DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
|
||||||
LEX *tmplex;
|
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
TABLE_LIST tables;
|
TABLE_LIST tables;
|
||||||
const char *defstr;
|
byte key[65]; // We know name is 64 and the enum is 1 byte
|
||||||
String *name;
|
uint keylen;
|
||||||
sp_head *sp = NULL;
|
int ret;
|
||||||
|
|
||||||
|
// Put the key together
|
||||||
|
keylen= namelen;
|
||||||
|
if (keylen > sizeof(key)-1)
|
||||||
|
keylen= sizeof(key)-1;
|
||||||
|
memcpy(key, name, keylen);
|
||||||
|
memset(key+keylen, (int)' ', sizeof(key)-1 - keylen); // Pad with space
|
||||||
|
key[sizeof(key)-1]= type;
|
||||||
|
keylen= sizeof(key);
|
||||||
|
|
||||||
name = iname->const_string();
|
|
||||||
DBUG_PRINT("enter", ("name: %*s", name->length(), name->c_ptr()));
|
|
||||||
memset(&tables, 0, sizeof(tables));
|
memset(&tables, 0, sizeof(tables));
|
||||||
tables.db= (char*)"mysql";
|
tables.db= (char*)"mysql";
|
||||||
tables.real_name= tables.alias= (char*)"proc";
|
tables.real_name= tables.alias= (char*)"proc";
|
||||||
if (! (table= open_ltable(thd, &tables, TL_READ)))
|
if (! (table= open_ltable(thd, &tables, ltype)))
|
||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
|
||||||
|
|
||||||
if (table->file->index_read_idx(table->record[0], 0,
|
if (table->file->index_read_idx(table->record[0], 0,
|
||||||
(byte*)name->c_ptr(), name->length(),
|
key, keylen,
|
||||||
HA_READ_KEY_EXACT))
|
HA_READ_KEY_EXACT))
|
||||||
goto done;
|
{
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(SP_KEY_NOT_FOUND);
|
||||||
|
}
|
||||||
|
*tablep= table;
|
||||||
|
|
||||||
if ((defstr= get_field(&thd->mem_root, table->field[1])) == NULL)
|
DBUG_RETURN(SP_OK);
|
||||||
goto done;
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("db_find_routine");
|
||||||
|
DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
|
||||||
|
extern int yyparse(void *thd);
|
||||||
|
LEX *tmplex;
|
||||||
|
TABLE *table;
|
||||||
|
const char *defstr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
// QQ Set up our own mem_root here???
|
// QQ Set up our own mem_root here???
|
||||||
|
ret= db_find_routine_aux(thd, type, name, namelen, TL_READ, &table);
|
||||||
|
if (ret != SP_OK)
|
||||||
|
goto done;
|
||||||
|
if ((defstr= get_field(&thd->mem_root, table->field[2])) == NULL)
|
||||||
|
{
|
||||||
|
ret= SP_GET_FIELD_FAILED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
|
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
|
||||||
if (yyparse(thd) || thd->is_fatal_error || tmplex->sphead == NULL)
|
if (yyparse(thd) || thd->is_fatal_error || tmplex->sphead == NULL)
|
||||||
goto done; // Error
|
ret= SP_PARSE_ERROR;
|
||||||
else
|
else
|
||||||
sp = tmplex->sphead;
|
*sphp= tmplex->sphead;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (table)
|
if (ret == SP_OK && table)
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
db_create_routine(THD *thd, int type,
|
||||||
|
char *name, uint namelen, char *def, uint deflen)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("db_create_routine");
|
||||||
|
DBUG_PRINT("enter", ("type: %d name: %*s def: %*s", type, namelen, name, deflen, def));
|
||||||
|
int ret;
|
||||||
|
TABLE *table;
|
||||||
|
TABLE_LIST tables;
|
||||||
|
|
||||||
|
memset(&tables, 0, sizeof(tables));
|
||||||
|
tables.db= (char*)"mysql";
|
||||||
|
tables.real_name= tables.alias= (char*)"proc";
|
||||||
|
|
||||||
|
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
||||||
|
ret= SP_OPEN_TABLE_FAILED;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
restore_record(table, 2); // Get default values for fields
|
||||||
|
|
||||||
|
table->field[0]->store(name, namelen, default_charset_info);
|
||||||
|
table->field[1]->store((longlong)type);
|
||||||
|
table->field[2]->store(def, deflen, default_charset_info);
|
||||||
|
|
||||||
|
if (table->file->write_row(table->record[0]))
|
||||||
|
ret= SP_WRITE_ROW_FAILED;
|
||||||
|
else
|
||||||
|
ret= SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == SP_OK && table)
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
db_drop_routine(THD *thd, int type, char *name, uint namelen)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("db_drop_routine");
|
||||||
|
DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
|
||||||
|
TABLE *table;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret= db_find_routine_aux(thd, type, name, namelen, TL_WRITE, &table);
|
||||||
|
if (ret == SP_OK)
|
||||||
|
{
|
||||||
|
if (table->file->delete_row(table->record[0]))
|
||||||
|
ret= SP_DELETE_ROW_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == SP_OK && table)
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* PROCEDURE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
sp_head *
|
||||||
|
sp_find_procedure(THD *thd, LEX_STRING *name)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_find_procedure");
|
||||||
|
sp_head *sp;
|
||||||
|
|
||||||
|
DBUG_PRINT("enter", ("name: %*s", name->length, name->str));
|
||||||
|
|
||||||
|
if (db_find_routine(thd, TYPE_ENUM_PROCEDURE,
|
||||||
|
name->str, name->length, &sp) != SP_OK)
|
||||||
|
sp= NULL;
|
||||||
|
|
||||||
DBUG_RETURN(sp);
|
DBUG_RETURN(sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,29 +179,10 @@ sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen)
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("sp_create_procedure");
|
DBUG_ENTER("sp_create_procedure");
|
||||||
DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def));
|
DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def));
|
||||||
int ret= 0;
|
int ret;
|
||||||
TABLE *table;
|
|
||||||
TABLE_LIST tables;
|
|
||||||
|
|
||||||
memset(&tables, 0, sizeof(tables));
|
ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen, def, deflen);
|
||||||
tables.db= (char*)"mysql";
|
|
||||||
tables.real_name= tables.alias= (char*)"proc";
|
|
||||||
/* Allow creation of procedures even if we can't open proc table */
|
|
||||||
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
|
||||||
{
|
|
||||||
ret= -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_record(table, 2); // Get default values for fields
|
|
||||||
|
|
||||||
table->field[0]->store(name, namelen, default_charset_info);
|
|
||||||
table->field[1]->store(def, deflen, default_charset_info);
|
|
||||||
|
|
||||||
ret= table->file->write_row(table->record[0]);
|
|
||||||
|
|
||||||
done:
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,26 +191,55 @@ sp_drop_procedure(THD *thd, char *name, uint namelen)
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("sp_drop_procedure");
|
DBUG_ENTER("sp_drop_procedure");
|
||||||
DBUG_PRINT("enter", ("name: %*s", namelen, name));
|
DBUG_PRINT("enter", ("name: %*s", namelen, name));
|
||||||
TABLE *table;
|
int ret;
|
||||||
TABLE_LIST tables;
|
|
||||||
|
|
||||||
tables.db= (char *)"mysql";
|
ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen);
|
||||||
tables.real_name= tables.alias= (char *)"proc";
|
|
||||||
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
|
||||||
goto err;
|
|
||||||
if (! table->file->index_read_idx(table->record[0], 0,
|
|
||||||
(byte *)name, namelen,
|
|
||||||
HA_READ_KEY_EXACT))
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
if ((error= table->file->delete_row(table->record[0])))
|
DBUG_RETURN(ret);
|
||||||
table->file->print_error(error, MYF(0));
|
}
|
||||||
}
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(0);
|
/*
|
||||||
|
*
|
||||||
err:
|
* FUNCTION
|
||||||
close_thread_tables(thd);
|
*
|
||||||
DBUG_RETURN(-1);
|
*/
|
||||||
|
|
||||||
|
sp_head *
|
||||||
|
sp_find_function(THD *thd, LEX_STRING *name)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_find_function_i");
|
||||||
|
sp_head *sp;
|
||||||
|
|
||||||
|
DBUG_PRINT("enter", ("name: %*s", name->length, name->str));
|
||||||
|
|
||||||
|
if (db_find_routine(thd, TYPE_ENUM_FUNCTION,
|
||||||
|
name->str, name->length, &sp) != SP_OK)
|
||||||
|
sp= NULL;
|
||||||
|
|
||||||
|
DBUG_RETURN(sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_create_function");
|
||||||
|
DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def));
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, name, namelen, def, deflen);
|
||||||
|
|
||||||
|
DBUG_RETURN(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sp_drop_function(THD *thd, char *name, uint namelen)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_drop_function");
|
||||||
|
DBUG_PRINT("enter", ("name: %*s", namelen, name));
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen);
|
||||||
|
|
||||||
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
19
sql/sp.h
19
sql/sp.h
@@ -18,11 +18,17 @@
|
|||||||
#ifndef _SP_H_
|
#ifndef _SP_H_
|
||||||
#define _SP_H_
|
#define _SP_H_
|
||||||
|
|
||||||
//
|
// Return codes from sp_create_* and sp_drop_*:
|
||||||
// Finds a stored procedure given its name. Returns NULL if not found.
|
#define SP_OK 0
|
||||||
//
|
#define SP_KEY_NOT_FOUND -1
|
||||||
|
#define SP_OPEN_TABLE_FAILED -2
|
||||||
|
#define SP_WRITE_ROW_FAILED -3
|
||||||
|
#define SP_DELETE_ROW_FAILED -4
|
||||||
|
#define SP_GET_FIELD_FAILED -5
|
||||||
|
#define SP_PARSE_ERROR -6
|
||||||
|
|
||||||
sp_head *
|
sp_head *
|
||||||
sp_find_procedure(THD *thd, Item_string *name);
|
sp_find_procedure(THD *thd, LEX_STRING *name);
|
||||||
|
|
||||||
int
|
int
|
||||||
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen);
|
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen);
|
||||||
@@ -30,15 +36,14 @@ sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen);
|
|||||||
int
|
int
|
||||||
sp_drop_procedure(THD *thd, char *name, uint namelen);
|
sp_drop_procedure(THD *thd, char *name, uint namelen);
|
||||||
|
|
||||||
#if 0
|
|
||||||
sp_head *
|
sp_head *
|
||||||
sp_find_function(THD *thd, Item_string *name);
|
sp_find_function(THD *thd, LEX_STRING *name);
|
||||||
|
|
||||||
int
|
int
|
||||||
sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen);
|
sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen);
|
||||||
|
|
||||||
int
|
int
|
||||||
sp_drop_function(THD *thd, char *name, uint namelen);
|
sp_drop_function(THD *thd, char *name, uint namelen);
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _SP_H_ */
|
#endif /* _SP_H_ */
|
||||||
|
@@ -102,11 +102,20 @@ sp_head::create(THD *thd)
|
|||||||
DBUG_ENTER("sp_head::create");
|
DBUG_ENTER("sp_head::create");
|
||||||
String *name= m_name->const_string();
|
String *name= m_name->const_string();
|
||||||
String *def= m_defstr->const_string();
|
String *def= m_defstr->const_string();
|
||||||
|
int ret;
|
||||||
|
|
||||||
DBUG_PRINT("info", ("name: %s def: %s", name->c_ptr(), def->c_ptr()));
|
DBUG_PRINT("info", ("type: %d name: %s def: %s",
|
||||||
DBUG_RETURN(sp_create_procedure(thd,
|
m_type, name->c_ptr(), def->c_ptr()));
|
||||||
name->c_ptr(), name->length(),
|
if (m_type == TYPE_ENUM_FUNCTION)
|
||||||
def->c_ptr(), def->length()));
|
ret= sp_create_function(thd,
|
||||||
|
name->c_ptr(), name->length(),
|
||||||
|
def->c_ptr(), def->length());
|
||||||
|
else
|
||||||
|
ret= sp_create_procedure(thd,
|
||||||
|
name->c_ptr(), name->length(),
|
||||||
|
def->c_ptr(), def->length());
|
||||||
|
|
||||||
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -127,7 +136,7 @@ sp_head::execute(THD *thd)
|
|||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
List_iterator_fast<Item> li(m_call_lex->value_list);
|
List_iterator_fast<Item> li(m_call_lex->value_list);
|
||||||
Item *it = li++; // Skip first one, it's the procedure name
|
Item *it;
|
||||||
|
|
||||||
nctx = new sp_rcontext(csize);
|
nctx = new sp_rcontext(csize);
|
||||||
if (! octx)
|
if (! octx)
|
||||||
@@ -184,7 +193,7 @@ sp_head::execute(THD *thd)
|
|||||||
if (ret == 0 && csize > 0)
|
if (ret == 0 && csize > 0)
|
||||||
{
|
{
|
||||||
List_iterator_fast<Item> li(m_call_lex->value_list);
|
List_iterator_fast<Item> li(m_call_lex->value_list);
|
||||||
Item *it = li++; // Skip first one, it's the procedure name
|
Item *it;
|
||||||
|
|
||||||
// Copy back all OUT or INOUT values to the previous frame, or
|
// Copy back all OUT or INOUT values to the previous frame, or
|
||||||
// set global user variables
|
// set global user variables
|
||||||
@@ -273,23 +282,18 @@ sp_head::restore_lex(THD *thd)
|
|||||||
// Collect some data from the sub statement lex.
|
// Collect some data from the sub statement lex.
|
||||||
if (thd->lex.sql_command == SQLCOM_CALL)
|
if (thd->lex.sql_command == SQLCOM_CALL)
|
||||||
{
|
{
|
||||||
// We know they are Item_strings (since we put them there ourselves)
|
|
||||||
// It would be slightly faster to keep the list sorted, but we need
|
// It would be slightly faster to keep the list sorted, but we need
|
||||||
// an "insert before" method to do that.
|
// an "insert before" method to do that.
|
||||||
Item_string *proc= static_cast<Item_string*>(thd->lex.value_list.head());
|
char *proc= thd->lex.udf.name.str;
|
||||||
String *snew= proc->val_str(NULL);
|
|
||||||
List_iterator_fast<Item_string> li(m_calls);
|
List_iterator_fast<char *> li(m_calls);
|
||||||
Item_string *it;
|
char **it;
|
||||||
|
|
||||||
while ((it= li++))
|
while ((it= li++))
|
||||||
{
|
if (strcasecmp(proc, *it) == 0)
|
||||||
String *sold= it->val_str(NULL);
|
|
||||||
|
|
||||||
if (stringcmp(snew, sold) == 0)
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (! it)
|
if (! it)
|
||||||
m_calls.push_back(proc);
|
m_calls.push_back(&proc);
|
||||||
|
|
||||||
}
|
}
|
||||||
// Merge used tables
|
// Merge used tables
|
||||||
|
@@ -24,6 +24,11 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Values for the type enum. This reflects the order of the enum declaration
|
||||||
|
// in the CREATE TABLE command.
|
||||||
|
#define TYPE_ENUM_FUNCTION 1
|
||||||
|
#define TYPE_ENUM_PROCEDURE 2
|
||||||
|
|
||||||
struct sp_label;
|
struct sp_label;
|
||||||
|
|
||||||
class sp_instr;
|
class sp_instr;
|
||||||
@@ -35,8 +40,10 @@ class sp_head : public Sql_alloc
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
|
||||||
|
enum enum_field_types m_returns; // For FUNCTIONs only
|
||||||
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
|
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
|
||||||
List<Item_string> m_calls; // Called procedures.
|
List<char *> m_calls; // Called procedures.
|
||||||
List<char *> m_tables; // Used tables.
|
List<char *> m_tables; // Used tables.
|
||||||
|
|
||||||
static void *operator new(size_t size)
|
static void *operator new(size_t size)
|
||||||
@@ -87,6 +94,15 @@ public:
|
|||||||
void
|
void
|
||||||
backpatch(struct sp_label *);
|
backpatch(struct sp_label *);
|
||||||
|
|
||||||
|
char *name(uint *lenp = 0) const
|
||||||
|
{
|
||||||
|
String *n= m_name->const_string();
|
||||||
|
|
||||||
|
if (lenp)
|
||||||
|
*lenp= n->length();
|
||||||
|
return n->c_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Item_string *m_name;
|
Item_string *m_name;
|
||||||
@@ -99,7 +115,7 @@ private:
|
|||||||
struct sp_label *lab;
|
struct sp_label *lab;
|
||||||
sp_instr *instr;
|
sp_instr *instr;
|
||||||
} bp_t;
|
} bp_t;
|
||||||
List<bp_t> m_backpatch; // Instructions needing backpaching
|
List<bp_t> m_backpatch; // Instructions needing backpatching
|
||||||
|
|
||||||
inline sp_instr *
|
inline sp_instr *
|
||||||
get_instr(uint i)
|
get_instr(uint i)
|
||||||
|
@@ -75,8 +75,8 @@ enum enum_sql_command {
|
|||||||
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
|
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
|
||||||
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
|
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
|
||||||
SQLCOM_HELP,
|
SQLCOM_HELP,
|
||||||
SQLCOM_CREATE_PROCEDURE, SQLCOM_CALL, SQLCOM_DROP_PROCEDURE,
|
SQLCOM_CREATE_PROCEDURE, SQLCOM_CALL,
|
||||||
SQLCOM_ALTER_PROCEDURE,
|
SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION,
|
||||||
|
|
||||||
/* This should be the last !!! */
|
/* This should be the last !!! */
|
||||||
SQLCOM_END
|
SQLCOM_END
|
||||||
|
112
sql/sql_parse.cc
112
sql/sql_parse.cc
@@ -2763,26 +2763,24 @@ mysql_execute_command(THD *thd)
|
|||||||
res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
|
res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SQLCOM_CREATE_FUNCTION:
|
case SQLCOM_CREATE_FUNCTION: // UDF function
|
||||||
if (check_access(thd,INSERT_ACL,"mysql",0,1))
|
{
|
||||||
break;
|
if (check_access(thd,INSERT_ACL,"mysql",0,1))
|
||||||
|
break;
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
if (!(res = mysql_create_function(thd,&lex->udf)))
|
sp_head *sph= sp_find_function(thd, &lex->udf.name);
|
||||||
send_ok(thd);
|
if (sph)
|
||||||
|
{
|
||||||
|
net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (!(res = mysql_create_function(thd,&lex->udf)))
|
||||||
|
send_ok(thd);
|
||||||
#else
|
#else
|
||||||
res= -1;
|
res= -1;
|
||||||
#endif
|
#endif
|
||||||
break;
|
|
||||||
case SQLCOM_DROP_FUNCTION:
|
|
||||||
if (check_access(thd,DELETE_ACL,"mysql",0,1))
|
|
||||||
break;
|
break;
|
||||||
#ifdef HAVE_DLOPEN
|
}
|
||||||
if (!(res = mysql_drop_function(thd,&lex->udf.name)))
|
|
||||||
send_ok(thd);
|
|
||||||
#else
|
|
||||||
res= -1;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case SQLCOM_REVOKE:
|
case SQLCOM_REVOKE:
|
||||||
case SQLCOM_GRANT:
|
case SQLCOM_GRANT:
|
||||||
{
|
{
|
||||||
@@ -2951,7 +2949,7 @@ mysql_execute_command(THD *thd)
|
|||||||
res= -1;
|
res= -1;
|
||||||
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
|
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
|
||||||
break;
|
break;
|
||||||
case SQLCOM_CREATE_PROCEDURE:
|
case SQLCOM_CREATE_PROCEDURE: // FUNCTION too (but not UDF!)
|
||||||
if (!lex->sphead)
|
if (!lex->sphead)
|
||||||
{
|
{
|
||||||
send_error(thd, ER_SP_NO_RECURSIVE_CREATE);
|
send_error(thd, ER_SP_NO_RECURSIVE_CREATE);
|
||||||
@@ -2959,22 +2957,35 @@ mysql_execute_command(THD *thd)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res= lex->sphead->create(thd);
|
uint namelen;
|
||||||
if (res != 0)
|
char *name= lex->sphead->name(&namelen);
|
||||||
|
udf_func *udf = find_udf(name, namelen);
|
||||||
|
|
||||||
|
if (udf)
|
||||||
{
|
{
|
||||||
send_error(thd, ER_SP_ALREADY_EXISTS);
|
net_printf(thd, ER_UDF_EXISTS, name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
res= lex->sphead->create(thd);
|
||||||
|
switch (res)
|
||||||
|
{
|
||||||
|
case SP_OK:
|
||||||
|
send_ok(thd);
|
||||||
|
break;
|
||||||
|
case SP_WRITE_ROW_FAILED:
|
||||||
|
send_error(thd, ER_SP_ALREADY_EXISTS);
|
||||||
|
goto error;
|
||||||
|
default:
|
||||||
|
send_error(thd, ER_SP_STORE_FAILED);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
send_ok(thd);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SQLCOM_CALL:
|
case SQLCOM_CALL:
|
||||||
{
|
{
|
||||||
Item_string *s;
|
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
|
|
||||||
s= (Item_string*)lex->value_list.head();
|
sp= sp_find_procedure(thd, &lex->udf.name);
|
||||||
sp= sp_find_procedure(thd, s);
|
|
||||||
if (! sp)
|
if (! sp)
|
||||||
{
|
{
|
||||||
send_error(thd, ER_SP_DOES_NOT_EXIST);
|
send_error(thd, ER_SP_DOES_NOT_EXIST);
|
||||||
@@ -3002,12 +3013,14 @@ mysql_execute_command(THD *thd)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SQLCOM_ALTER_PROCEDURE:
|
case SQLCOM_ALTER_PROCEDURE:
|
||||||
|
case SQLCOM_ALTER_FUNCTION:
|
||||||
{
|
{
|
||||||
Item_string *s;
|
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
|
|
||||||
s= (Item_string*)lex->value_list.head();
|
if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
|
||||||
sp= sp_find_procedure(thd, s);
|
sp= sp_find_procedure(thd, &lex->udf.name);
|
||||||
|
else
|
||||||
|
sp= sp_find_function(thd, &lex->udf.name);
|
||||||
if (! sp)
|
if (! sp)
|
||||||
{
|
{
|
||||||
send_error(thd, ER_SP_DOES_NOT_EXIST);
|
send_error(thd, ER_SP_DOES_NOT_EXIST);
|
||||||
@@ -3022,28 +3035,41 @@ mysql_execute_command(THD *thd)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SQLCOM_DROP_PROCEDURE:
|
case SQLCOM_DROP_PROCEDURE:
|
||||||
|
case SQLCOM_DROP_FUNCTION:
|
||||||
{
|
{
|
||||||
Item_string *s;
|
if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
|
||||||
sp_head *sp;
|
res= sp_drop_procedure(thd, lex->udf.name.str, lex->udf.name.length);
|
||||||
|
|
||||||
s = (Item_string*)lex->value_list.head();
|
|
||||||
sp = sp_find_procedure(thd, s);
|
|
||||||
if (! sp)
|
|
||||||
{
|
|
||||||
send_error(thd, ER_SP_DOES_NOT_EXIST);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
String *name = s->const_string();
|
res= sp_drop_function(thd, lex->udf.name.str, lex->udf.name.length);
|
||||||
|
#ifdef HAVE_DLOPEN
|
||||||
res= sp_drop_procedure(thd, name->c_ptr(), name->length());
|
if (res == SP_KEY_NOT_FOUND)
|
||||||
if (res != 0)
|
|
||||||
{
|
{
|
||||||
send_error(thd, ER_SP_DROP_FAILED);
|
udf_func *udf = find_udf(lex->udf.name.str, lex->udf.name.length);
|
||||||
goto error;
|
if (udf)
|
||||||
|
{
|
||||||
|
if (check_access(thd, DELETE_ACL, "mysql", 0, 1))
|
||||||
|
goto error;
|
||||||
|
if (!(res = mysql_drop_function(thd,&lex->udf.name)))
|
||||||
|
{
|
||||||
|
send_ok(thd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
switch (res)
|
||||||
|
{
|
||||||
|
case SP_OK:
|
||||||
send_ok(thd);
|
send_ok(thd);
|
||||||
|
break;
|
||||||
|
case SP_KEY_NOT_FOUND:
|
||||||
|
send_error(thd, ER_SP_DOES_NOT_EXIST);
|
||||||
|
goto error;
|
||||||
|
default:
|
||||||
|
send_error(thd, ER_SP_DROP_FAILED);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
124
sql/sql_yacc.yy
124
sql/sql_yacc.yy
@@ -366,9 +366,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token FUNC_ARG1
|
%token FUNC_ARG1
|
||||||
%token FUNC_ARG2
|
%token FUNC_ARG2
|
||||||
%token FUNC_ARG3
|
%token FUNC_ARG3
|
||||||
%token UDF_RETURNS_SYM
|
%token RETURN_SYM
|
||||||
|
%token RETURNS_SYM
|
||||||
%token UDF_SONAME_SYM
|
%token UDF_SONAME_SYM
|
||||||
%token UDF_SYM
|
%token FUNCTION_SYM
|
||||||
%token UNCOMMITTED_SYM
|
%token UNCOMMITTED_SYM
|
||||||
%token UNDERSCORE_CHARSET
|
%token UNDERSCORE_CHARSET
|
||||||
%token UNICODE_SYM
|
%token UNICODE_SYM
|
||||||
@@ -902,27 +903,23 @@ create:
|
|||||||
lex->name=$4.str;
|
lex->name=$4.str;
|
||||||
lex->create_info.options=$3;
|
lex->create_info.options=$3;
|
||||||
}
|
}
|
||||||
| CREATE udf_func_type UDF_SYM IDENT
|
| CREATE udf_func_type FUNCTION_SYM IDENT
|
||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
lex->sql_command = SQLCOM_CREATE_FUNCTION;
|
|
||||||
lex->udf.name = $4;
|
lex->udf.name = $4;
|
||||||
lex->udf.type= $2;
|
lex->udf.type= $2;
|
||||||
}
|
}
|
||||||
UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING
|
create_function_tail
|
||||||
{
|
{}
|
||||||
LEX *lex=Lex;
|
|
||||||
lex->udf.returns=(Item_result) $7;
|
|
||||||
lex->udf.dl=$9.str;
|
|
||||||
}
|
|
||||||
| CREATE PROCEDURE ident
|
| CREATE PROCEDURE ident
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
|
|
||||||
lex->spcont = new sp_pcontext();
|
lex->spcont= new sp_pcontext();
|
||||||
lex->sphead = new sp_head(&$3, lex);
|
lex->sphead= new sp_head(&$3, lex);
|
||||||
|
lex->sphead->m_type= TYPE_ENUM_PROCEDURE;
|
||||||
}
|
}
|
||||||
'(' sp_dparam_list ')'
|
'(' sp_pdparam_list ')'
|
||||||
{
|
{
|
||||||
Lex->spcont->set_params();
|
Lex->spcont->set_params();
|
||||||
}
|
}
|
||||||
@@ -932,15 +929,43 @@ create:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
create_function_tail:
|
||||||
|
RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING
|
||||||
|
{
|
||||||
|
LEX *lex=Lex;
|
||||||
|
lex->sql_command = SQLCOM_CREATE_FUNCTION;
|
||||||
|
lex->udf.returns=(Item_result) $2;
|
||||||
|
lex->udf.dl=$4.str;
|
||||||
|
}
|
||||||
|
| '('
|
||||||
|
{
|
||||||
|
LEX *lex= Lex;
|
||||||
|
|
||||||
|
lex->sql_command = SQLCOM_CREATE_PROCEDURE;
|
||||||
|
lex->spcont= new sp_pcontext();
|
||||||
|
lex->sphead= new sp_head(&lex->udf.name, lex);
|
||||||
|
lex->sphead->m_type= TYPE_ENUM_FUNCTION;
|
||||||
|
}
|
||||||
|
sp_fdparam_list ')'
|
||||||
|
{
|
||||||
|
Lex->spcont->set_params();
|
||||||
|
}
|
||||||
|
RETURNS_SYM type
|
||||||
|
{
|
||||||
|
Lex->sphead->m_returns= (enum enum_field_types)$7;
|
||||||
|
}
|
||||||
|
sp_proc_stmt
|
||||||
|
{}
|
||||||
|
;
|
||||||
|
|
||||||
call:
|
call:
|
||||||
CALL_SYM ident
|
CALL_SYM ident
|
||||||
{
|
{
|
||||||
LEX *lex = Lex;
|
LEX *lex = Lex;
|
||||||
|
|
||||||
lex->sql_command= SQLCOM_CALL;
|
lex->sql_command= SQLCOM_CALL;
|
||||||
|
lex->udf.name= $2;
|
||||||
lex->value_list.empty();
|
lex->value_list.empty();
|
||||||
lex->value_list.push_back(
|
|
||||||
(Item*)new Item_string($2.str, $2.length, default_charset_info));
|
|
||||||
}
|
}
|
||||||
'(' sp_cparam_list ')' {}
|
'(' sp_cparam_list ')' {}
|
||||||
;
|
;
|
||||||
@@ -962,18 +987,36 @@ sp_cparams:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/* SP parameter declaration list */
|
/* Stored FUNCTION parameter declaration list */
|
||||||
sp_dparam_list:
|
sp_fdparam_list:
|
||||||
/* Empty */
|
/* Empty */
|
||||||
| sp_dparams
|
| sp_fdparams
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_dparams:
|
sp_fdparams:
|
||||||
sp_dparams ',' sp_dparam
|
sp_fdparams ',' sp_fdparam
|
||||||
| sp_dparam
|
| sp_fdparam
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_dparam:
|
sp_fdparam:
|
||||||
|
ident type sp_opt_locator
|
||||||
|
{
|
||||||
|
Lex->spcont->push(&$1, (enum enum_field_types)$2, sp_param_in);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Stored PROCEDURE parameter declaration list */
|
||||||
|
sp_pdparam_list:
|
||||||
|
/* Empty */
|
||||||
|
| sp_pdparams
|
||||||
|
;
|
||||||
|
|
||||||
|
sp_pdparams:
|
||||||
|
sp_pdparams ',' sp_pdparam
|
||||||
|
| sp_pdparam
|
||||||
|
;
|
||||||
|
|
||||||
|
sp_pdparam:
|
||||||
sp_opt_inout ident type sp_opt_locator
|
sp_opt_inout ident type sp_opt_locator
|
||||||
{
|
{
|
||||||
Lex->spcont->push(&$2,
|
Lex->spcont->push(&$2,
|
||||||
@@ -1068,6 +1111,20 @@ sp_proc_stmt:
|
|||||||
lex->sphead->restore_lex(YYTHD);
|
lex->sphead->restore_lex(YYTHD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
| RETURN_SYM expr
|
||||||
|
{
|
||||||
|
LEX *lex= Lex;
|
||||||
|
|
||||||
|
if (lex->sphead->m_type == TYPE_ENUM_PROCEDURE)
|
||||||
|
{
|
||||||
|
send_error(YYTHD, ER_SP_BADRETURN);
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* QQ nothing yet */
|
||||||
|
}
|
||||||
|
}
|
||||||
| IF sp_if END IF {}
|
| IF sp_if END IF {}
|
||||||
| CASE_SYM WHEN_SYM
|
| CASE_SYM WHEN_SYM
|
||||||
{
|
{
|
||||||
@@ -1886,7 +1943,7 @@ alter:
|
|||||||
lex->sql_command=SQLCOM_ALTER_DB;
|
lex->sql_command=SQLCOM_ALTER_DB;
|
||||||
lex->name=$3.str;
|
lex->name=$3.str;
|
||||||
}
|
}
|
||||||
| ALTER PROCEDURE opt_specific ident
|
| ALTER PROCEDURE ident
|
||||||
/* QQ Characteristics missing for now */
|
/* QQ Characteristics missing for now */
|
||||||
opt_restrict
|
opt_restrict
|
||||||
{
|
{
|
||||||
@@ -1895,18 +1952,10 @@ alter:
|
|||||||
/* This is essensially an no-op right now, since we haven't
|
/* This is essensially an no-op right now, since we haven't
|
||||||
put the characteristics in yet. */
|
put the characteristics in yet. */
|
||||||
lex->sql_command= SQLCOM_ALTER_PROCEDURE;
|
lex->sql_command= SQLCOM_ALTER_PROCEDURE;
|
||||||
lex->value_list.empty();
|
lex->udf.name= $3;
|
||||||
lex->value_list.push_back(
|
|
||||||
(Item*)new Item_string($4.str, $4.length, default_charset_info));
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_specific:
|
|
||||||
/* Empty */
|
|
||||||
|
|
|
||||||
SPECIFIC_SYM
|
|
||||||
;
|
|
||||||
|
|
||||||
alter_list:
|
alter_list:
|
||||||
| alter_list_item
|
| alter_list_item
|
||||||
| alter_list ',' alter_list_item;
|
| alter_list ',' alter_list_item;
|
||||||
@@ -3540,23 +3589,20 @@ drop:
|
|||||||
lex->drop_if_exists=$3;
|
lex->drop_if_exists=$3;
|
||||||
lex->name=$4.str;
|
lex->name=$4.str;
|
||||||
}
|
}
|
||||||
| DROP UDF_SYM IDENT
|
| DROP FUNCTION_SYM IDENT opt_restrict
|
||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
lex->sql_command = SQLCOM_DROP_FUNCTION;
|
lex->sql_command = SQLCOM_DROP_FUNCTION;
|
||||||
lex->udf.name = $3;
|
lex->udf.name= $3;
|
||||||
}
|
}
|
||||||
| DROP PROCEDURE ident opt_restrict
|
| DROP PROCEDURE ident opt_restrict
|
||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
lex->sql_command = SQLCOM_DROP_PROCEDURE;
|
lex->sql_command = SQLCOM_DROP_PROCEDURE;
|
||||||
lex->value_list.empty();
|
lex->udf.name= $3;
|
||||||
lex->value_list.push_back(
|
|
||||||
(Item*)new Item_string($3.str, $3.length, default_charset_info));
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
table_list:
|
table_list:
|
||||||
table_name
|
table_name
|
||||||
| table_list ',' table_name;
|
| table_list ',' table_name;
|
||||||
@@ -4583,7 +4629,7 @@ keyword:
|
|||||||
| TIMESTAMP {}
|
| TIMESTAMP {}
|
||||||
| TIME_SYM {}
|
| TIME_SYM {}
|
||||||
| TYPE_SYM {}
|
| TYPE_SYM {}
|
||||||
| UDF_SYM {}
|
| FUNCTION_SYM {}
|
||||||
| UNCOMMITTED_SYM {}
|
| UNCOMMITTED_SYM {}
|
||||||
| UNICODE_SYM {}
|
| UNICODE_SYM {}
|
||||||
| USE_FRM {}
|
| USE_FRM {}
|
||||||
|
Reference in New Issue
Block a user