From 7a20e5282e6048c3ef33f1e1bc049aff7ad1a3b8 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Fri, 12 Dec 2003 14:05:29 +0100 Subject: [PATCH] In order to make ALTER PROCEDURE|FUNCTION work correctly, and in general to make characteristics (and SHOW) work right, we had to separate the old definition blob in the mysql.proc table into separate fields for parameters, return type, and body, and handle the characteristics (like SQL SECURITY) separately... and then reassemble the CREATE string for parsing, of course. This is rather ugly, mostly the parser bit. (Hopefully that will be better with the new parser.) --- Docs/sp-imp-spec.txt | 11 +- mysql-test/r/sp.result | 49 +++++- mysql-test/t/sp.test | 30 ++++ scripts/mysql_create_system_tables.sh | 6 +- scripts/mysql_fix_privilege_tables.sql | 6 +- sql/sp.cc | 223 +++++++++++++++++-------- sql/sp.h | 6 +- sql/sp_head.cc | 57 +++++-- sql/sp_head.h | 33 ++-- sql/sql_yacc.yy | 39 ++++- 10 files changed, 340 insertions(+), 120 deletions(-) diff --git a/Docs/sp-imp-spec.txt b/Docs/sp-imp-spec.txt index b93416df2f7..ee9bc7a0e4f 100644 --- a/Docs/sp-imp-spec.txt +++ b/Docs/sp-imp-spec.txt @@ -1063,8 +1063,10 @@ language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, - definition blob DEFAULT '' NOT NULL, - security_type enum('INVOKER','DEFINER') DEFAULT 'INVOKER' NOT NULL, + security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, + param_list blob DEFAULT '' NOT NULL, + returns char(64) DEFAULT '' NOT NULL, + body blob DEFAULT '' NOT NULL, definer char(77) binary DEFAULT '' NOT NULL, created timestamp, modified timestamp, @@ -1093,5 +1095,6 @@ comment char(64) binary DEFAULT '' NOT NULL, PRIMARY KEY (schema,name,type) ) comment='Stored Procedures'; - --- + + -- + \ No newline at end of file diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index e0d72a77832..851d56ba458 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -691,6 +691,43 @@ delete from t1; delete from t2; drop table t3; drop procedure cur2; +create procedure chistics() +language sql +not deterministic +sql security definer +comment 'Characteristics procedure test' + insert into t1 values ("chistics", 1); +call chistics(); +select * from t1; +id data +chistics 1 +delete from t1; +alter procedure chistics sql security invoker name chistics2; +show create procedure chistics2; +Procedure Create Procedure +chistics2 CREATE PROCEDURE chistics2() + SQL SECURITY INVOKER + COMMENT 'Characteristics procedure test' +insert into t1 values ("chistics", 1) +drop procedure chistics2; +create function chistics() returns int +language sql +deterministic +sql security invoker +comment 'Characteristics procedure test' + return 42; +select chistics(); +chistics() +42 +alter function chistics name chistics2 comment 'Characteristics function test'; +show create function chistics2; +Function Create Function +chistics2 CREATE FUNCTION chistics2() RETURNS int + DETERMINISTIC + SQL SECURITY INVOKER + COMMENT 'Characteristics function test' +return 42 +drop function chistics2; insert into t1 values ("foo", 1), ("bar", 2), ("zip", 3); set @@sql_mode = 'ANSI'; create procedure modes(out c1 int, out c2 int) @@ -881,7 +918,7 @@ n f drop table fac; show function status like '%f%'; Name Type Definer Modified Created Security_type Comment -fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER +fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER drop procedure ifac; drop function fac; show function status like '%f%'; @@ -946,7 +983,7 @@ end while; end; show create procedure opp; Procedure Create Procedure -opp create procedure opp(n bigint unsigned, out pp bool) +opp CREATE PROCEDURE opp(n bigint unsigned, out pp bool) begin declare r double; declare b, s bigint unsigned default 0; @@ -974,8 +1011,8 @@ end loop; end show procedure status like '%p%'; Name Type Definer Modified Created Security_type Comment -ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER -opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER +ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER call ip(200); select * from primes where i=45 or i=100 or i=199; i p @@ -1043,8 +1080,8 @@ alter procedure bar2 name bar comment "3333333333"; alter procedure bar; show create procedure bar; Procedure Create Procedure -bar create procedure bar(x char(16), y int) -comment "111111111111" sql security invoker +bar CREATE PROCEDURE bar(x char(16), y int) + COMMENT '3333333333' insert into test.t1 values (x, y) show procedure status like 'bar'; Name Type Definer Modified Created Security_type Comment diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 933fe828440..3681d9a9517 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -816,6 +816,36 @@ drop table t3| drop procedure cur2| +# The few characteristics we parse +create procedure chistics() + language sql + not deterministic + sql security definer + comment 'Characteristics procedure test' + insert into t1 values ("chistics", 1)| + +# Call it, just to make sure. +call chistics()| +select * from t1| +delete from t1| +alter procedure chistics sql security invoker name chistics2| +show create procedure chistics2| +drop procedure chistics2| + +create function chistics() returns int + language sql + deterministic + sql security invoker + comment 'Characteristics procedure test' + return 42| + +# Call it, just to make sure. +select chistics()| +alter function chistics name chistics2 comment 'Characteristics function test'| +show create function chistics2| +drop function chistics2| + + # Check mode settings insert into t1 values ("foo", 1), ("bar", 2), ("zip", 3)| diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index 7ae6773c1cf..57198abd53a 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -296,8 +296,10 @@ then c_p="$c_p language enum('SQL') DEFAULT 'SQL' NOT NULL," c_p="$c_p sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL," c_p="$c_p is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL," - c_p="$c_p definition blob DEFAULT '' NOT NULL," - c_p="$c_p security_type enum('INVOKER','DEFINER') DEFAULT 'INVOKER' NOT NULL," + c_p="$c_p security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL," + c_p="$c_p param_list blob DEFAULT '' NOT NULL," + c_p="$c_p returns char(64) DEFAULT '' NOT NULL," + c_p="$c_p body blob DEFAULT '' NOT NULL," c_p="$c_p definer char(77) binary DEFAULT '' NOT NULL," c_p="$c_p created timestamp," c_p="$c_p modified timestamp," diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index e342e08ea9d..788913fa38e 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -147,8 +147,10 @@ CREATE TABLE IF NOT EXISTS proc ( language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, - definition blob DEFAULT '' NOT NULL, - security_type enum('INVOKER','DEFINER') DEFAULT 'INVOKER' NOT NULL, + security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, + param_list blob DEFAULT '' NOT NULL, + returns char(64) DEFAULT '' NOT NULL, + body blob DEFAULT '' NOT NULL, definer char(77) binary DEFAULT '' NOT NULL, created timestamp, modified timestamp, diff --git a/sql/sp.cc b/sql/sp.cc index 42b0ba001a6..ded45102815 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -20,27 +20,41 @@ #include "sp_head.h" #include "sp_cache.h" +static char * +create_string(THD *thd, ulong *lenp, + int sp_type, + char *name, ulong namelen, + const char *params, ulong paramslen, + const char *returns, ulong returnslen, + const char *body, ulong bodylen, + st_sp_chistics *chistics); + /* * * DB storage of Stored PROCEDUREs and FUNCTIONs * */ -#define MYSQL_PROC_FIELD_SCHEMA 0 -#define MYSQL_PROC_FIELD_NAME 1 -#define MYSQL_PROC_FIELD_TYPE 2 -#define MYSQL_PROC_FIELD_SPECIFIC_NAME 3 -#define MYSQL_PROC_FIELD_LANGUAGE 4 -#define MYSQL_PROC_FIELD_ACCESS 5 -#define MYSQL_PROC_FIELD_DETERMINISTIC 6 -#define MYSQL_PROC_FIELD_DEFINITION 7 -#define MYSQL_PROC_FIELD_SECURITY_TYPE 8 -#define MYSQL_PROC_FIELD_DEFINER 9 -#define MYSQL_PROC_FIELD_CREATED 10 -#define MYSQL_PROC_FIELD_MODIFIED 11 -#define MYSQL_PROC_FIELD_SQL_MODE 12 -#define MYSQL_PROC_FIELD_COMMENT 13 -#define MYSQL_PROC_FIELD_COUNT 14 +enum +{ + MYSQL_PROC_FIELD_SCHEMA = 0, + MYSQL_PROC_FIELD_NAME, + MYSQL_PROC_FIELD_TYPE, + MYSQL_PROC_FIELD_SPECIFIC_NAME, + MYSQL_PROC_FIELD_LANGUAGE, + MYSQL_PROC_FIELD_ACCESS, + MYSQL_PROC_FIELD_DETERMINISTIC, + MYSQL_PROC_FIELD_SECURITY_TYPE, + MYSQL_PROC_FIELD_PARAM_LIST, + MYSQL_PROC_FIELD_RETURNS, + MYSQL_PROC_FIELD_BODY, + MYSQL_PROC_FIELD_DEFINER, + MYSQL_PROC_FIELD_CREATED, + MYSQL_PROC_FIELD_MODIFIED, + MYSQL_PROC_FIELD_SQL_MODE, + MYSQL_PROC_FIELD_COMMENT, + MYSQL_PROC_FIELD_COUNT +}; /* *opened=true means we opened ourselves */ static int @@ -104,13 +118,13 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name)); extern int yyparse(void *thd); TABLE *table; - const char *defstr; + const char *params, *returns, *body; int ret; bool opened; const char *creator; longlong created; longlong modified; - bool suid= 1; + st_sp_chistics *chistics; char *ptr; uint length; char buff[65]; @@ -127,8 +141,40 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) goto done; } - if ((defstr= get_field(&thd->mem_root, - table->field[MYSQL_PROC_FIELD_DEFINITION])) == NULL) + if ((ptr= get_field(&thd->mem_root, + table->field[MYSQL_PROC_FIELD_DETERMINISTIC])) == NULL) + { + ret= SP_GET_FIELD_FAILED; + goto done; + } + chistics= (st_sp_chistics *)thd->alloc(sizeof(st_sp_chistics)); + chistics->detistic= (ptr[0] == 'N' ? FALSE : TRUE); + + if ((ptr= get_field(&thd->mem_root, + table->field[MYSQL_PROC_FIELD_SECURITY_TYPE])) == NULL) + { + ret= SP_GET_FIELD_FAILED; + goto done; + } + chistics->suid= (ptr[0] == 'I' ? IS_NOT_SUID : IS_SUID); + + if ((params= get_field(&thd->mem_root, + table->field[MYSQL_PROC_FIELD_PARAM_LIST])) == NULL) + { + params= ""; + } + + if (type == TYPE_ENUM_PROCEDURE) + returns= ""; + else if ((returns= get_field(&thd->mem_root, + table->field[MYSQL_PROC_FIELD_RETURNS])) == NULL) + { + ret= SP_GET_FIELD_FAILED; + goto done; + } + + if ((body= get_field(&thd->mem_root, + table->field[MYSQL_PROC_FIELD_BODY])) == NULL) { ret= SP_GET_FIELD_FAILED; goto done; @@ -145,22 +191,15 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) modified= table->field[MYSQL_PROC_FIELD_MODIFIED]->val_int(); created= table->field[MYSQL_PROC_FIELD_CREATED]->val_int(); - if ((ptr= get_field(&thd->mem_root, - table->field[MYSQL_PROC_FIELD_SECURITY_TYPE])) == NULL) - { - ret= SP_GET_FIELD_FAILED; - goto done; - } - if (ptr[0] == 'N') - suid= 0; - sql_mode= table->field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(); table->field[MYSQL_PROC_FIELD_COMMENT]->val_str(&str, &str); ptr= 0; if ((length= str.length())) - ptr= strmake_root(&thd->mem_root, str.ptr(), length); + ptr= thd->strmake(str.ptr(), length); + chistics->comment.str= ptr; + chistics->comment.length= length; if (opened) { @@ -169,6 +208,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) } { + char *defstr; + ulong deflen; LEX *oldlex= thd->lex; enum enum_sql_command oldcmd= thd->lex->sql_command; ulong old_sql_mode= thd->variables.sql_mode; @@ -177,7 +218,14 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) thd->variables.sql_mode= sql_mode; thd->variables.select_limit= HA_POS_ERROR; - lex_start(thd, (uchar*)defstr, strlen(defstr)); + defstr= create_string(thd, &deflen, + type, + name, namelen, + params, strlen(params), + returns, strlen(returns), + body, strlen(body), + chistics); + lex_start(thd, (uchar*)defstr, deflen); if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL) { LEX *newlex= thd->lex; @@ -196,8 +244,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) { *sphp= thd->lex->sphead; (*sphp)->set_info((char *) creator, (uint) strlen(creator), - created, modified, suid, - ptr, length); + created, modified, chistics); } thd->lex->sql_command= oldcmd; thd->variables.sql_mode= old_sql_mode; @@ -211,12 +258,10 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) } static int -db_create_routine(THD *thd, int type, - char *name, uint namelen, char *def, uint deflen, - st_sp_chistics *chistics) +db_create_routine(THD *thd, int type, sp_head *sp) { DBUG_ENTER("db_create_routine"); - DBUG_PRINT("enter", ("type: %d name: %*s def: %*s", type, namelen, name, deflen, def)); + DBUG_PRINT("enter", ("type: %d name: %*s",type,sp->m_name.length,sp->m_name.str)); int ret; TABLE *table; TABLE_LIST tables; @@ -238,27 +283,33 @@ db_create_routine(THD *thd, int type, ret= SP_GET_FIELD_FAILED; goto done; } - table->field[MYSQL_PROC_FIELD_NAME]->store(name, namelen, - system_charset_info); - table->field[MYSQL_PROC_FIELD_TYPE]->store((longlong)type); - table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]->store(name, namelen, - system_charset_info); - table->field[MYSQL_PROC_FIELD_DEFINITION]->store(def, deflen, - system_charset_info); - table->field[MYSQL_PROC_FIELD_DEFINER]->store(creator, - (uint)strlen(creator), - system_charset_info); + table->field[MYSQL_PROC_FIELD_NAME]-> + store(sp->m_name.str, sp->m_name.length, system_charset_info); + table->field[MYSQL_PROC_FIELD_TYPE]-> + store((longlong)type); + table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]-> + store(sp->m_name.str, sp->m_name.length, system_charset_info); + table->field[MYSQL_PROC_FIELD_DETERMINISTIC]-> + store((longlong)(sp->m_chistics->detistic ? 1 : 2)); + if (sp->m_chistics->suid != IS_DEFAULT_SUID) + table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]-> + store((longlong)sp->m_chistics->suid); + table->field[MYSQL_PROC_FIELD_PARAM_LIST]-> + store(sp->m_params.str, sp->m_params.length, system_charset_info); + if (sp->m_retstr.str) + table->field[MYSQL_PROC_FIELD_RETURNS]-> + store(sp->m_retstr.str, sp->m_retstr.length, system_charset_info); + table->field[MYSQL_PROC_FIELD_BODY]-> + store(sp->m_body.str, sp->m_body.length, system_charset_info); + table->field[MYSQL_PROC_FIELD_DEFINER]-> + store(creator, (uint)strlen(creator), system_charset_info); ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time(); - if (chistics->suid != IS_DEFAULT_SUID) - table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->store( - (longlong)chistics->suid); - table->field[MYSQL_PROC_FIELD_SQL_MODE]->store( - (longlong)thd->variables.sql_mode); - if (chistics->comment.str) - table->field[MYSQL_PROC_FIELD_COMMENT]->store( - chistics->comment.str, - chistics->comment.length, - system_charset_info); + table->field[MYSQL_PROC_FIELD_SQL_MODE]-> + store((longlong)thd->variables.sql_mode); + if (sp->m_chistics->comment.str) + table->field[MYSQL_PROC_FIELD_COMMENT]-> + store(sp->m_chistics->comment.str, sp->m_chistics->comment.length, + system_charset_info); if (table->file->write_row(table->record[0])) ret= SP_WRITE_ROW_FAILED; @@ -308,7 +359,7 @@ db_update_routine(THD *thd, int type, char *name, uint namelen, { store_record(table,record[1]); ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time(); - if (chistics->suid) + if (chistics->suid != IS_DEFAULT_SUID) table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->store((longlong)chistics->suid); if (newname) table->field[MYSQL_PROC_FIELD_NAME]->store(newname, @@ -516,15 +567,13 @@ sp_find_procedure(THD *thd, LEX_STRING *name) } int -sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen, - st_sp_chistics *chistics) +sp_create_procedure(THD *thd, sp_head *sp) { DBUG_ENTER("sp_create_procedure"); - DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def)); + DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str)); int ret; - ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen, def, deflen, - chistics); + ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp); DBUG_RETURN(ret); } @@ -611,15 +660,13 @@ sp_find_function(THD *thd, LEX_STRING *name) } int -sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen, - st_sp_chistics *chistics) +sp_create_function(THD *thd, sp_head *sp) { DBUG_ENTER("sp_create_function"); - DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def)); + DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str)); int ret; - ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, name, namelen, def, deflen, - chistics); + ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp); DBUG_RETURN(ret); } @@ -774,3 +821,45 @@ sp_cache_functions(THD *thd, LEX *lex) } return ret; } + +static char * +create_string(THD *thd, ulong *lenp, + int type, + char *name, ulong namelen, + const char *params, ulong paramslen, + const char *returns, ulong returnslen, + const char *body, ulong bodylen, + st_sp_chistics *chistics) +{ + char *buf, *ptr; + ulong buflen, pos; + + buflen= 100 + namelen + paramslen + returnslen + bodylen + + chistics->comment.length; + ptr= buf= thd->alloc(buflen); + if (type == TYPE_ENUM_FUNCTION) + { + ptr+= my_sprintf(buf, + (buf, (char *) + "CREATE FUNCTION %s(%s) RETURNS %s\n", + name, params, returns)); + } + else + { + ptr+= my_sprintf(buf, + (buf, (char *) + "CREATE PROCEDURE %s(%s)\n", + name, params)); + } + if (chistics->detistic) + ptr+= my_sprintf(ptr, (ptr, (char *)" DETERMINISTIC\n")); + if (chistics->suid == IS_NOT_SUID) + ptr+= my_sprintf(ptr, (ptr, (char *)" SQL SECURITY INVOKER\n")); + if (chistics->comment.str) + ptr+= my_sprintf(ptr, (ptr, (char *)" COMMENT '%*s'\n", + chistics->comment.length, + chistics->comment.str)); + strcpy(ptr, body); + *lenp= (ptr-buf)+bodylen; + return buf; +} diff --git a/sql/sp.h b/sql/sp.h index 9bce886336d..b9f29138de2 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -32,8 +32,7 @@ sp_head * sp_find_procedure(THD *thd, LEX_STRING *name); int -sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen, - st_sp_chistics *chistics); +sp_create_procedure(THD *thd, sp_head *sp); int sp_drop_procedure(THD *thd, char *name, uint namelen); @@ -54,8 +53,7 @@ sp_head * sp_find_function(THD *thd, LEX_STRING *name); int -sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen, - st_sp_chistics *chistics); +sp_create_function(THD *thd, sp_head *sp); int sp_drop_function(THD *thd, char *name, uint namelen); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 39669c5b86f..cfaf08b7972 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -163,18 +163,51 @@ sp_head::sp_head() } void -sp_head::init(LEX_STRING *name, LEX *lex) +sp_head::init(LEX *lex) { DBUG_ENTER("sp_head::init"); - const char *dstr = (const char*)lex->buf; + + lex->spcont= m_pcont= new sp_pcontext(); + my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8); + m_param_begin= m_param_end= m_returns_begin= m_returns_end= m_body_begin= 0; + m_name.str= m_params.str= m_retstr.str= m_body.str= m_defstr.str= 0; + m_name.length= m_params.length= m_retstr.length= m_body.length= + m_defstr.length= 0; + DBUG_VOID_RETURN; +} + +void +sp_head::init_strings(LEX_STRING *name, LEX *lex) +{ + DBUG_ENTER("sp_head::init_strings"); DBUG_PRINT("info", ("name: %*s", name->length, name->str)); m_name.length= name->length; m_name.str= lex->thd->strmake(name->str, name->length); + m_params.length= m_param_end- m_param_begin; + m_params.str= lex->thd->strmake((char *)m_param_begin, m_params.length); + if (m_returns_begin && m_returns_end) + { + /* QQ KLUDGE: We can't seem to cut out just the type in the parser + (without the RETURNS), so we'll have to do it here. :-( */ + char *p= (char *)m_returns_begin+strspn((char *)m_returns_begin,"\t\n\r "); + p+= strcspn(p, "\t\n\r "); + p+= strspn(p, "\t\n\r "); + if (p < (char *)m_returns_end) + m_returns_begin= (uchar *)p; + /* While we're at it, trim the end too. */ + p= (char *)m_returns_end-1; + while (p > (char *)m_returns_begin && + (*p == '\t' || *p == '\n' || *p == '\r' || *p == ' ')) + p-= 1; + m_returns_end= (uchar *)p+1; + m_retstr.length= m_returns_end - m_returns_begin; + m_retstr.str= lex->thd->strmake((char *)m_returns_begin, m_retstr.length); + } + m_body.length= lex->end_of_query - m_body_begin; + m_body.str= lex->thd->strmake((char *)m_body_begin, m_body.length); m_defstr.length= lex->end_of_query - lex->buf; - m_defstr.str= lex->thd->strmake(dstr, m_defstr.length); - lex->spcont= m_pcont= new sp_pcontext(); - my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8); + m_defstr.str= lex->thd->strmake((char *)lex->buf, m_defstr.length); DBUG_VOID_RETURN; } @@ -184,18 +217,12 @@ sp_head::create(THD *thd) DBUG_ENTER("sp_head::create"); int ret; - DBUG_PRINT("info", ("type: %d name: %s def: %s", - m_type, m_name.str, m_defstr.str)); + DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s", + m_type, m_name.str, m_params.str, m_body.str)); if (m_type == TYPE_ENUM_FUNCTION) - ret= sp_create_function(thd, - m_name.str, m_name.length, - m_defstr.str, m_defstr.length, - m_chistics); + ret= sp_create_function(thd, this); else - ret= sp_create_procedure(thd, - m_name.str, m_name.length, - m_defstr.str, m_defstr.length, - m_chistics); + ret= sp_create_procedure(thd, this); DBUG_RETURN(ret); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 0f0c618ffb4..33c6bd4fe38 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -56,6 +56,18 @@ public: List m_calls; // Called procedures. List m_tables; // Used tables. #endif + LEX_STRING m_name; + LEX_STRING m_params; + LEX_STRING m_retstr; // For FUNCTIONs only + LEX_STRING m_body; + LEX_STRING m_defstr; + char *m_creator; + uint m_creatorlen; + longlong m_created; + longlong m_modified; + // Pointers set during parsing + uchar *m_param_begin, *m_param_end, *m_returns_begin, *m_returns_end, + *m_body_begin; static void * operator new(size_t size); @@ -67,7 +79,11 @@ public: // Initialize after we have reset mem_root void - init(LEX_STRING *name, LEX *lex); + init(LEX *lex); + + // Initialize strings after parsing header + void + init_strings(LEX_STRING *name, LEX *lex); int create(THD *thd); @@ -136,6 +152,8 @@ public: return m_name.str; } + char *create_string(THD *thd, ulong *lenp); + inline Item_result result() { return sp_map_result_type(m_returns); @@ -143,15 +161,13 @@ public: void set_info(char *creator, uint creatorlen, longlong created, longlong modified, - bool suid, char *comment, uint commentlen) + st_sp_chistics *chistics) { m_creator= creator; m_creatorlen= creatorlen; m_created= created; m_modified= modified; - m_chistics->comment.length= commentlen; - m_chistics->comment.str= comment; - m_chistics->suid= (suid ? IS_SUID : IS_NOT_SUID); + m_chistics= chistics; } inline void reset_thd_mem_root(THD *thd) @@ -180,13 +196,6 @@ private: Item *m_free_list; // Where the items go THD *m_thd; // Set if we have reset mem_root - LEX_STRING m_name; - LEX_STRING m_defstr; - char *m_creator; - uint m_creatorlen; - longlong m_created; - longlong m_modified; - sp_pcontext *m_pcont; // Parse context List m_lex; // Temp. store for the other lex DYNAMIC_ARRAY m_instr; // The "instructions" diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 369880486f9..cbafd69b9ac 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1040,7 +1040,7 @@ create: /* Order is important here: new - reset - init */ sp= new sp_head(); sp->reset_thd_mem_root(YYTHD); - sp->init(&$3, lex); + sp->init(lex); sp->m_type= TYPE_ENUM_PROCEDURE; lex->sphead= sp; @@ -1052,10 +1052,18 @@ create: sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES); } - '(' sp_pdparam_list ')' + '(' { LEX *lex= Lex; + lex->sphead->m_param_begin= lex->tok_start+1; + } + sp_pdparam_list + ')' + { + LEX *lex= Lex; + + lex->sphead->m_param_end= lex->tok_start; lex->spcont->set_params(); bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); } @@ -1064,11 +1072,13 @@ create: LEX *lex= Lex; lex->sphead->m_chistics= &lex->sp_chistics; + lex->sphead->m_body_begin= lex->tok_start; } sp_proc_stmt { LEX *lex= Lex; + lex->sphead->init_strings(&$3, lex); lex->sql_command= SQLCOM_CREATE_PROCEDURE; /* Restore flag if it was cleared above */ if (lex->sphead->m_old_cmq) @@ -1103,7 +1113,7 @@ create_function_tail: /* Order is important here: new - reset - init */ sp= new sp_head(); sp->reset_thd_mem_root(YYTHD); - sp->init(&lex->udf.name, lex); + sp->init(lex); sp->m_type= TYPE_ENUM_FUNCTION; lex->sphead= sp; @@ -1114,16 +1124,25 @@ create_function_tail: */ sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES; + lex->sphead->m_param_begin= lex->tok_start+1; } sp_fdparam_list ')' { - Lex->spcont->set_params(); + LEX *lex= Lex; + + lex->spcont->set_params(); + lex->sphead->m_param_end= lex->tok_start; } - RETURNS_SYM type + RETURNS_SYM + { + Lex->sphead->m_returns_begin= Lex->tok_start; + } + type { LEX *lex= Lex; - lex->sphead->m_returns= (enum enum_field_types)$7; + lex->sphead->m_returns_end= lex->tok_start; + lex->sphead->m_returns= (enum enum_field_types)$8; bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); } sp_c_chistics @@ -1131,16 +1150,19 @@ create_function_tail: LEX *lex= Lex; lex->sphead->m_chistics= &lex->sp_chistics; + lex->sphead->m_body_begin= lex->tok_start; } sp_proc_stmt { LEX *lex= Lex; + sp_head *sp= lex->sphead; lex->sql_command= SQLCOM_CREATE_SPFUNCTION; + sp->init_strings(&lex->udf.name, lex); /* Restore flag if it was cleared above */ - if (lex->sphead->m_old_cmq) + if (sp->m_old_cmq) YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; - lex->sphead->restore_thd_mem_root(YYTHD); + sp->restore_thd_mem_root(YYTHD); } ; @@ -5884,6 +5906,7 @@ keyword: | RESET_SYM {} | RESOURCES {} | RESTORE_SYM {} + | RETURNS_SYM {} | ROLLBACK_SYM {} | ROLLUP_SYM {} | ROWS_SYM {}