summaryrefslogtreecommitdiff
path: root/sql/sp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sp.cc')
-rw-r--r--sql/sp.cc917
1 files changed, 460 insertions, 457 deletions
diff --git a/sql/sp.cc b/sql/sp.cc
index ef4d0996b78..12d303ed85a 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -20,6 +20,7 @@
#include "unireg.h"
#include "sp.h"
#include "sql_base.h" // close_thread_tables
+#include "sql_lex.h" // empty_clex_str
#include "sql_parse.h" // parse_sql
#include "key.h" // key_copy
#include "sql_show.h" // append_definer, append_identifier
@@ -34,18 +35,59 @@
#include <my_user.h>
-/* Used in error handling only */
-#define SP_TYPE_STRING(type) \
- (type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE")
-
-static int
-db_load_routine(THD *thd, stored_procedure_type type, sp_name *name,
- sp_head **sphp,
- sql_mode_t sql_mode, const char *params, const char *returns,
- const char *body, st_sp_chistics &chistics,
- LEX_STRING *definer_user_name, LEX_STRING *definer_host_name,
- longlong created, longlong modified,
- Stored_program_creation_ctx *creation_ctx);
+
+sp_cache **Sp_handler_procedure::get_cache(THD *thd) const
+{
+ return &thd->sp_proc_cache;
+}
+
+sp_cache **Sp_handler_function::get_cache(THD *thd) const
+{
+ return &thd->sp_func_cache;
+}
+
+ulong Sp_handler_procedure::recursion_depth(THD *thd) const
+{
+ return thd->variables.max_sp_recursion_depth;
+}
+
+
+bool Sp_handler::add_instr_freturn(THD *thd, sp_head *sp,
+ sp_pcontext *spcont,
+ Item *item, LEX *lex) const
+{
+ my_error(ER_SP_BADRETURN, MYF(0));
+ return true;
+}
+
+
+bool Sp_handler::add_instr_preturn(THD *thd, sp_head *sp,
+ sp_pcontext *spcont) const
+{
+ thd->parse_error();
+ return true;
+}
+
+
+bool Sp_handler_function::add_instr_freturn(THD *thd, sp_head *sp,
+ sp_pcontext *spcont,
+ Item *item, LEX *lex) const
+{
+ return sp->add_instr_freturn(thd, spcont, item, lex);
+}
+
+
+bool Sp_handler_procedure::add_instr_preturn(THD *thd, sp_head *sp,
+ sp_pcontext *spcont) const
+{
+ return sp->add_instr_preturn(thd, spcont);
+}
+
+
+Sp_handler_procedure sp_handler_procedure;
+Sp_handler_function sp_handler_function;
+Sp_handler_trigger sp_handler_trigger;
+
static const
TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] =
@@ -131,7 +173,8 @@ TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] =
"'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
"'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
"'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
- "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") },
+ "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH',"
+ "'EMPTY_STRING_IS_NULL')") },
{ NULL, 0 }
},
{
@@ -176,7 +219,7 @@ class Stored_routine_creation_ctx : public Stored_program_creation_ctx,
{
public:
static Stored_routine_creation_ctx *
- load_from_db(THD *thd, const sp_name *name, TABLE *proc_tbl);
+ load_from_db(THD *thd, const Database_qualified_name *name, TABLE *proc_tbl);
public:
virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root)
@@ -214,15 +257,16 @@ bool load_charset(MEM_ROOT *mem_root,
CHARSET_INFO *dflt_cs,
CHARSET_INFO **cs)
{
- String cs_name;
+ LEX_CSTRING cs_name;
- if (get_field(mem_root, field, &cs_name))
+ if (field->val_str_nopad(mem_root, &cs_name))
{
*cs= dflt_cs;
return TRUE;
}
- *cs= get_charset_by_csname(cs_name.c_ptr(), MY_CS_PRIMARY, MYF(0));
+ DBUG_ASSERT(cs_name.str[cs_name.length] == 0);
+ *cs= get_charset_by_csname(cs_name.str, MY_CS_PRIMARY, MYF(0));
if (*cs == NULL)
{
@@ -240,15 +284,16 @@ bool load_collation(MEM_ROOT *mem_root,
CHARSET_INFO *dflt_cl,
CHARSET_INFO **cl)
{
- String cl_name;
+ LEX_CSTRING cl_name;
- if (get_field(mem_root, field, &cl_name))
+ if (field->val_str_nopad(mem_root, &cl_name))
{
*cl= dflt_cl;
return TRUE;
}
- *cl= get_charset_by_name(cl_name.c_ptr(), MYF(0));
+ DBUG_ASSERT(cl_name.str[cl_name.length] == 0);
+ *cl= get_charset_by_name(cl_name.str, MYF(0));
if (*cl == NULL)
{
@@ -263,8 +308,8 @@ bool load_collation(MEM_ROOT *mem_root,
Stored_routine_creation_ctx *
Stored_routine_creation_ctx::load_from_db(THD *thd,
- const sp_name *name,
- TABLE *proc_tbl)
+ const Database_qualified_name *name,
+ TABLE *proc_tbl)
{
/* Load character set/collation attributes. */
@@ -459,7 +504,6 @@ static TABLE *open_proc_table_for_update(THD *thd)
Find row in open mysql.proc table representing stored routine.
@param thd Thread context
- @param type Type of routine to find (function or procedure)
@param name Name of routine
@param table TABLE object for open mysql.proc table.
@@ -469,14 +513,16 @@ static TABLE *open_proc_table_for_update(THD *thd)
SP_KEY_NOT_FOUND No routine with given name
*/
-static int
-db_find_routine_aux(THD *thd, stored_procedure_type type, sp_name *name,
- TABLE *table)
+int
+Sp_handler::db_find_routine_aux(THD *thd,
+ const Database_qualified_name *name,
+ TABLE *table) const
{
uchar key[MAX_KEY_LENGTH]; // db, name, optional key length type
DBUG_ENTER("db_find_routine_aux");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, (int) name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("type: %s name: %.*s",
+ type_str(),
+ (int) name->m_name.length, name->m_name.str));
/*
Create key to find row. We have to use field->store() to be able to
@@ -487,10 +533,9 @@ db_find_routine_aux(THD *thd, stored_procedure_type type, sp_name *name,
*/
if (name->m_name.length > table->field[1]->field_length)
DBUG_RETURN(SP_KEY_NOT_FOUND);
- table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin);
- table->field[1]->store(name->m_name.str, name->m_name.length,
- &my_charset_bin);
- table->field[2]->store((longlong) type, TRUE);
+ table->field[0]->store(name->m_db, &my_charset_bin);
+ table->field[1]->store(name->m_name, &my_charset_bin);
+ table->field[2]->store((longlong) type(), true);
key_copy(key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -503,12 +548,67 @@ db_find_routine_aux(THD *thd, stored_procedure_type type, sp_name *name,
}
+bool st_sp_chistics::read_from_mysql_proc_row(THD *thd, TABLE *table)
+{
+ LEX_CSTRING str;
+
+ if (table->field[MYSQL_PROC_FIELD_ACCESS]->val_str_nopad(thd->mem_root,
+ &str))
+ return true;
+
+ switch (str.str[0]) {
+ case 'N':
+ daccess= SP_NO_SQL;
+ break;
+ case 'C':
+ daccess= SP_CONTAINS_SQL;
+ break;
+ case 'R':
+ daccess= SP_READS_SQL_DATA;
+ break;
+ case 'M':
+ daccess= SP_MODIFIES_SQL_DATA;
+ break;
+ default:
+ daccess= SP_DEFAULT_ACCESS_MAPPING;
+ }
+
+ if (table->field[MYSQL_PROC_FIELD_DETERMINISTIC]->val_str_nopad(thd->mem_root,
+ &str))
+ return true;
+ detistic= str.str[0] == 'N' ? false : true;
+
+ if (table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->val_str_nopad(thd->mem_root,
+ &str))
+ return true;
+ suid= str.str[0] == 'I' ? SP_IS_NOT_SUID : SP_IS_SUID;
+
+ if (table->field[MYSQL_PROC_FIELD_COMMENT]->val_str_nopad(thd->mem_root,
+ &comment))
+ return true;
+
+ return false;
+}
+
+
+bool AUTHID::read_from_mysql_proc_row(THD *thd, TABLE *table)
+{
+ LEX_CSTRING str;
+ if (table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root,
+ &str))
+ return true;
+ parse(str.str, str.length);
+ if (user.str[user.length])
+ ((char *) user.str)[user.length]= '\0'; // 0-terminate if was truncated
+ return false;
+}
+
+
/**
Find routine definition in mysql.proc table and create corresponding
sp_head object for it.
@param thd Thread context
- @param type Type of routine (TYPE_ENUM_PROCEDURE/...)
@param name Name of routine
@param sphp Out parameter in which pointer to created sp_head
object is returned (0 in case of error).
@@ -523,33 +623,27 @@ db_find_routine_aux(THD *thd, stored_procedure_type type, sp_name *name,
non-0 Error (may be one of special codes like SP_KEY_NOT_FOUND)
*/
-static int
-db_find_routine(THD *thd, stored_procedure_type type, sp_name *name,
- sp_head **sphp)
+int
+Sp_handler::db_find_routine(THD *thd,
+ const Database_qualified_name *name,
+ sp_head **sphp) const
{
TABLE *table;
- const char *params, *returns, *body;
+ LEX_CSTRING params, returns, body;
int ret;
- const char *definer;
longlong created;
longlong modified;
- st_sp_chistics chistics;
- char *ptr;
- uint length;
- char buff[65];
- String str(buff, sizeof(buff), &my_charset_bin);
+ Sp_chistics chistics;
bool saved_time_zone_used= thd->time_zone_used;
sql_mode_t sql_mode, saved_mode= thd->variables.sql_mode;
Open_tables_backup open_tables_state_backup;
Stored_program_creation_ctx *creation_ctx;
- char definer_user_name_holder[USERNAME_LENGTH + 1];
- LEX_STRING definer_user_name= { definer_user_name_holder, USERNAME_LENGTH };
- char definer_host_name_holder[HOSTNAME_LENGTH + 1];
- LEX_STRING definer_host_name= { definer_host_name_holder, HOSTNAME_LENGTH };
+ AUTHID definer;
DBUG_ENTER("db_find_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, (int) name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("type: %s name: %.*s",
+ type_str(),
+ (int) name->m_name.length, name->m_name.str));
*sphp= 0; // In case of errors
if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup)))
@@ -558,7 +652,7 @@ db_find_routine(THD *thd, stored_procedure_type type, sp_name *name,
/* Reset sql_mode during data dictionary operations. */
thd->variables.sql_mode= 0;
- if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
+ if ((ret= db_find_routine_aux(thd, name, table)) != SP_OK)
goto done;
if (table->s->fields < MYSQL_PROC_FIELD_COUNT)
@@ -567,106 +661,43 @@ db_find_routine(THD *thd, stored_procedure_type type, sp_name *name,
goto done;
}
- bzero((char *)&chistics, sizeof(chistics));
- if ((ptr= get_field(thd->mem_root,
- table->field[MYSQL_PROC_FIELD_ACCESS])) == NULL)
+ if (chistics.read_from_mysql_proc_row(thd, table) ||
+ definer.read_from_mysql_proc_row(thd, table))
{
ret= SP_GET_FIELD_FAILED;
goto done;
}
- switch (ptr[0]) {
- case 'N':
- chistics.daccess= SP_NO_SQL;
- break;
- case 'C':
- chistics.daccess= SP_CONTAINS_SQL;
- break;
- case 'R':
- chistics.daccess= SP_READS_SQL_DATA;
- break;
- case 'M':
- chistics.daccess= SP_MODIFIES_SQL_DATA;
- break;
- default:
- chistics.daccess= SP_DEFAULT_ACCESS_MAPPING;
- }
-
- if ((ptr= get_field(thd->mem_root,
- table->field[MYSQL_PROC_FIELD_DETERMINISTIC])) == NULL)
- {
- ret= SP_GET_FIELD_FAILED;
- goto done;
- }
- 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' ? SP_IS_NOT_SUID : SP_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)
+ table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
+ &params);
+ if (type() == TYPE_ENUM_PROCEDURE)
+ returns= empty_clex_str;
+ else if (table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
+ &returns))
{
ret= SP_GET_FIELD_FAILED;
goto done;
}
- if ((body= get_field(thd->mem_root,
- table->field[MYSQL_PROC_FIELD_BODY])) == NULL)
+ if (table->field[MYSQL_PROC_FIELD_BODY]->val_str_nopad(thd->mem_root,
+ &body))
{
ret= SP_GET_FIELD_FAILED;
goto done;
}
// Get additional information
- if ((definer= get_field(thd->mem_root,
- table->field[MYSQL_PROC_FIELD_DEFINER])) == NULL)
- {
- ret= SP_GET_FIELD_FAILED;
- goto done;
- }
-
modified= table->field[MYSQL_PROC_FIELD_MODIFIED]->val_int();
created= table->field[MYSQL_PROC_FIELD_CREATED]->val_int();
-
- sql_mode= (ulong) 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= thd->strmake(str.ptr(), length);
- chistics.comment.str= ptr;
- chistics.comment.length= length;
+ sql_mode= (sql_mode_t) table->field[MYSQL_PROC_FIELD_SQL_MODE]->val_int();
creation_ctx= Stored_routine_creation_ctx::load_from_db(thd, name, table);
close_system_tables(thd, &open_tables_state_backup);
table= 0;
- if (parse_user(definer, strlen(definer),
- definer_user_name.str, &definer_user_name.length,
- definer_host_name.str, &definer_host_name.length) &&
- definer_user_name.length && !definer_host_name.length)
- {
- // 'user@' -> 'user@%'
- definer_host_name= host_not_specified;
- }
-
- ret= db_load_routine(thd, type, name, sphp,
- sql_mode, params, returns, body, chistics,
- &definer_user_name, &definer_host_name,
+ ret= db_load_routine(thd, name, sphp,
+ sql_mode, params, returns, body, chistics, definer,
created, modified, creation_ctx);
done:
/*
@@ -681,6 +712,23 @@ db_find_routine(THD *thd, stored_procedure_type type, sp_name *name,
}
+int
+Sp_handler::db_find_and_cache_routine(THD *thd,
+ const Database_qualified_name *name,
+ sp_head **sp) const
+{
+ int rc= db_find_routine(thd, name, sp);
+ if (rc == SP_OK)
+ {
+ sp_cache_insert(get_cache(thd), *sp);
+ DBUG_PRINT("info", ("added new: %p, level: %lu, flags %x",
+ sp[0], sp[0]->m_recursion_level,
+ sp[0]->m_flags));
+ }
+ return rc;
+}
+
+
/**
Silence DEPRECATED SYNTAX warnings when loading a stored procedure
into the cache.
@@ -809,14 +857,17 @@ Bad_db_error_handler::handle_condition(THD *thd,
}
-static int
-db_load_routine(THD *thd, stored_procedure_type type,
- sp_name *name, sp_head **sphp,
- sql_mode_t sql_mode, const char *params, const char *returns,
- const char *body, st_sp_chistics &chistics,
- LEX_STRING *definer_user_name, LEX_STRING *definer_host_name,
- longlong created, longlong modified,
- Stored_program_creation_ctx *creation_ctx)
+int
+Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
+ sp_head **sphp,
+ sql_mode_t sql_mode,
+ const LEX_CSTRING &params,
+ const LEX_CSTRING &returns,
+ const LEX_CSTRING &body,
+ const st_sp_chistics &chistics,
+ const AUTHID &definer,
+ longlong created, longlong modified,
+ Stored_program_creation_ctx *creation_ctx) const
{
LEX *old_lex= thd->lex, newlex;
String defstr;
@@ -830,8 +881,6 @@ db_load_routine(THD *thd, stored_procedure_type type,
thd->lex= &newlex;
newlex.current_select= NULL;
- // Resetting REPLACE and EXIST flags in create_info, for show_create_sp()
- newlex.create_info.DDL_options_st::init();
defstr.set_charset(creation_ctx->get_client_cs());
@@ -841,15 +890,10 @@ db_load_routine(THD *thd, stored_procedure_type type,
definition for SHOW CREATE PROCEDURE later.
*/
- if (!show_create_sp(thd, &defstr,
- type,
- NULL, 0,
- name->m_name.str, name->m_name.length,
- params, strlen(params),
- returns, strlen(returns),
- body, strlen(body),
- &chistics, definer_user_name, definer_host_name,
- sql_mode))
+ if (show_create_sp(thd, &defstr,
+ null_clex_str, name->m_name,
+ params, returns, body,
+ chistics, definer, DDL_options(), sql_mode))
{
ret= SP_INTERNAL_ERROR;
goto end;
@@ -886,7 +930,9 @@ db_load_routine(THD *thd, stored_procedure_type type,
generate an error.
*/
- if (cur_db_changed && mysql_change_db(thd, &saved_cur_db_name, TRUE))
+ if (cur_db_changed && mysql_change_db(thd,
+ (LEX_CSTRING*) &saved_cur_db_name,
+ TRUE))
{
ret= SP_INTERNAL_ERROR;
goto end;
@@ -898,8 +944,8 @@ db_load_routine(THD *thd, stored_procedure_type type,
goto end;
}
- (*sphp)->set_definer(definer_user_name, definer_host_name);
- (*sphp)->set_info(created, modified, &chistics, sql_mode);
+ (*sphp)->set_definer(&definer.user, &definer.host);
+ (*sphp)->set_info(created, modified, chistics, sql_mode);
(*sphp)->set_creation_ctx(creation_ctx);
(*sphp)->optimize();
/*
@@ -922,7 +968,7 @@ end:
void
-sp_returns_type(THD *thd, String &result, sp_head *sp)
+sp_returns_type(THD *thd, String &result, const sp_head *sp)
{
TABLE table;
TABLE_SHARE share;
@@ -958,7 +1004,6 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
and invalidates the stored-routine cache.
@param thd Thread context.
- @param type Stored routine type (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param name Stored routine name.
@param table A pointer to the opened mysql.proc table
@@ -966,9 +1011,10 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
@return SP_OK on success, or SP_DELETE_ROW_FAILED on error.
used to indicate about errors.
*/
-static int
-sp_drop_routine_internal(THD *thd, stored_procedure_type type,
- sp_name *name, TABLE *table)
+int
+Sp_handler::sp_drop_routine_internal(THD *thd,
+ const Database_qualified_name *name,
+ TABLE *table) const
{
DBUG_ENTER("sp_drop_routine_internal");
@@ -985,10 +1031,9 @@ sp_drop_routine_internal(THD *thd, stored_procedure_type type,
local cache.
*/
sp_head *sp;
- sp_cache **spc= (type == TYPE_ENUM_FUNCTION ?
- &thd->sp_func_cache : &thd->sp_proc_cache);
- sp= sp_cache_lookup(spc, name);
- if (sp)
+ sp_cache **spc= get_cache(thd);
+ DBUG_ASSERT(spc);
+ if ((sp= sp_cache_lookup(spc, name)))
sp_cache_flush_obsolete(spc, &sp);
DBUG_RETURN(SP_OK);
}
@@ -1001,8 +1046,6 @@ sp_drop_routine_internal(THD *thd, stored_procedure_type type,
the mysql.proc.
@param thd Thread context.
- @param type Stored routine type
- (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION).
@param sp Stored routine object to store.
@note Opens and closes the thread tables. Therefore assumes
@@ -1019,16 +1062,14 @@ sp_drop_routine_internal(THD *thd, stored_procedure_type type,
*/
bool
-sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
+Sp_handler::sp_create_routine(THD *thd, const sp_head *sp) const
{
LEX *lex= thd->lex;
bool ret= TRUE;
TABLE *table;
char definer_buf[USER_HOST_BUFF_SIZE];
- LEX_STRING definer;
+ LEX_CSTRING definer;
sql_mode_t saved_mode= thd->variables.sql_mode;
- MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
- MDL_key::FUNCTION : MDL_key::PROCEDURE;
CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str);
@@ -1036,15 +1077,15 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
bool store_failed= FALSE;
DBUG_ENTER("sp_create_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s", (int) type,
+ DBUG_PRINT("enter", ("type: %s name: %.*s",
+ type_str(),
(int) sp->m_name.length,
sp->m_name.str));
+ MDL_key::enum_mdl_namespace mdl_type= get_mdl_type();
+ LEX_CSTRING returns= empty_clex_str;
String retstr(64);
retstr.set_charset(system_charset_info);
- DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
- type == TYPE_ENUM_FUNCTION);
-
/* Grab an exclusive MDL lock. */
if (lock_object_name(thd, mdl_type, sp->m_db.str, sp->m_name.str))
{
@@ -1072,17 +1113,17 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
if (!(table= open_proc_table_for_update(thd)))
{
- my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(type),sp->m_name.str);
+ my_error(ER_SP_STORE_FAILED, MYF(0), type_str(), sp->m_name.str);
goto done;
}
else
{
/* Checking if the routine already exists */
- if (db_find_routine_aux(thd, type, lex->spname, table) == SP_OK)
+ if (db_find_routine_aux(thd, sp, table) == SP_OK)
{
if (lex->create_info.or_replace())
{
- if ((ret= sp_drop_routine_internal(thd, type, lex->spname, table)))
+ if ((ret= sp_drop_routine_internal(thd, sp, table)))
goto done;
}
else if (lex->create_info.if_not_exists())
@@ -1090,20 +1131,21 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_SP_ALREADY_EXISTS,
ER_THD(thd, ER_SP_ALREADY_EXISTS),
- SP_TYPE_STRING(type),
- lex->spname->m_name.str);
+ type_str(), sp->m_name.str);
ret= FALSE;
// Setting retstr as it is used for logging.
- if (sp->m_type == TYPE_ENUM_FUNCTION)
+ if (type() == TYPE_ENUM_FUNCTION)
+ {
sp_returns_type(thd, retstr, sp);
+ returns= retstr.lex_cstring();
+ }
goto log;
}
else
{
- my_error(ER_SP_ALREADY_EXISTS, MYF(0),
- SP_TYPE_STRING(type), sp->m_name.str);
+ my_error(ER_SP_ALREADY_EXISTS, MYF(0), type_str(), sp->m_name.str);
goto done;
}
}
@@ -1115,8 +1157,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
if (table->s->fields < MYSQL_PROC_FIELD_COUNT)
{
- my_error(ER_SP_STORE_FAILED, MYF(0),
- SP_TYPE_STRING(type), sp->m_name.str);
+ my_error(ER_SP_STORE_FAILED, MYF(0), type_str(), sp->m_name.str);
goto done;
}
@@ -1136,45 +1177,46 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
store_failed=
table->field[MYSQL_PROC_FIELD_DB]->
- store(sp->m_db.str, sp->m_db.length, system_charset_info);
+ store(sp->m_db, system_charset_info);
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_NAME]->
- store(sp->m_name.str, sp->m_name.length, system_charset_info);
+ store(sp->m_name, system_charset_info);
store_failed= store_failed ||
table->field[MYSQL_PROC_MYSQL_TYPE]->
- store((longlong)type, TRUE);
+ store((longlong) type(), true);
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]->
- store(sp->m_name.str, sp->m_name.length, system_charset_info);
+ store(sp->m_name, system_charset_info);
- if (sp->m_chistics->daccess != SP_DEFAULT_ACCESS)
+ if (sp->daccess() != SP_DEFAULT_ACCESS)
{
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_ACCESS]->
- store((longlong)sp->m_chistics->daccess, TRUE);
+ store((longlong)sp->daccess(), TRUE);
}
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_DETERMINISTIC]->
- store((longlong)(sp->m_chistics->detistic ? 1 : 2), TRUE);
+ store((longlong)(sp->detistic() ? 1 : 2), TRUE);
- if (sp->m_chistics->suid != SP_IS_DEFAULT_SUID)
+ if (sp->suid() != SP_IS_DEFAULT_SUID)
{
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
- store((longlong)sp->m_chistics->suid, TRUE);
+ store((longlong)sp->suid(), TRUE);
}
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
- store(sp->m_params.str, sp->m_params.length, system_charset_info);
+ store(sp->m_params, system_charset_info);
- if (sp->m_type == TYPE_ENUM_FUNCTION)
+ if (type() == TYPE_ENUM_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
+ returns= retstr.lex_cstring();
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_RETURNS]->
@@ -1183,11 +1225,11 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_BODY]->
- store(sp->m_body.str, sp->m_body.length, system_charset_info);
+ store(sp->m_body, system_charset_info);
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_DEFINER]->
- store(definer.str, definer.length, system_charset_info);
+ store(definer, system_charset_info);
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time();
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
@@ -1196,26 +1238,25 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
table->field[MYSQL_PROC_FIELD_SQL_MODE]->
store((longlong)saved_mode, TRUE);
- if (sp->m_chistics->comment.str)
+ if (sp->comment().str)
{
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_COMMENT]->
- store(sp->m_chistics->comment.str, sp->m_chistics->comment.length,
- system_charset_info);
+ store(sp->comment(), system_charset_info);
}
- if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
+ if (type() == TYPE_ENUM_FUNCTION &&
!trust_function_creators && mysql_bin_log.is_open())
{
- if (!sp->m_chistics->detistic)
+ if (!sp->detistic())
{
/*
Note that this test is not perfect; one could use
a non-deterministic read-only function in an update statement.
*/
enum enum_sp_data_access access=
- (sp->m_chistics->daccess == SP_DEFAULT_ACCESS) ?
- SP_DEFAULT_ACCESS_MAPPING : sp->m_chistics->daccess;
+ (sp->daccess() == SP_DEFAULT_ACCESS) ?
+ SP_DEFAULT_ACCESS_MAPPING : sp->daccess();
if (access == SP_CONTAINS_SQL ||
access == SP_MODIFIES_SQL_DATA)
{
@@ -1252,7 +1293,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
table->field[MYSQL_PROC_FIELD_BODY_UTF8]->set_notnull();
store_failed= store_failed ||
table->field[MYSQL_PROC_FIELD_BODY_UTF8]->store(
- sp->m_body_utf8.str, sp->m_body_utf8.length, system_charset_info);
+ sp->m_body_utf8, system_charset_info);
if (store_failed)
{
@@ -1262,8 +1303,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
if (table->file->ha_write_row(table->record[0]))
{
- my_error(ER_SP_ALREADY_EXISTS, MYF(0),
- SP_TYPE_STRING(type), sp->m_name.str);
+ my_error(ER_SP_ALREADY_EXISTS, MYF(0), type_str(), sp->m_name.str);
goto done;
}
/* Make change permanent and avoid 'table is marked as crashed' errors */
@@ -1280,16 +1320,13 @@ log:
StringBuffer<128> log_query(thd->variables.character_set_client);
DBUG_ASSERT(log_query.charset()->mbminlen == 1);
- if (!show_create_sp(thd, &log_query,
- sp->m_type,
- (sp->m_explicit_name ? sp->m_db.str : NULL),
- (sp->m_explicit_name ? sp->m_db.length : 0),
- sp->m_name.str, sp->m_name.length,
- sp->m_params.str, sp->m_params.length,
- retstr.ptr(), retstr.length(),
- sp->m_body.str, sp->m_body.length,
- sp->m_chistics, &(thd->lex->definer->user),
- &(thd->lex->definer->host),
+ if (show_create_sp(thd, &log_query,
+ sp->m_explicit_name ? sp->m_db : null_clex_str,
+ sp->m_name,
+ sp->m_params, returns, sp->m_body,
+ sp->chistics(),
+ thd->lex->definer[0],
+ thd->lex->create_info,
saved_mode))
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -1317,6 +1354,26 @@ done:
}
+static bool
+append_suid(String *buf, enum_sp_suid_behaviour suid)
+{
+ return suid == SP_IS_NOT_SUID &&
+ buf->append(STRING_WITH_LEN(" SQL SECURITY INVOKER\n"));
+}
+
+
+static bool
+append_comment(String *buf, const LEX_CSTRING &comment)
+{
+ if (!comment.length)
+ return false;
+ if (buf->append(STRING_WITH_LEN(" COMMENT ")))
+ return true;
+ append_unescaped(buf, comment.str, comment.length);
+ return buf->append('\n');
+}
+
+
/**
Delete the record for the stored routine object from mysql.proc
and do binary logging.
@@ -1325,8 +1382,6 @@ done:
from the mysql.proc table and invalidates the stored-routine cache.
@param thd Thread context.
- @param type Stored routine type
- (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param name Stored routine name.
@return Error code. SP_OK is returned on success. Other SP_ constants are
@@ -1334,18 +1389,16 @@ done:
*/
int
-sp_drop_routine(THD *thd, stored_procedure_type type, sp_name *name)
+Sp_handler::sp_drop_routine(THD *thd,
+ const Database_qualified_name *name) const
{
TABLE *table;
int ret;
- MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
- MDL_key::FUNCTION : MDL_key::PROCEDURE;
DBUG_ENTER("sp_drop_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, (int) name->m_name.length, name->m_name.str));
-
- DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
- type == TYPE_ENUM_FUNCTION);
+ DBUG_PRINT("enter", ("type: %s name: %.*s",
+ type_str(),
+ (int) name->m_name.length, name->m_name.str));
+ MDL_key::enum_mdl_namespace mdl_type= get_mdl_type();
/* Grab an exclusive MDL lock. */
if (lock_object_name(thd, mdl_type, name->m_db.str, name->m_name.str))
@@ -1354,8 +1407,8 @@ sp_drop_routine(THD *thd, stored_procedure_type type, sp_name *name)
if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
- ret= sp_drop_routine_internal(thd, type, name, table);
+ if ((ret= db_find_routine_aux(thd, name, table)) == SP_OK)
+ ret= sp_drop_routine_internal(thd, name, table);
if (ret == SP_OK &&
write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
@@ -1378,8 +1431,6 @@ sp_drop_routine(THD *thd, stored_procedure_type type, sp_name *name)
successful update, the cache is invalidated.
@param thd Thread context.
- @param type Stored routine type
- (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param name Stored routine name.
@param chistics New values of stored routine attributes to write.
@@ -1388,20 +1439,16 @@ sp_drop_routine(THD *thd, stored_procedure_type type, sp_name *name)
*/
int
-sp_update_routine(THD *thd, stored_procedure_type type, sp_name *name,
- st_sp_chistics *chistics)
+Sp_handler::sp_update_routine(THD *thd, const Database_qualified_name *name,
+ const st_sp_chistics *chistics) const
{
TABLE *table;
int ret;
- MDL_key::enum_mdl_namespace mdl_type= type == TYPE_ENUM_FUNCTION ?
- MDL_key::FUNCTION : MDL_key::PROCEDURE;
DBUG_ENTER("sp_update_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- (int) type,
+ DBUG_PRINT("enter", ("type: %s name: %.*s",
+ type_str(),
(int) name->m_name.length, name->m_name.str));
-
- DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
- type == TYPE_ENUM_FUNCTION);
+ MDL_key::enum_mdl_namespace mdl_type= get_mdl_type();
/* Grab an exclusive MDL lock. */
if (lock_object_name(thd, mdl_type, name->m_db.str, name->m_name.str))
@@ -1410,9 +1457,9 @@ sp_update_routine(THD *thd, stored_procedure_type type, sp_name *name,
if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
+ if ((ret= db_find_routine_aux(thd, name, table)) == SP_OK)
{
- if (type == TYPE_ENUM_FUNCTION && ! trust_function_creators &&
+ if (type() == TYPE_ENUM_FUNCTION && ! trust_function_creators &&
mysql_bin_log.is_open() &&
(chistics->daccess == SP_CONTAINS_SQL ||
chistics->daccess == SP_MODIFIES_SQL_DATA))
@@ -1445,8 +1492,7 @@ sp_update_routine(THD *thd, stored_procedure_type type, sp_name *name,
table->field[MYSQL_PROC_FIELD_ACCESS]->
store((longlong)chistics->daccess, TRUE);
if (chistics->comment.str)
- table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str,
- chistics->comment.length,
+ table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment,
system_charset_info);
if ((ret= table->file->ha_update_row(table->record[1],table->record[0])) &&
ret != HA_ERR_RECORD_IS_THE_SAME)
@@ -1503,7 +1549,7 @@ public:
cases.
*/
-bool lock_db_routines(THD *thd, char *db)
+bool lock_db_routines(THD *thd, const char *db)
{
TABLE *table;
uint key_len;
@@ -1589,7 +1635,7 @@ bool lock_db_routines(THD *thd, char *db)
*/
int
-sp_drop_db_routines(THD *thd, char *db)
+sp_drop_db_routines(THD *thd, const char *db)
{
TABLE *table;
int ret;
@@ -1662,8 +1708,6 @@ err:
calls sp_head::show_create_routine() for the object.
@param thd Thread context.
- @param type Stored routine type
- (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
@param name Stored routine name.
@return Error status.
@@ -1672,18 +1716,16 @@ err:
*/
bool
-sp_show_create_routine(THD *thd, stored_procedure_type type, sp_name *name)
+Sp_handler::sp_show_create_routine(THD *thd,
+ const Database_qualified_name *name) const
{
sp_head *sp;
DBUG_ENTER("sp_show_create_routine");
- DBUG_PRINT("enter", ("name: %.*s",
+ DBUG_PRINT("enter", ("type: %s name: %.*s",
+ type_str(),
(int) name->m_name.length,
name->m_name.str));
-
- DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
- type == TYPE_ENUM_FUNCTION);
-
/*
@todo: Consider using prelocking for this code as well. Currently
SHOW CREATE PROCEDURE/FUNCTION is a dirty read of the data
@@ -1691,18 +1733,16 @@ sp_show_create_routine(THD *thd, stored_procedure_type type, sp_name *name)
It is "safe" to do as long as it doesn't affect the results
of the binary log or the query cache, which currently it does not.
*/
- if (sp_cache_routine(thd, type, name, FALSE, &sp))
+ if (sp_cache_routine(thd, name, false, &sp))
DBUG_RETURN(TRUE);
- if (sp == NULL || sp->show_create_routine(thd, type))
+ if (sp == NULL || sp->show_create_routine(thd, this))
{
/*
If we have insufficient privileges, pretend the routine
does not exist.
*/
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE",
- name->m_name.str);
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), type_str(), name->m_name.str);
DBUG_RETURN(TRUE);
}
@@ -1710,12 +1750,90 @@ sp_show_create_routine(THD *thd, stored_procedure_type type, sp_name *name)
}
+/*
+ In case of recursions, we create multiple copies of the same SP.
+ This methods checks the current recursion depth.
+ In case if the recursion limit exceeded, it throws an error
+ and returns NULL.
+ Otherwise, depending on the current recursion level, it:
+ - either returns the original SP,
+ - or makes and returns a new clone of SP
+*/
+sp_head *
+Sp_handler::sp_clone_and_link_routine(THD *thd,
+ const Database_qualified_name *name,
+ sp_head *sp) const
+{
+ DBUG_ENTER("sp_link_routine");
+ ulong level;
+ sp_head *new_sp;
+ LEX_CSTRING returns= empty_clex_str;
+
+ /*
+ String buffer for RETURNS data type must have system charset;
+ 64 -- size of "returns" column of mysql.proc.
+ */
+ String retstr(64);
+ retstr.set_charset(sp->get_creation_ctx()->get_client_cs());
+
+ DBUG_PRINT("info", ("found: %p", sp));
+ if (sp->m_first_free_instance)
+ {
+ DBUG_PRINT("info", ("first free: %p level: %lu flags %x",
+ sp->m_first_free_instance,
+ sp->m_first_free_instance->m_recursion_level,
+ sp->m_first_free_instance->m_flags));
+ DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED));
+ if (sp->m_first_free_instance->m_recursion_level > recursion_depth(thd))
+ {
+ recursion_level_error(thd, sp);
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(sp->m_first_free_instance);
+ }
+ /*
+ Actually depth could be +1 than the actual value in case a SP calls
+ SHOW CREATE PROCEDURE. Hence, the linked list could hold up to one more
+ instance.
+ */
+
+ level= sp->m_last_cached_sp->m_recursion_level + 1;
+ if (level > recursion_depth(thd))
+ {
+ recursion_level_error(thd, sp);
+ DBUG_RETURN(0);
+ }
+
+ if (type() == TYPE_ENUM_FUNCTION)
+ {
+ sp_returns_type(thd, retstr, sp);
+ returns= retstr.lex_cstring();
+ }
+ if (db_load_routine(thd, name, &new_sp,
+ sp->m_sql_mode, sp->m_params, returns,
+ sp->m_body, sp->chistics(),
+ sp->m_definer,
+ sp->m_created, sp->m_modified,
+ sp->get_creation_ctx()) == SP_OK)
+ {
+ sp->m_last_cached_sp->m_next_cached_sp= new_sp;
+ new_sp->m_recursion_level= level;
+ new_sp->m_first_instance= sp;
+ sp->m_last_cached_sp= sp->m_first_free_instance= new_sp;
+ DBUG_PRINT("info", ("added level: %p, level: %lu, flags %x",
+ new_sp, new_sp->m_recursion_level,
+ new_sp->m_flags));
+ DBUG_RETURN(new_sp);
+ }
+ DBUG_RETURN(0);
+}
+
+
/**
Obtain object representing stored procedure/function by its name from
stored procedures cache and looking into mysql.proc if needed.
@param thd thread context
- @param type type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE)
@param name name of procedure
@param cp hash to look routine in
@param cache_only if true perform cache-only lookup
@@ -1728,93 +1846,21 @@ sp_show_create_routine(THD *thd, stored_procedure_type type, sp_name *name)
*/
sp_head *
-sp_find_routine(THD *thd, stored_procedure_type type, sp_name *name,
- sp_cache **cp, bool cache_only)
+Sp_handler::sp_find_routine(THD *thd, const Database_qualified_name *name,
+ bool cache_only) const
{
- sp_head *sp;
- ulong depth= (type == TYPE_ENUM_PROCEDURE ?
- thd->variables.max_sp_recursion_depth :
- 0);
DBUG_ENTER("sp_find_routine");
- DBUG_PRINT("enter", ("name: %.*s.%.*s type: %d cache only %d",
+ DBUG_PRINT("enter", ("name: %.*s.%.*s type: %s cache only %d",
(int) name->m_db.length, name->m_db.str,
(int) name->m_name.length, name->m_name.str,
- type, cache_only));
+ type_str(), cache_only));
+ sp_cache **cp= get_cache(thd);
+ sp_head *sp;
if ((sp= sp_cache_lookup(cp, name)))
- {
- ulong level;
- sp_head *new_sp;
- const char *returns= "";
-
- /*
- String buffer for RETURNS data type must have system charset;
- 64 -- size of "returns" column of mysql.proc.
- */
- String retstr(64);
- retstr.set_charset(sp->get_creation_ctx()->get_client_cs());
-
- DBUG_PRINT("info", ("found:%p", sp));
- if (sp->m_first_free_instance)
- {
- DBUG_PRINT("info", ("first free:%p level: %lu flags %x",
- sp->m_first_free_instance,
- sp->m_first_free_instance->m_recursion_level,
- sp->m_first_free_instance->m_flags));
- DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED));
- if (sp->m_first_free_instance->m_recursion_level > depth)
- {
- sp->recursion_level_error(thd);
- DBUG_RETURN(0);
- }
- DBUG_RETURN(sp->m_first_free_instance);
- }
- /*
- Actually depth could be +1 than the actual value in case a SP calls
- SHOW CREATE PROCEDURE. Hence, the linked list could hold up to one more
- instance.
- */
-
- level= sp->m_last_cached_sp->m_recursion_level + 1;
- if (level > depth)
- {
- sp->recursion_level_error(thd);
- DBUG_RETURN(0);
- }
-
- if (type == TYPE_ENUM_FUNCTION)
- {
- sp_returns_type(thd, retstr, sp);
- returns= retstr.ptr();
- }
- if (db_load_routine(thd, type, name, &new_sp,
- sp->m_sql_mode, sp->m_params.str, returns,
- sp->m_body.str, *sp->m_chistics,
- &sp->m_definer_user, &sp->m_definer_host,
- sp->m_created, sp->m_modified,
- sp->get_creation_ctx()) == SP_OK)
- {
- sp->m_last_cached_sp->m_next_cached_sp= new_sp;
- new_sp->m_recursion_level= level;
- new_sp->m_first_instance= sp;
- sp->m_last_cached_sp= sp->m_first_free_instance= new_sp;
- DBUG_PRINT("info", ("added level:%p, level: %lu, flags %x",
- new_sp, new_sp->m_recursion_level,
- new_sp->m_flags));
- DBUG_RETURN(new_sp);
- }
- DBUG_RETURN(0);
- }
+ DBUG_RETURN(sp_clone_and_link_routine(thd, name, sp));
if (!cache_only)
- {
- if (db_find_routine(thd, type, name, &sp) == SP_OK)
- {
- sp_cache_insert(cp, sp);
- DBUG_PRINT("info", ("added new:%p, level: %lu, flags %x",
- sp, sp->m_recursion_level,
- sp->m_flags));
- }
- }
+ db_find_and_cache_routine(thd, name, &sp);
DBUG_RETURN(sp);
}
@@ -1825,8 +1871,6 @@ sp_find_routine(THD *thd, stored_procedure_type type, sp_name *name,
@param thd Thread handler
@param routines List of needles in the hay stack
- @param is_proc Indicates whether routines in the list are procedures
- or functions.
@return
@retval FALSE Found.
@@ -1834,7 +1878,7 @@ sp_find_routine(THD *thd, stored_procedure_type type, sp_name *name,
*/
bool
-sp_exist_routines(THD *thd, TABLE_LIST *routines, bool is_proc)
+Sp_handler::sp_exist_routines(THD *thd, TABLE_LIST *routines) const
{
TABLE_LIST *routine;
bool sp_object_found;
@@ -1842,20 +1886,13 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool is_proc)
for (routine= routines; routine; routine= routine->next_global)
{
sp_name *name;
- LEX_STRING lex_db;
- LEX_STRING lex_name;
- lex_db.length= strlen(routine->db);
- lex_name.length= strlen(routine->table_name);
- lex_db.str= thd->strmake(routine->db, lex_db.length);
- lex_name.str= thd->strmake(routine->table_name, lex_name.length);
- name= new sp_name(lex_db, lex_name, true);
- name->init_qname(thd);
- sp_object_found= is_proc ? sp_find_routine(thd, TYPE_ENUM_PROCEDURE,
- name, &thd->sp_proc_cache,
- FALSE) != NULL :
- sp_find_routine(thd, TYPE_ENUM_FUNCTION,
- name, &thd->sp_func_cache,
- FALSE) != NULL;
+ LEX_CSTRING lex_db;
+ LEX_CSTRING lex_name;
+ thd->make_lex_string(&lex_db, routine->db, strlen(routine->db));
+ thd->make_lex_string(&lex_name, routine->table_name,
+ strlen(routine->table_name));
+ name= new sp_name(&lex_db, &lex_name, true);
+ sp_object_found= sp_find_routine(thd, name, false) != NULL;
thd->get_stmt_da()->clear_warning_info(thd->query_id);
if (! sp_object_found)
{
@@ -1946,20 +1983,18 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
@param arena Arena in which memory for new element of the set
will be allocated
@param rt Routine name
- @param rt_type Routine type (one of TYPE_ENUM_PROCEDURE/...)
@note
Will also add element to end of 'Query_tables_list::sroutines_list' list
(and will take into account that this is an explicitly used routine).
*/
-void sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
- sp_name *rt, enum stored_procedure_type rt_type)
+void Sp_handler::add_used_routine(Query_tables_list *prelocking_ctx,
+ Query_arena *arena,
+ const Database_qualified_name *rt) const
{
- MDL_key key((rt_type == TYPE_ENUM_FUNCTION) ? MDL_key::FUNCTION :
- MDL_key::PROCEDURE,
- rt->m_db.str, rt->m_name.str);
- (void)sp_add_used_routine(prelocking_ctx, arena, &key, 0);
+ MDL_key key(get_mdl_type(), rt->m_db.str, rt->m_name.str);
+ (void) sp_add_used_routine(prelocking_ctx, arena, &key, 0);
prelocking_ctx->sroutines_list_own_last= prelocking_ctx->sroutines_list.next;
prelocking_ctx->sroutines_list_own_elements=
prelocking_ctx->sroutines_list.elements;
@@ -2086,24 +2121,24 @@ void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
prelocking until 'sp_name' is eradicated as a class.
*/
-int sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
- bool lookup_only, sp_head **sp)
+int Sroutine_hash_entry::sp_cache_routine(THD *thd,
+ bool lookup_only,
+ sp_head **sp) const
{
char qname_buff[NAME_LEN*2+1+1];
- sp_name name(&rt->mdl_request.key, qname_buff);
- MDL_key::enum_mdl_namespace mdl_type= rt->mdl_request.key.mdl_namespace();
- stored_procedure_type type= ((mdl_type == MDL_key::FUNCTION) ?
- TYPE_ENUM_FUNCTION : TYPE_ENUM_PROCEDURE);
-
+ sp_name name(&mdl_request.key, qname_buff);
+ MDL_key::enum_mdl_namespace mdl_type= mdl_request.key.mdl_namespace();
+ const Sp_handler *sph= Sp_handler::handler(mdl_type);
+ DBUG_ASSERT(sph);
/*
Check that we have an MDL lock on this routine, unless it's a top-level
CALL. The assert below should be unambiguous: the first element
in sroutines_list has an MDL lock unless it's a top-level call, or a
trigger, but triggers can't occur here (see the preceding assert).
*/
- DBUG_ASSERT(rt->mdl_request.ticket || rt == thd->lex->sroutines_list.first);
+ DBUG_ASSERT(mdl_request.ticket || this == thd->lex->sroutines_list.first);
- return sp_cache_routine(thd, type, &name, lookup_only, sp);
+ return sph->sp_cache_routine(thd, &name, lookup_only, sp);
}
@@ -2114,7 +2149,6 @@ int sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
loading.
@param[in] thd Thread context.
- @param[in] type Type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE).
@param[in] name Name of routine.
@param[in] lookup_only Only check that the routine is in the cache.
If it's not, don't try to load. If it is present,
@@ -2127,16 +2161,17 @@ int sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
@retval non-0 Error while loading routine from mysql,proc table.
*/
-int sp_cache_routine(THD *thd, enum stored_procedure_type type, sp_name *name,
- bool lookup_only, sp_head **sp)
+int Sp_handler::sp_cache_routine(THD *thd,
+ const Database_qualified_name *name,
+ bool lookup_only,
+ sp_head **sp) const
{
int ret= 0;
- sp_cache **spc= (type == TYPE_ENUM_FUNCTION ?
- &thd->sp_func_cache : &thd->sp_proc_cache);
+ sp_cache **spc= get_cache(thd);
DBUG_ENTER("sp_cache_routine");
- DBUG_ASSERT(type == TYPE_ENUM_FUNCTION || type == TYPE_ENUM_PROCEDURE);
+ DBUG_ASSERT(spc);
*sp= sp_cache_lookup(spc, name);
@@ -2150,10 +2185,9 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type, sp_name *name,
DBUG_RETURN(SP_OK);
}
- switch ((ret= db_find_routine(thd, type, name, sp)))
+ switch ((ret= db_find_and_cache_routine(thd, name, sp)))
{
case SP_OK:
- sp_cache_insert(spc, *sp);
break;
case SP_KEY_NOT_FOUND:
ret= SP_OK;
@@ -2176,20 +2210,8 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type, sp_name *name,
*/
if (! thd->is_error())
{
- /*
- SP allows full NAME_LEN chars thus he have to allocate enough
- size in bytes. Otherwise there is stack overrun could happen
- if multibyte sequence is `name`. `db` is still safe because the
- rest of the server checks agains NAME_LEN bytes and not chars.
- Hence, the overrun happens only if the name is in length > 32 and
- uses multibyte (cyrillic, greek, etc.)
- */
- char n[NAME_LEN*2+2];
-
- /* m_qname.str is not always \0 terminated */
- memcpy(n, name->m_qname.str, name->m_qname.length);
- n[name->m_qname.length]= '\0';
- my_error(ER_SP_PROC_TABLE_CORRUPT, MYF(0), n, ret);
+ my_error(ER_SP_PROC_TABLE_CORRUPT, MYF(0),
+ ErrConvDQName(name).ptr(), ret);
}
break;
}
@@ -2201,56 +2223,57 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type, sp_name *name,
Generates the CREATE... string from the table information.
@return
- Returns TRUE on success, FALSE on (alloc) failure.
+ Returns false on success, true on (alloc) failure.
*/
bool
-show_create_sp(THD *thd, String *buf,
- stored_procedure_type type,
- const char *db, ulong dblen,
- const char *name, ulong namelen,
- const char *params, ulong paramslen,
- const char *returns, ulong returnslen,
- const char *body, ulong bodylen,
- st_sp_chistics *chistics,
- const LEX_STRING *definer_user,
- const LEX_STRING *definer_host,
- sql_mode_t sql_mode)
+Sp_handler::show_create_sp(THD *thd, String *buf,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &name,
+ const LEX_CSTRING &params,
+ const LEX_CSTRING &returns,
+ const LEX_CSTRING &body,
+ const st_sp_chistics &chistics,
+ const AUTHID &definer,
+ const DDL_options_st ddl_options,
+ sql_mode_t sql_mode) const
{
sql_mode_t old_sql_mode= thd->variables.sql_mode;
/* Make some room to begin with */
- if (buf->alloc(100 + dblen + 1 + namelen + paramslen + returnslen + bodylen +
- chistics->comment.length + 10 /* length of " DEFINER= "*/ +
+ if (buf->alloc(100 + db.length + 1 + name.length +
+ params.length + returns.length +
+ chistics.comment.length + 10 /* length of " DEFINER= "*/ +
USER_HOST_BUFF_SIZE))
- return FALSE;
+ return true;
thd->variables.sql_mode= sql_mode;
buf->append(STRING_WITH_LEN("CREATE "));
- if (thd->lex->create_info.or_replace())
+ if (ddl_options.or_replace())
buf->append(STRING_WITH_LEN("OR REPLACE "));
- append_definer(thd, buf, definer_user, definer_host);
- if (type == TYPE_ENUM_FUNCTION)
- buf->append(STRING_WITH_LEN("FUNCTION "));
- else
- buf->append(STRING_WITH_LEN("PROCEDURE "));
- if (thd->lex->create_info.if_not_exists())
+ append_definer(thd, buf, &definer.user, &definer.host);
+ buf->append(type_lex_cstring());
+ buf->append(STRING_WITH_LEN(" "));
+ if (ddl_options.if_not_exists())
buf->append(STRING_WITH_LEN("IF NOT EXISTS "));
- if (dblen > 0)
+ if (db.length > 0)
{
- append_identifier(thd, buf, db, dblen);
+ append_identifier(thd, buf, db.str, db.length);
buf->append('.');
}
- append_identifier(thd, buf, name, namelen);
+ append_identifier(thd, buf, name.str, name.length);
buf->append('(');
- buf->append(params, paramslen);
+ buf->append(params);
buf->append(')');
- if (type == TYPE_ENUM_FUNCTION)
+ if (type() == TYPE_ENUM_FUNCTION)
{
- buf->append(STRING_WITH_LEN(" RETURNS "));
- buf->append(returns, returnslen);
+ if (sql_mode & MODE_ORACLE)
+ buf->append(STRING_WITH_LEN(" RETURN "));
+ else
+ buf->append(STRING_WITH_LEN(" RETURNS "));
+ buf->append(returns);
}
buf->append('\n');
- switch (chistics->daccess) {
+ switch (chistics.daccess) {
case SP_NO_SQL:
buf->append(STRING_WITH_LEN(" NO SQL\n"));
break;
@@ -2265,19 +2288,13 @@ show_create_sp(THD *thd, String *buf,
/* Do nothing */
break;
}
- if (chistics->detistic)
+ if (chistics.detistic)
buf->append(STRING_WITH_LEN(" DETERMINISTIC\n"));
- if (chistics->suid == SP_IS_NOT_SUID)
- buf->append(STRING_WITH_LEN(" SQL SECURITY INVOKER\n"));
- if (chistics->comment.length)
- {
- buf->append(STRING_WITH_LEN(" COMMENT "));
- append_unescaped(buf, chistics->comment.str, chistics->comment.length);
- buf->append('\n');
- }
- buf->append(body, bodylen);
+ append_suid(buf, chistics.suid);
+ append_comment(buf, chistics.comment);
+ buf->append(body);
thd->variables.sql_mode= old_sql_mode;
- return TRUE;
+ return false;
}
@@ -2302,28 +2319,19 @@ show_create_sp(THD *thd, String *buf,
*/
sp_head *
-sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db,
- String *name, sql_mode_t sql_mode,
- stored_procedure_type type,
- const char *returns, const char *params,
- bool *free_sp_head)
+Sp_handler::sp_load_for_information_schema(THD *thd, TABLE *proc_table,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &name,
+ const LEX_CSTRING &params,
+ const LEX_CSTRING &returns,
+ sql_mode_t sql_mode,
+ bool *free_sp_head) const
{
- const char *sp_body;
String defstr;
- struct st_sp_chistics sp_chistics;
- const LEX_STRING definer_user= {(char*)STRING_WITH_LEN("")};
- const LEX_STRING definer_host= {(char*)STRING_WITH_LEN("")};
- LEX_STRING sp_db_str;
- LEX_STRING sp_name_str;
+ const AUTHID definer= {{STRING_WITH_LEN("")}, {STRING_WITH_LEN("")}};
sp_head *sp;
- sp_cache **spc= ((type == TYPE_ENUM_PROCEDURE) ?
- &thd->sp_proc_cache : &thd->sp_func_cache);
- sp_db_str.str= db->c_ptr();
- sp_db_str.length= db->length();
- sp_name_str.str= name->c_ptr();
- sp_name_str.length= name->length();
- sp_name sp_name_obj(sp_db_str, sp_name_str, true);
- sp_name_obj.init_qname(thd);
+ sp_cache **spc= get_cache(thd);
+ sp_name sp_name_obj(&db, &name, true); // This can change "name"
*free_sp_head= 0;
if ((sp= sp_cache_lookup(spc, &sp_name_obj)))
{
@@ -2333,16 +2341,11 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db,
LEX *old_lex= thd->lex, newlex;
Stored_program_creation_ctx *creation_ctx=
Stored_routine_creation_ctx::load_from_db(thd, &sp_name_obj, proc_table);
- sp_body= (type == TYPE_ENUM_FUNCTION ? "RETURN NULL" : "BEGIN END");
- bzero((char*) &sp_chistics, sizeof(sp_chistics));
defstr.set_charset(creation_ctx->get_client_cs());
- if (!show_create_sp(thd, &defstr, type,
- sp_db_str.str, sp_db_str.length,
- sp_name_obj.m_name.str, sp_name_obj.m_name.length,
- params, strlen(params),
- returns, strlen(returns),
- sp_body, strlen(sp_body),
- &sp_chistics, &definer_user, &definer_host, sql_mode))
+ if (show_create_sp(thd, &defstr,
+ sp_name_obj.m_db, sp_name_obj.m_name,
+ params, returns, empty_body_lex_cstring(),
+ Sp_chistics(), definer, DDL_options(), sql_mode))
return 0;
thd->lex= &newlex;