diff options
author | unknown <pem@mysql.comhem.se> | 2004-03-11 17:18:59 +0100 |
---|---|---|
committer | unknown <pem@mysql.comhem.se> | 2004-03-11 17:18:59 +0100 |
commit | eb4aa092e5648cc950ff8a6e3e5acbe296ae8fa7 (patch) | |
tree | 2a790442a0c109f0f5eabc6530c71782c2104c30 /sql | |
parent | 5aa57221d8b40a0b5146c9af027cdd2dc15af737 (diff) | |
download | mariadb-git-eb4aa092e5648cc950ff8a6e3e5acbe296ae8fa7.tar.gz |
WL#1366: Use the schema (db) associated with an SP.
Phase 2: Make SPs belong to a DB, and use qualified names.
As a side effect, using USE in an SP is no longer allowed.
(It just doesn't work otherwise.)
include/mysqld_error.h:
New error code (USE is no longer allowed in a stored procedure).
include/sql_state.h:
New error state (USE is no longer allowed in a stored procedure).
mysql-test/r/sp-error.result:
Updated result for test of USE in SP (not allowed now).
mysql-test/r/sp-security.result:
Updated test results for new db column and qualified procedured names.
mysql-test/r/sp.result:
Updated results for USE in SP (as it's no longer allowed), and
for new db column in status result.
mysql-test/t/sp-error.test:
Moved test of USE in SP from sp.test (as it's no longer allowed).
mysql-test/t/sp-security.test:
Ajusted tests for new db column and qualified procedured names.
mysql-test/t/sp.test:
Moved test of USE in SP to sp-error.test (as it's no longer allowed).
Adjusted tests for new db column in status result.
sql/mysql_priv.h:
mysql_change_db() now has optional arguments for use by SP with qualified names.
sql/share/czech/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/danish/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/dutch/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/english/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/estonian/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/french/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/german/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/greek/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/hungarian/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/italian/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/japanese/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/korean/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/norwegian-ny/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/norwegian/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/polish/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/portuguese/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/romanian/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/russian/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/serbian/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/slovak/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/spanish/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/swedish/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/share/ukrainian/errmsg.txt:
New error message: USE is not allowed in a stored procedure.
sql/sp.cc:
SPs are now "belong" to a DB and may have qualified names.
New functions for changing DB ("use") when parsing and invoking SPs.
sql/sp.h:
New functions for changing DB ("use") when parsing and invoking SPs.
sql/sp_cache.cc:
Use the qualified name in the SP cache.
sql/sp_head.cc:
New function for allocating a qualified SP name (used in sql_yacc.yy).
Change DB when executing an SP (if needed).
Moved thd_mem_root swap functions from sp_head.h.
sql/sp_head.h:
New function for allocating a qualified SP name (used in sql_yacc.yy).
Moved thd_mem_root swap functions to sp_head.cc.
sql/sql_db.cc:
mysql_change_db() now has optional arguments for use by SP with qualified names
(for use when reading an SP from database and executing it); also allow "unusing"
a database, i.e. setting thd->thd to "".
sql/sql_yacc.yy:
Initialize qualfied SP names correctly.
USE is no longer allowed in an SP.
Diffstat (limited to 'sql')
31 files changed, 303 insertions, 124 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e17847ebe24..21822e02d29 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -445,7 +445,8 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, int quick_rm_table(enum db_type base,const char *db, const char *table_name); bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); -bool mysql_change_db(THD *thd,const char *name); +bool mysql_change_db(THD *thd,const char *name, + bool empty_is_ok=0, bool no_access_check=0); void mysql_parse(THD *thd,char *inBuf,uint length); bool is_update_query(enum enum_sql_command command); void free_items(Item *item); diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 117bf4b37d4..eea5912cbdf 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -335,3 +335,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index ba012e0eea3..2c2782d4cf0 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -329,3 +329,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 0349929f0d3..84bd5781ffb 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -337,3 +337,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 6bf4bde9b22..2c88e1b445f 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -326,3 +326,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 03e2d4d6c90..d72d7f94309 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -331,3 +331,4 @@ character-set=latin7 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index dab2ab9f51d..227b5138e98 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -326,3 +326,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 5b2378dde22..d4e42ed5d58 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -338,3 +338,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index a840e95de97..44e072bb20e 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -326,3 +326,4 @@ character-set=greek "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 0b24ca6afb8..72fdf4f8c51 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -328,3 +328,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index a298baa7682..6694f220848 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -326,3 +326,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index a25357ae079..896146749a9 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -328,3 +328,4 @@ character-set=ujis "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index d3799d881ed..3a92c060c67 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -326,3 +326,4 @@ character-set=euckr "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index d69d52408ff..ada0435b52a 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -328,3 +328,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 5fbbaf19480..d0688b2858c 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -328,3 +328,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 92572db5fdc..d0c96146441 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -330,3 +330,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 580fec472b6..71be50ba262 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -327,3 +327,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 3e6bff75591..d800906e663 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -330,3 +330,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index b04cda84efd..633e29e8c48 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -328,3 +328,4 @@ character-set=koi8r "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 2737ce26873..efda5bb12cc 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -321,3 +321,4 @@ character-set=cp1250 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index bf9fe6d3519..8fa84320a8f 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -334,3 +334,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index fec6bbb4342..75a6d42bec8 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -328,3 +328,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 8b2892172ba..9b743acb930 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -326,3 +326,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 393c765a8ca..2b3587e2028 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -331,3 +331,4 @@ character-set=koi8u "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/sp.cc b/sql/sp.cc index 26f21c31fd8..20cd43c2ad3 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -23,7 +23,7 @@ static char * create_string(THD *thd, ulong *lenp, int sp_type, - char *name, ulong namelen, + sp_name *name, const char *params, ulong paramslen, const char *returns, ulong returnslen, const char *body, ulong bodylen, @@ -69,7 +69,11 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, type, name->m_name.length, name->m_name.str)); // Put the key used to read the row together - memset(key, (int)' ', 64); // QQ Empty db for now + keylen= name->m_db.length; + if (keylen > 64) + keylen= 64; + memcpy(key, name->m_db.str, keylen); + memset(key+keylen, (int)' ', 64-keylen); // Pad with space keylen= name->m_name.length; if (keylen > 64) keylen= 64; @@ -213,6 +217,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) char *defstr; ulong deflen; LEX *oldlex= thd->lex; + char olddb[128]; + char *olddbptr; enum enum_sql_command oldcmd= thd->lex->sql_command; ulong old_sql_mode= thd->variables.sql_mode; ha_rows select_limit= thd->variables.select_limit; @@ -221,23 +227,30 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) thd->variables.select_limit= HA_POS_ERROR; if (!(defstr= create_string(thd, &deflen, - type, - name->m_name.str, name->m_name.length, - params, strlen(params), - returns, strlen(returns), - body, strlen(body), + type, + name, + params, strlen(params), + returns, strlen(returns), + body, strlen(body), &chistics))) { ret= SP_INTERNAL_ERROR; goto done; } + olddbptr= thd->db; + if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb), 1))) + goto done; + lex_start(thd, (uchar*)defstr, deflen); if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL) { LEX *newlex= thd->lex; sp_head *sp= newlex->sphead; + if (olddbptr != thd->db && + (ret= sp_change_db(thd, olddb, 1))) + goto done; if (sp) { if (oldlex != newlex) @@ -249,6 +262,9 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) } else { + if (olddbptr != thd->db && + (ret= sp_change_db(thd, olddb, 1))) + goto done; *sphp= thd->lex->sphead; (*sphp)->set_info((char *)definer, (uint)strlen(definer), created, modified, &chistics); @@ -259,6 +275,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) } done: + if (opened) close_thread_tables(thd); DBUG_RETURN(ret); @@ -291,9 +308,8 @@ db_create_routine(THD *thd, int type, sp_head *sp) ret= SP_GET_FIELD_FAILED; goto done; } -// QQ Not yet -// table->field[MYSQL_PROC_FIELD_DB]-> -// store(sp->m_db.str, sp->m_db.length, system_charset_info); + table->field[MYSQL_PROC_FIELD_DB]-> + store(sp->m_db.str, sp->m_db.length, 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]-> @@ -402,8 +418,7 @@ struct st_used_field static struct st_used_field init_fields[]= { -// QQ Not yet -// { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0}, + { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0}, { "Name", NAME_LEN, MYSQL_TYPE_STRING, 0}, { "Type", 9, MYSQL_TYPE_STRING, 0}, { "Definer", 77, MYSQL_TYPE_STRING, 0}, @@ -424,14 +439,20 @@ print_field_values(THD *thd, TABLE *table, if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type) { - String *tmp_string= new String(); + String db_string; + String name_string; struct st_used_field *used_field= used_fields; - get_field(&thd->mem_root, used_field->field, tmp_string); - if (!wild || !wild[0] || !wild_compare(tmp_string->ptr(), wild, 0)) + if (get_field(&thd->mem_root, used_field->field, &db_string)) + db_string.set_ascii("", 0); + used_field+= 1; + get_field(&thd->mem_root, used_field->field, &name_string); + + if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0)) { protocol->prepare_for_resend(); - protocol->store(tmp_string); + protocol->store(&db_string); + protocol->store(&name_string); for (used_field++; used_field->field_name; used_field++) @@ -448,10 +469,10 @@ print_field_values(THD *thd, TABLE *table, break; default: { - String *tmp_string1= new String(); + String tmp_string; - get_field(&thd->mem_root, used_field->field, tmp_string1); - protocol->store(tmp_string1); + get_field(&thd->mem_root, used_field->field, &tmp_string); + protocol->store(&tmp_string); } break; } @@ -738,17 +759,16 @@ sp_show_status_function(THD *thd, const char *wild) bool -sp_function_exists(THD *thd, LEX_STRING *name) +sp_function_exists(THD *thd, sp_name *name) { TABLE *table; bool ret= FALSE; bool opened= FALSE; - sp_name n(*name); DBUG_ENTER("sp_function_exists"); - if (sp_cache_lookup(&thd->sp_func_cache, &n) || + if (sp_cache_lookup(&thd->sp_func_cache, name) || db_find_routine_aux(thd, TYPE_ENUM_FUNCTION, - &n, TL_READ, + name, TL_READ, &table, &opened) == SP_OK) ret= TRUE; if (opened) @@ -770,11 +790,11 @@ void sp_add_fun_to_lex(LEX *lex, sp_name *fun) { if (! hash_search(&lex->spfuns, - (byte *)fun->m_name.str, fun->m_name.length)) + (byte *)fun->m_qname.str, fun->m_qname.length)) { LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING)); - ls->str= sql_strmake(fun->m_name.str, fun->m_name.length); - ls->length= fun->m_name.length; + ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length); + ls->length= fun->m_qname.length; my_hash_insert(&lex->spfuns, (byte *)ls); } @@ -805,6 +825,7 @@ sp_cache_functions(THD *thd, LEX *lex) LEX_STRING *ls= (LEX_STRING *)hash_element(h, i); sp_name name(*ls); + name.m_qname= *ls; if (! sp_cache_lookup(&thd->sp_func_cache, &name)) { sp_head *sp; @@ -812,6 +833,13 @@ sp_cache_functions(THD *thd, LEX *lex) LEX *newlex= new st_lex; thd->lex= newlex; + name.m_name.str= strchr(name.m_qname.str, '.'); + name.m_db.length= name.m_name.str - name.m_qname.str; + name.m_db.str= strmake_root(&thd->mem_root, + name.m_qname.str, name.m_db.length); + name.m_name.str+= 1; + name.m_name.length= name.m_qname.length - name.m_db.length - 1; + if (db_find_routine(thd, TYPE_ENUM_FUNCTION, &name, &sp) == SP_OK) { @@ -839,7 +867,7 @@ sp_cache_functions(THD *thd, LEX *lex) static char * create_string(THD *thd, ulong *lenp, int type, - char *name, ulong namelen, + sp_name *name, const char *params, ulong paramslen, const char *returns, ulong returnslen, const char *body, ulong bodylen, @@ -848,14 +876,15 @@ create_string(THD *thd, ulong *lenp, char *buf, *ptr; ulong buflen; - buflen= 100 + namelen + paramslen + returnslen + bodylen + + buflen= 100 + name->m_qname.length + paramslen + returnslen + bodylen + chistics->comment.length; if (!(buf= thd->alloc(buflen))) return 0; ptr= strxmov(buf, "CREATE ", (type == TYPE_ENUM_FUNCTION) ? "FUNCTION" : "PROCEDURE", - " `", name, "`(", params, ")", NullS); + " `", name->m_db.str, "`.`", name->m_name.str, "`(", params, ")", + NullS); if (type == TYPE_ENUM_FUNCTION) ptr= strxmov(ptr, " RETURNS ", returns, NullS); @@ -874,3 +903,63 @@ create_string(THD *thd, ulong *lenp, *lenp= (ptr-buf); return buf; } + + +// +// Utilities... +// + +int +sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen, + bool no_access_check) +{ + bool changeit; + DBUG_ENTER("sp_use_new_db"); + DBUG_PRINT("enter", ("newdb: %s", newdb)); + + if (thd->db && thd->db[0]) + { + if (my_strcasecmp(system_charset_info, thd->db, newdb) == 0) + changeit= 0; + else + { + changeit= 1; + strnmov(olddb, thd->db, olddblen); + } + } + else + { // thd->db empty + if (newdb[0]) + changeit= 1; + else + changeit= 0; + olddb[0] = '\0'; + } + if (!changeit) + { + DBUG_RETURN(0); + } + else + { + int ret= sp_change_db(thd, newdb, no_access_check); + + DBUG_RETURN(ret); + } +} + +int +sp_change_db(THD *thd, char *db, bool no_access_check) +{ + int ret; + ulong dbaccess= thd->db_access; /* mysql_change_db() changes this */ + my_bool nsok= thd->net.no_send_ok; /* mysql_change_db() does send_ok() */ + thd->net.no_send_ok= TRUE; + DBUG_ENTER("sp_change_db"); + DBUG_PRINT("enter", ("db: %s, no_access_check: %d", db, no_access_check)); + + ret= mysql_change_db(thd, db, 1, no_access_check); + + thd->net.no_send_ok= nsok; + thd->db_access= dbaccess; + DBUG_RETURN(ret); +} @@ -70,7 +70,7 @@ int sp_show_status_function(THD *thd, const char *wild); bool -sp_function_exists(THD *thd, LEX_STRING *name); +sp_function_exists(THD *thd, sp_name *name); // This is needed since we have to read the functions before we @@ -82,4 +82,19 @@ sp_merge_funs(LEX *dst, LEX *src); int sp_cache_functions(THD *thd, LEX *lex); + +// +// Utilities... +// + +// Do a "use newdb". The current db is stored at olddb. +// If newdb is the same as the current one, nothing is changed. +int +sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax, + bool no_access_check); + +// Like mysql_change_db() but handles empty db name and the send_ok() problem. +int +sp_change_db(THD *thd, char *db, bool no_access_check); + #endif /* _SP_H_ */ diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 93f51938000..e13fb2695e7 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -89,7 +89,7 @@ sp_cache_lookup(sp_cache **cp, sp_name *name) c->version= v; return NULL; } - return c->lookup(name->m_name.str, name->m_name.length); + return c->lookup(name->m_qname.str, name->m_qname.length); } bool @@ -109,7 +109,7 @@ sp_cache_remove(sp_cache **cp, sp_name *name) if (c->version < v) c->remove_all(); else - found= c->remove(name->m_name.str, name->m_name.length); + found= c->remove(name->m_qname.str, name->m_qname.length); c->version= v+1; } return found; @@ -120,7 +120,10 @@ static byte * hash_get_key_for_sp_head(const byte *ptr, uint *plen, my_bool first) { - return (byte*) ((sp_head*)ptr)->name(plen); + sp_head *sp= (sp_head *)ptr; + + *plen= sp->m_qname.length; + return (byte*) sp->m_qname.str; } static void diff --git a/sql/sp_head.cc b/sql/sp_head.cc index eebe02c1834..ebf74e25bbe 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -147,6 +147,26 @@ sp_name::init_qname(THD *thd) m_name.length, m_name.str); } +sp_name * +sp_name_current_db_new(THD *thd, LEX_STRING name) +{ + sp_name *qname; + + if (! thd->db) + qname= new sp_name(name); + else + { + LEX_STRING db; + + db.length= strlen(thd->db); + db.str= thd->strmake(thd->db, db.length); + qname= new sp_name(db, name); + } + qname->init_qname(thd); + return qname; +} + + /* ------------------------------------------------------------------ */ @@ -224,8 +244,8 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) /* We have to copy strings to get them into the right memroot */ if (name->m_db.length == 0) { - m_db.length= strlen(thd->db); - m_db.str= strmake_root(root, thd->db, m_db.length); + m_db.length= (thd->db ? strlen(thd->db) : 0); + m_db.str= strmake_root(root, (thd->db ? thd->db : ""), m_db.length); } else { @@ -317,30 +337,22 @@ int sp_head::execute(THD *thd) { DBUG_ENTER("sp_head::execute"); - char olddbname[128]; - char *olddbptr= thd->db; + char olddb[128]; + char *olddbptr; sp_rcontext *ctx= thd->spcont; int ret= 0; uint ip= 0; #ifndef EMBEDDED_LIBRARY - if (check_stack_overrun(thd, olddbptr)) + if (check_stack_overrun(thd, olddb)) { DBUG_RETURN(-1); } #endif - if (olddbptr) - { - uint i= 0; - char *p= olddbptr; - - /* Fast inline strncpy without padding... */ - while (*p && i < sizeof(olddbname)) - olddbname[i++]= *p++; - if (i == sizeof(olddbname)) - i-= 1; // QQ Error or warning for truncate? - olddbname[i]= '\0'; - } + + olddbptr= thd->db; + if ((ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0))) + goto done; if (ctx) ctx->clear_handler(); @@ -379,18 +391,17 @@ sp_head::execute(THD *thd) } } while (ret == 0 && !thd->killed && !thd->query_error); + done: DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d", ret, thd->killed, thd->query_error)); if (thd->killed || thd->query_error) ret= -1; /* If the DB has changed, the pointer has changed too, but the original thd->db will then have been freed */ - if (olddbptr && olddbptr != thd->db) + if (olddbptr != thd->db) { - /* QQ Maybe we should issue some special error message or warning here, - if this fails?? */ if (! thd->killed) - ret= mysql_change_db(thd, olddbname); + ret= sp_change_db(thd, olddb, 0); } DBUG_RETURN(ret); } @@ -757,6 +768,32 @@ sp_head::set_info(char *definer, uint definerlen, m_chistics->comment.length); } +void +sp_head::reset_thd_mem_root(THD *thd) +{ + m_thd_root= thd->mem_root; + thd->mem_root= m_mem_root; + m_free_list= thd->free_list; // Keep the old list + thd->free_list= NULL; // Start a new one + /* Copy the db, since substatements will point to it */ + m_thd_db= thd->db; + thd->db= strmake_root(&thd->mem_root, thd->db, thd->db_length); + m_thd= thd; +} + +void +sp_head::restore_thd_mem_root(THD *thd) +{ + Item *flist= m_free_list; // The old list + m_free_list= thd->free_list; // Get the new one + thd->free_list= flist; // Restore the old one + thd->db= m_thd_db; // Restore the original db pointer + m_mem_root= thd->mem_root; + thd->mem_root= m_thd_root; + m_thd= NULL; +} + + int sp_head::show_create_procedure(THD *thd) { @@ -1157,8 +1194,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) { ctxp->master_access= thd->master_access; ctxp->db_access= thd->db_access; - ctxp->db= thd->db; - ctxp->db_length= thd->db_length; ctxp->priv_user= thd->priv_user; strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host)); ctxp->user= thd->user; @@ -1174,8 +1209,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ctxp->changed= FALSE; thd->master_access= ctxp->master_access; thd->db_access= ctxp->db_access; - thd->db= ctxp->db; - thd->db_length= ctxp->db_length; thd->priv_user= ctxp->priv_user; strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host)); } @@ -1195,8 +1228,6 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ctxp->changed= FALSE; thd->master_access= ctxp->master_access; thd->db_access= ctxp->db_access; - thd->db= ctxp->db; - thd->db_length= ctxp->db_length; thd->priv_user= ctxp->priv_user; strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host)); } diff --git a/sql/sp_head.h b/sql/sp_head.h index b35b4c37501..791c6697693 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -66,6 +66,10 @@ public: {} }; +sp_name * +sp_name_current_db_new(THD *thd, LEX_STRING name); + + class sp_head : public Sql_alloc { sp_head(const sp_head &); /* Prevent use of these */ @@ -194,24 +198,10 @@ public: longlong created, longlong modified, st_sp_chistics *chistics); - inline void reset_thd_mem_root(THD *thd) - { - m_thd_root= thd->mem_root; - thd->mem_root= m_mem_root; - m_free_list= thd->free_list; // Keep the old list - thd->free_list= NULL; // Start a new one - m_thd= thd; - } + void reset_thd_mem_root(THD *thd); + + void restore_thd_mem_root(THD *thd); - inline void restore_thd_mem_root(THD *thd) - { - Item *flist= m_free_list; // The old list - m_free_list= thd->free_list; // Get the new one - thd->free_list= flist; // Restore the old one - m_mem_root= thd->mem_root; - thd->mem_root= m_thd_root; - m_thd= NULL; - } private: @@ -219,6 +209,7 @@ private: MEM_ROOT m_thd_root; // Temp. store for thd's mem_root Item *m_free_list; // Where the items go THD *m_thd; // Set if we have reset mem_root + char *m_thd_db; // Original thd->db pointer sp_pcontext *m_pcont; // Parse context List<LEX> m_lex; // Temp. store for the other lex @@ -671,8 +662,6 @@ struct st_sp_security_context bool changed; uint master_access; uint db_access; - char *db; - uint db_length; char *priv_user; char priv_host[MAX_HOSTNAME]; char *user; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index bc6b30040d6..3ea6821ef80 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -595,7 +595,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, 1 error */ -bool mysql_change_db(THD *thd, const char *name) +bool mysql_change_db(THD *thd, const char *name, + bool empty_is_ok, bool no_access_check) { int length, db_length; char *dbname=my_strdup((char*) name,MYF(MY_WME)); @@ -604,62 +605,76 @@ bool mysql_change_db(THD *thd, const char *name) HA_CREATE_INFO create; DBUG_ENTER("mysql_change_db"); - if (!dbname || !(db_length=strip_sp(dbname))) + if ((!dbname || !(db_length=strip_sp(dbname))) && !empty_is_ok) { x_free(dbname); /* purecov: inspected */ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } - if ((db_length > NAME_LEN) || check_db_name(dbname)) + if (!empty_is_ok || (dbname && db_length)) { - net_printf(thd, ER_WRONG_DB_NAME, dbname); - x_free(dbname); - DBUG_RETURN(1); + if ((db_length > NAME_LEN) || check_db_name(dbname)) + { + net_printf(thd, ER_WRONG_DB_NAME, dbname); + x_free(dbname); + DBUG_RETURN(1); + } } DBUG_PRINT("info",("Use database: %s", dbname)); -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (test_all_bits(thd->master_access,DB_ACLS)) - db_access=DB_ACLS; - else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); - if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) + if (!empty_is_ok || (dbname && db_length)) { - net_printf(thd,ER_DBACCESS_DENIED_ERROR, - thd->priv_user, - thd->priv_host, - dbname); - mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - thd->priv_user, - thd->priv_host, - dbname); - my_free(dbname,MYF(0)); - DBUG_RETURN(1); - } +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (! no_access_check) + { + if (test_all_bits(thd->master_access,DB_ACLS)) + db_access=DB_ACLS; + else + db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | + thd->master_access); + if (!(db_access & DB_ACLS) && + (!grant_option || check_grant_db(thd,dbname))) + { + net_printf(thd,ER_DBACCESS_DENIED_ERROR, + thd->priv_user, + thd->priv_host, + dbname); + mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), + thd->priv_user, + thd->priv_host, + dbname); + my_free(dbname,MYF(0)); + DBUG_RETURN(1); + } + } #endif - (void) sprintf(path,"%s/%s",mysql_data_home,dbname); - length=unpack_dirname(path,path); // Convert if not unix - if (length && path[length-1] == FN_LIBCHAR) - path[length-1]=0; // remove ending '\' - if (access(path,F_OK)) - { - net_printf(thd,ER_BAD_DB_ERROR,dbname); - my_free(dbname,MYF(0)); - DBUG_RETURN(1); + (void) sprintf(path,"%s/%s",mysql_data_home,dbname); + length=unpack_dirname(path,path); // Convert if not unix + if (length && path[length-1] == FN_LIBCHAR) + path[length-1]=0; // remove ending '\' + if (access(path,F_OK)) + { + net_printf(thd,ER_BAD_DB_ERROR,dbname); + my_free(dbname,MYF(0)); + DBUG_RETURN(1); + } } send_ok(thd); x_free(thd->db); thd->db=dbname; // THD::~THD will free this thd->db_length=db_length; + if (!empty_is_ok || (dbname && db_length)) + { #ifndef NO_EMBEDDED_ACCESS_CHECKS - thd->db_access=db_access; + if (! no_access_check) + thd->db_access=db_access; #endif - strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE); - load_db_opt(thd, path, &create); - thd->db_charset= create.default_table_charset ? - create.default_table_charset : - thd->variables.collation_server; - thd->variables.collation_database= thd->db_charset; + strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE); + load_db_opt(thd, path, &create); + thd->db_charset= create.default_table_charset ? + create.default_table_charset : + thd->variables.collation_server; + thd->variables.collation_database= thd->db_charset; + } DBUG_RETURN(0); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4224971fd47..50f475eb68c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1090,8 +1090,15 @@ create: ; sp_name: - IDENT_sys '.' IDENT_sys { $$= new sp_name($1, $3); } - | IDENT_sys { $$= new sp_name($1); } + IDENT_sys '.' IDENT_sys + { + $$= new sp_name($1, $3); + $$->init_qname(YYTHD); + } + | IDENT_sys + { + $$= sp_name_current_db_new(YYTHD, $1); + } ; create_function_tail: @@ -1576,6 +1583,11 @@ sp_proc_stmt: /* We maybe have one or more SELECT without INTO */ lex->sphead->m_multi_results= TRUE; } + if (lex->sql_command == SQLCOM_CHANGE_DB) + { /* "USE db" doesn't work in a procedure */ + send_error(YYTHD, ER_SP_NO_USE); + YYABORT; + } /* Don't add an instruction for empty SET statements. ** (This happens if the SET only contained local variables, ** which get their set instructions generated separately.) @@ -3913,10 +3925,11 @@ simple_expr: { $$= new Item_int((char*) "TRUE",1,1); } | IDENT_sys '(' udf_expr_list ')' { - if (sp_function_exists(YYTHD, &$1)) + sp_name *name= sp_name_current_db_new(YYTHD, $1); + + if (sp_function_exists(YYTHD, name)) { LEX *lex= Lex; - sp_name *name= new sp_name($1); sp_add_fun_to_lex(lex, name); if ($3) |