summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2017-07-31 23:00:59 +0400
committerAlexander Barkov <bar@mariadb.org>2017-07-31 23:00:59 +0400
commitc431eafd62bae41dd89a6b71e4554facbad1040b (patch)
treef8e64bee7cba1d3a70f88e57be85a23e890b16be /sql
parente67b816451cb1003fc42755e40327411fd8b7a35 (diff)
parentc9218ff43989bf2385d1f62b45ed1f6229cbc5a5 (diff)
downloadmariadb-git-c431eafd62bae41dd89a6b71e4554facbad1040b.tar.gz
Merge remote-tracking branch 'origin/bb-10.2-ext' into 10.3
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc19
-rw-r--r--sql/field.h15
-rw-r--r--sql/item_create.cc2
-rw-r--r--sql/item_func.cc11
-rw-r--r--sql/sp.cc618
-rw-r--r--sql/sp.h331
-rw-r--r--sql/sp_head.cc132
-rw-r--r--sql/sp_head.h38
-rw-r--r--sql/sql_acl.cc173
-rw-r--r--sql/sql_acl.h11
-rw-r--r--sql/sql_base.cc4
-rw-r--r--sql/sql_class.cc30
-rw-r--r--sql/sql_lex.cc22
-rw-r--r--sql/sql_lex.h17
-rw-r--r--sql/sql_parse.cc71
-rw-r--r--sql/sql_parse.h11
-rw-r--r--sql/sql_prepare.cc9
-rw-r--r--sql/sql_select.cc8
-rw-r--r--sql/sql_show.cc141
-rw-r--r--sql/sql_string.h1
-rw-r--r--sql/sql_yacc.yy27
-rw-r--r--sql/sql_yacc_ora.yy42
-rw-r--r--sql/structs.h2
-rw-r--r--sql/wsrep_mysqld.cc21
24 files changed, 985 insertions, 771 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 6320121d1c3..fbb2ad79ba9 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -10773,3 +10773,22 @@ void Field::register_field_in_read_map()
}
bitmap_set_bit(table->read_set, field_index);
}
+
+
+bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
+{
+ StringBuffer<MAX_FIELD_WIDTH> str;
+ bool rc= false;
+ THD *thd= get_thd();
+ sql_mode_t sql_mode_backup= thd->variables.sql_mode;
+ thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+
+ val_str(&str);
+ if (!(to->length= str.length()))
+ *to= empty_clex_str;
+ else if ((rc= !(to->str= strmake_root(mem_root, str.ptr(), str.length()))))
+ to->length= 0;
+
+ thd->variables.sql_mode= sql_mode_backup;
+ return rc;
+}
diff --git a/sql/field.h b/sql/field.h
index 208941b3daa..cb8ade55090 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -839,6 +839,21 @@ public:
*/
virtual String *val_str(String*,String *)=0;
String *val_int_as_str(String *val_buffer, bool unsigned_flag);
+ /*
+ Return the field value as a LEX_CSTRING, without padding to full length
+ (MODE_PAD_CHAR_TO_FULL_LENGTH is temporarily suppressed during the call).
+
+ In case of an empty value, to[0] is assigned to empty_clex_string,
+ memory is not allocated.
+ In case of a non-empty value, the memory is allocated on mem_root.
+ In case of a memory allocation failure, to[0] is assigned to {NULL,0}.
+
+ @param [IN] mem_root store non-empty values here
+ @param [OUT to return the string here
+ @retval false (success)
+ @retval true (EOM)
+ */
+ bool val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to);
fast_field_copier get_fast_field_copier(const Field *from);
/*
str_needs_quotes() returns TRUE if the value returned by val_str() needs
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 8ab45e5dbe1..50f524bad40 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -3424,7 +3424,7 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name,
arg_count= item_list->elements;
qname= new (thd->mem_root) sp_name(db, name, use_explicit_name);
- sp_add_used_routine(lex, thd, qname, TYPE_ENUM_FUNCTION);
+ sp_handler_function.add_used_routine(lex, thd, qname);
if (arg_count > 0)
func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(), qname,
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 10c5944995b..8ab5fd5f739 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -6265,8 +6265,7 @@ Item_func_sp::init_result_field(THD *thd)
DBUG_ASSERT(m_sp == NULL);
DBUG_ASSERT(sp_result_field == NULL);
- if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
- &thd->sp_func_cache, TRUE)))
+ if (!(m_sp= sp_handler_function.sp_find_routine(thd, m_name, true)))
{
my_missing_function_error (m_name->m_name, ErrConvDQName(m_name).ptr());
context->process_error(thd);
@@ -6515,7 +6514,8 @@ Item_func_sp::sp_check_access(THD *thd)
DBUG_ENTER("Item_func_sp::sp_check_access");
DBUG_ASSERT(m_sp);
if (check_routine_access(thd, EXECUTE_ACL,
- m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
+ m_sp->m_db.str, m_sp->m_name.str,
+ &sp_handler_function, false))
DBUG_RETURN(TRUE);
DBUG_RETURN(FALSE);
@@ -6541,7 +6541,8 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
thd->security_ctx= context->security_ctx;
res= check_routine_access(thd, EXECUTE_ACL, m_name->m_db.str,
- m_name->m_name.str, 0, FALSE);
+ m_name->m_name.str,
+ &sp_handler_function, false);
thd->security_ctx= save_security_ctx;
if (res)
@@ -6584,7 +6585,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
Try to set and restore the security context to see whether it's valid
*/
Security_context *save_secutiry_ctx;
- res= set_routine_security_ctx(thd, m_sp, false, &save_secutiry_ctx);
+ res= set_routine_security_ctx(thd, m_sp, &save_secutiry_ctx);
if (!res)
m_sp->m_security_ctx.restore_security_context(thd, save_secutiry_ctx);
diff --git a/sql/sp.cc b/sql/sp.cc
index c80078ebe19..8aefb8b3a34 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) stored_procedure_type_to_str(type)
-
-static int
-db_load_routine(THD *thd, stored_procedure_type type, const sp_name *name,
- sp_head **sphp,
- sql_mode_t sql_mode, const char *params, const char *returns,
- const char *body, const st_sp_chistics &chistics,
- LEX_CSTRING *definer_user_name,
- LEX_CSTRING *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] =
@@ -176,7 +218,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 +256,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 +283,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 +307,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 +503,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,15 +512,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,
- const Database_qualified_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
@@ -490,7 +534,7 @@ db_find_routine_aux(THD *thd, stored_procedure_type type,
DBUG_RETURN(SP_KEY_NOT_FOUND);
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);
+ table->field[2]->store((longlong) type(), true);
key_copy(key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -503,12 +547,67 @@ db_find_routine_aux(THD *thd, stored_procedure_type type,
}
+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 +622,27 @@ db_find_routine_aux(THD *thd, stored_procedure_type type,
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, const 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;
Sp_chistics chistics;
- char *ptr;
- uint length;
- char buff[65];
- String str(buff, sizeof(buff), &my_charset_bin);
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_CSTRING definer_user_name= { definer_user_name_holder, USERNAME_LENGTH };
- char definer_host_name_holder[HOSTNAME_LENGTH + 1];
- LEX_CSTRING 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 +651,7 @@ db_find_routine(THD *thd, stored_procedure_type type, const 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 +660,43 @@ db_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
goto done;
}
- if ((ptr= get_field(thd->mem_root,
- table->field[MYSQL_PROC_FIELD_ACCESS])) == NULL)
- {
- 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)
+ if (chistics.read_from_mysql_proc_row(thd, table) ||
+ definer.read_from_mysql_proc_row(thd, table))
{
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;
-
creation_ctx= Stored_routine_creation_ctx::load_from_db(thd, name, table);
close_system_tables(thd, &open_tables_state_backup);
table= 0;
- /* It's ok to cast to char* here as the pointers are to local buffers */
- if (parse_user(definer, strlen(definer),
- (char*) definer_user_name.str, &definer_user_name.length,
- (char*) 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:
/*
@@ -808,15 +838,17 @@ Bad_db_error_handler::handle_condition(THD *thd,
}
-static int
-db_load_routine(THD *thd, stored_procedure_type type,
- const sp_name *name, sp_head **sphp,
- sql_mode_t sql_mode, const char *params, const char *returns,
- const char *body, const st_sp_chistics &chistics,
- LEX_CSTRING *definer_user_name,
- LEX_CSTRING *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;
@@ -842,14 +874,9 @@ db_load_routine(THD *thd, stored_procedure_type type,
*/
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))
+ null_clex_str, name->m_name,
+ params, returns, body,
+ chistics, definer, sql_mode))
{
ret= SP_INTERNAL_ERROR;
goto end;
@@ -900,7 +927,7 @@ db_load_routine(THD *thd, stored_procedure_type type,
goto end;
}
- (*sphp)->set_definer(definer_user_name, definer_host_name);
+ (*sphp)->set_definer(&definer.user, &definer.host);
(*sphp)->set_info(created, modified, chistics, sql_mode);
(*sphp)->set_creation_ctx(creation_ctx);
(*sphp)->optimize();
@@ -924,7 +951,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;
@@ -960,7 +987,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
@@ -968,9 +994,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,
- const Database_qualified_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");
@@ -987,10 +1014,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);
}
@@ -1003,8 +1029,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
@@ -1021,7 +1045,7 @@ 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;
@@ -1029,8 +1053,6 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
char definer_buf[USER_HOST_BUFF_SIZE];
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);
@@ -1038,15 +1060,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))
{
@@ -1074,17 +1096,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, sp, 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, sp, table)))
+ if ((ret= sp_drop_routine_internal(thd, sp, table)))
goto done;
}
else if (lex->create_info.if_not_exists())
@@ -1092,20 +1114,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),
- sp->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;
}
}
@@ -1117,8 +1140,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;
}
@@ -1146,7 +1168,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
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]->
@@ -1174,9 +1196,10 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
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]->
@@ -1205,7 +1228,7 @@ sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp)
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->detistic())
@@ -1263,8 +1286,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 */
@@ -1282,16 +1304,11 @@ log:
log_query.set_charset(system_charset_info);
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->chistics(), &(thd->lex->definer->user),
- &(thd->lex->definer->host),
- saved_mode))
+ 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],
+ saved_mode))
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
goto done;
@@ -1326,8 +1343,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
@@ -1335,18 +1350,16 @@ done:
*/
int
-sp_drop_routine(THD *thd, stored_procedure_type type, const 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))
@@ -1355,8 +1368,8 @@ sp_drop_routine(THD *thd, stored_procedure_type type, const 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()))
@@ -1379,8 +1392,6 @@ sp_drop_routine(THD *thd, stored_procedure_type type, const 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.
@@ -1389,20 +1400,16 @@ sp_drop_routine(THD *thd, stored_procedure_type type, const sp_name *name)
*/
int
-sp_update_routine(THD *thd, stored_procedure_type type, const sp_name *name,
- const 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))
@@ -1411,9 +1418,9 @@ sp_update_routine(THD *thd, stored_procedure_type type, const 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))
@@ -1662,8 +1669,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,19 +1677,16 @@ err:
*/
bool
-sp_show_create_routine(THD *thd,
- stored_procedure_type type, const 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
@@ -1692,17 +1694,16 @@ sp_show_create_routine(THD *thd,
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), stored_procedure_type_to_str(type),
- name->m_name.str);
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), type_str(), name->m_name.str);
DBUG_RETURN(TRUE);
}
@@ -1715,7 +1716,6 @@ sp_show_create_routine(THD *thd,
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,24 +1728,22 @@ sp_show_create_routine(THD *thd,
*/
sp_head *
-sp_find_routine(THD *thd, stored_procedure_type type, const 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_cache **cp= get_cache(thd);
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));
if ((sp= sp_cache_lookup(cp, name)))
{
ulong level;
sp_head *new_sp;
- const char *returns= "";
+ LEX_CSTRING returns= empty_clex_str;
/*
String buffer for RETURNS data type must have system charset;
@@ -1762,9 +1760,9 @@ sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
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)
+ if (sp->m_first_free_instance->m_recursion_level > recursion_depth(thd))
{
- sp->recursion_level_error(thd);
+ recursion_level_error(thd, sp);
DBUG_RETURN(0);
}
DBUG_RETURN(sp->m_first_free_instance);
@@ -1776,21 +1774,21 @@ sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
*/
level= sp->m_last_cached_sp->m_recursion_level + 1;
- if (level > depth)
+ if (level > recursion_depth(thd))
{
- sp->recursion_level_error(thd);
+ recursion_level_error(thd, sp);
DBUG_RETURN(0);
}
- if (type == TYPE_ENUM_FUNCTION)
+ if (type() == TYPE_ENUM_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
- returns= retstr.ptr();
+ returns= retstr.lex_cstring();
}
- if (db_load_routine(thd, type, name, &new_sp,
- sp->m_sql_mode, sp->m_params.str, returns,
- sp->m_body.str, sp->chistics(),
- &sp->m_definer.user, &sp->m_definer.host,
+ 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)
{
@@ -1807,7 +1805,7 @@ sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
}
if (!cache_only)
{
- if (db_find_routine(thd, type, name, &sp) == SP_OK)
+ if (db_find_routine(thd, name, &sp) == SP_OK)
{
sp_cache_insert(cp, sp);
DBUG_PRINT("info", ("added new: 0x%lx, level: %lu, flags %x",
@@ -1825,8 +1823,6 @@ sp_find_routine(THD *thd, stored_procedure_type type, const 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 +1830,7 @@ sp_find_routine(THD *thd, stored_procedure_type type, const 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;
@@ -1848,12 +1844,7 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool is_proc)
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= 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;
+ sp_object_found= sp_find_routine(thd, name, false) != NULL;
thd->get_stmt_da()->clear_warning_info(thd->query_id);
if (! sp_object_found)
{
@@ -1944,20 +1935,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,
- const 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;
@@ -2084,24 +2073,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);
}
@@ -2112,7 +2101,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,
@@ -2125,17 +2113,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,
- const 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);
@@ -2149,7 +2137,7 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type,
DBUG_RETURN(SP_OK);
}
- switch ((ret= db_find_routine(thd, type, name, sp)))
+ switch ((ret= db_find_routine(thd, name, sp)))
{
case SP_OK:
sp_cache_insert(spc, *sp);
@@ -2191,21 +2179,20 @@ int sp_cache_routine(THD *thd, enum stored_procedure_type type,
Returns TRUE on success, FALSE 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,
- const st_sp_chistics &chistics,
- const LEX_CSTRING *definer_user,
- const LEX_CSTRING *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,
+ 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 +
+ 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;
@@ -2214,30 +2201,28 @@ show_create_sp(THD *thd, String *buf,
buf->append(STRING_WITH_LEN("CREATE "));
if (thd->lex->create_info.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 "));
+ append_definer(thd, buf, &definer.user, &definer.host);
+ buf->append(type_lex_cstring());
+ buf->append(STRING_WITH_LEN(" "));
if (thd->lex->create_info.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)
{
if (sql_mode & MODE_ORACLE)
buf->append(STRING_WITH_LEN(" RETURN "));
else
buf->append(STRING_WITH_LEN(" RETURNS "));
- buf->append(returns, returnslen);
+ buf->append(returns);
}
buf->append('\n');
switch (chistics.daccess) {
@@ -2265,7 +2250,7 @@ show_create_sp(THD *thd, String *buf,
append_unescaped(buf, chistics.comment.str, chistics.comment.length);
buf->append('\n');
}
- buf->append(body, bodylen);
+ buf->append(body);
thd->variables.sql_mode= old_sql_mode;
return TRUE;
}
@@ -2292,26 +2277,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;
- const LEX_CSTRING definer_user= {STRING_WITH_LEN("")};
- const LEX_CSTRING definer_host= {STRING_WITH_LEN("")};
- LEX_CSTRING sp_db_str;
- LEX_CSTRING 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_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)))
{
@@ -2321,15 +2299,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");
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, sql_mode))
return 0;
thd->lex= &newlex;
diff --git a/sql/sp.h b/sql/sp.h
index dc93b8b20ee..060596bda1f 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -17,7 +17,10 @@
#ifndef _SP_H_
#define _SP_H_
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_string.h" // LEX_STRING
+#include "sql_cmd.h"
+#include "mdl.h"
class Field;
class Open_tables_backup;
@@ -28,8 +31,10 @@ class Sroutine_hash_entry;
class THD;
class sp_cache;
class sp_head;
-class sp_name;
+class sp_pcontext;
+class Database_qualified_name;
struct st_sp_chistics;
+class Stored_program_creation_ctx;
struct LEX;
struct TABLE;
struct TABLE_LIST;
@@ -49,19 +54,268 @@ enum stored_procedure_type
};
-static inline const char *
-stored_procedure_type_to_str(enum stored_procedure_type type)
+class Sp_handler
+{
+ int db_find_routine_aux(THD *thd, const Database_qualified_name *name,
+ TABLE *table) const;
+ int db_find_routine(THD *thd, const Database_qualified_name *name,
+ sp_head **sphp) const;
+ int 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;
+ int sp_drop_routine_internal(THD *thd,
+ const Database_qualified_name *name,
+ TABLE *table) const;
+public:
+ static const Sp_handler *handler(enum enum_sql_command cmd);
+ static const Sp_handler *handler(stored_procedure_type type);
+ static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns);
+ const char *type_str() const { return type_lex_cstring().str; }
+ virtual const char *show_create_routine_col1_caption() const
+ {
+ DBUG_ASSERT(0);
+ return "";
+ }
+ virtual const char *show_create_routine_col3_caption() const
+ {
+ DBUG_ASSERT(0);
+ return "";
+ }
+ virtual stored_procedure_type type() const= 0;
+ virtual LEX_CSTRING type_lex_cstring() const= 0;
+ virtual LEX_CSTRING empty_body_lex_cstring() const
+ {
+ static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("???")};
+ DBUG_ASSERT(0);
+ return m_empty_body;
+ }
+ virtual MDL_key::enum_mdl_namespace get_mdl_type() const= 0;
+ virtual sp_cache **get_cache(THD *) const { return NULL; }
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ virtual HASH *get_priv_hash() const { return NULL; }
+#endif
+ virtual ulong recursion_depth(THD *thd) const { return 0; }
+ /**
+ Return appropriate error about recursion limit reaching
+
+ @param thd Thread handle
+ @param sp SP routine
+
+ @remark For functions and triggers we return error about
+ prohibited recursion. For stored procedures we
+ return about reaching recursion limit.
+ */
+ virtual void recursion_level_error(THD *thd, const sp_head *sp) const
+ {
+ my_error(ER_SP_NO_RECURSION, MYF(0));
+ }
+ virtual bool add_instr_freturn(THD *thd, sp_head *sp,
+ sp_pcontext *spcont,
+ Item *item, LEX *lex) const;
+ virtual bool add_instr_preturn(THD *thd, sp_head *sp,
+ sp_pcontext *spcont) const;
+
+ void add_used_routine(Query_tables_list *prelocking_ctx,
+ Query_arena *arena,
+ const Database_qualified_name *rt) const;
+
+ sp_head *sp_find_routine(THD *thd, const Database_qualified_name *name,
+ bool cache_only) const;
+ int sp_cache_routine(THD *thd, const Database_qualified_name *name,
+ bool lookup_only, sp_head **sp) const;
+
+ bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const;
+ bool sp_show_create_routine(THD *thd,
+ const Database_qualified_name *name) const;
+
+ bool sp_create_routine(THD *thd, const sp_head *sp) const;
+
+ int sp_update_routine(THD *thd, const Database_qualified_name *name,
+ const st_sp_chistics *chistics) const;
+
+ int sp_drop_routine(THD *thd, const Database_qualified_name *name) const;
+
+ sp_head *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;
+
+ bool 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,
+ sql_mode_t sql_mode) const;
+};
+
+
+class Sp_handler_procedure: public Sp_handler
+{
+public:
+ stored_procedure_type type() const { return TYPE_ENUM_PROCEDURE; }
+ LEX_CSTRING type_lex_cstring() const
+ {
+ static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("PROCEDURE")};
+ return m_type_str;
+ }
+ LEX_CSTRING empty_body_lex_cstring() const
+ {
+ static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("BEGIN END")};
+ return m_empty_body;
+ }
+ const char *show_create_routine_col1_caption() const
+ {
+ return "Procedure";
+ }
+ const char *show_create_routine_col3_caption() const
+ {
+ return "Create Procedure";
+ }
+ MDL_key::enum_mdl_namespace get_mdl_type() const
+ {
+ return MDL_key::PROCEDURE;
+ }
+ sp_cache **get_cache(THD *) const;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ HASH *get_priv_hash() const;
+#endif
+ ulong recursion_depth(THD *thd) const;
+ void recursion_level_error(THD *thd, const sp_head *sp) const;
+ bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const;
+};
+
+
+class Sp_handler_function: public Sp_handler
+{
+public:
+ stored_procedure_type type() const { return TYPE_ENUM_FUNCTION; }
+ LEX_CSTRING type_lex_cstring() const
+ {
+ static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("FUNCTION")};
+ return m_type_str;
+ }
+ LEX_CSTRING empty_body_lex_cstring() const
+ {
+ static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("RETURN NULL")};
+ return m_empty_body;
+ }
+ const char *show_create_routine_col1_caption() const
+ {
+ return "Function";
+ }
+ const char *show_create_routine_col3_caption() const
+ {
+ return "Create Function";
+ }
+ MDL_key::enum_mdl_namespace get_mdl_type() const
+ {
+ return MDL_key::FUNCTION;
+ }
+ sp_cache **get_cache(THD *) const;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ HASH *get_priv_hash() const;
+#endif
+ bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont,
+ Item *item, LEX *lex) const;
+};
+
+
+class Sp_handler_trigger: public Sp_handler
+{
+public:
+ stored_procedure_type type() const { return TYPE_ENUM_TRIGGER; }
+ LEX_CSTRING type_lex_cstring() const
+ {
+ static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("TRIGGER")};
+ return m_type_str;
+ }
+ MDL_key::enum_mdl_namespace get_mdl_type() const
+ {
+ DBUG_ASSERT(0);
+ return MDL_key::TRIGGER;
+ }
+};
+
+
+extern MYSQL_PLUGIN_IMPORT Sp_handler_function sp_handler_function;
+extern MYSQL_PLUGIN_IMPORT Sp_handler_procedure sp_handler_procedure;
+extern MYSQL_PLUGIN_IMPORT Sp_handler_trigger sp_handler_trigger;
+
+
+inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd)
+{
+ switch (cmd) {
+ case SQLCOM_CREATE_PROCEDURE:
+ case SQLCOM_ALTER_PROCEDURE:
+ case SQLCOM_DROP_PROCEDURE:
+ case SQLCOM_SHOW_PROC_CODE:
+ case SQLCOM_SHOW_CREATE_PROC:
+ case SQLCOM_SHOW_STATUS_PROC:
+ return &sp_handler_procedure;
+ case SQLCOM_CREATE_SPFUNCTION:
+ case SQLCOM_ALTER_FUNCTION:
+ case SQLCOM_DROP_FUNCTION:
+ case SQLCOM_SHOW_FUNC_CODE:
+ case SQLCOM_SHOW_CREATE_FUNC:
+ case SQLCOM_SHOW_STATUS_FUNC:
+ return &sp_handler_function;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+
+inline const Sp_handler *Sp_handler::handler(stored_procedure_type type)
{
switch (type) {
- case TYPE_ENUM_PROCEDURE: return "PROCEDURE";
- case TYPE_ENUM_FUNCTION: return "FUNCTION";
- case TYPE_ENUM_TRIGGER: return "TRIGGER";
- case TYPE_ENUM_PROXY: return "PROXY";
+ case TYPE_ENUM_PROCEDURE:
+ return &sp_handler_procedure;
+ case TYPE_ENUM_FUNCTION:
+ return &sp_handler_function;
+ case TYPE_ENUM_TRIGGER:
+ return &sp_handler_trigger;
+ case TYPE_ENUM_PROXY:
+ break;
}
- DBUG_ASSERT(0);
- return "UNKNOWN_STORED_";
+ return NULL;
}
+
+inline const Sp_handler *Sp_handler::handler(MDL_key::enum_mdl_namespace type)
+{
+ switch (type) {
+ case MDL_key::FUNCTION:
+ return &sp_handler_function;
+ case MDL_key::PROCEDURE:
+ return &sp_handler_procedure;
+ case MDL_key::GLOBAL:
+ case MDL_key::SCHEMA:
+ case MDL_key::TABLE:
+ case MDL_key::TRIGGER:
+ case MDL_key::EVENT:
+ case MDL_key::COMMIT:
+ case MDL_key::USER_LOCK:
+ case MDL_key::NAMESPACE_END:
+ break;
+ }
+ return NULL;
+}
+
+
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
@@ -121,36 +375,6 @@ sp_drop_db_routines(THD *thd, const char *db);
*/
bool lock_db_routines(THD *thd, const char *db);
-sp_head *
-sp_find_routine(THD *thd, stored_procedure_type type, const sp_name *name,
- sp_cache **cp, bool cache_only);
-
-int
-sp_cache_routine(THD *thd, Sroutine_hash_entry *rt,
- bool lookup_only, sp_head **sp);
-
-
-int
-sp_cache_routine(THD *thd, stored_procedure_type type, const sp_name *name,
- bool lookup_only, sp_head **sp);
-
-bool
-sp_exist_routines(THD *thd, TABLE_LIST *procs, bool is_proc);
-
-bool
-sp_show_create_routine(THD *thd, stored_procedure_type type, const sp_name *name);
-
-bool
-sp_create_routine(THD *thd, stored_procedure_type type, sp_head *sp);
-
-int
-sp_update_routine(THD *thd, stored_procedure_type type, const sp_name *name,
- const st_sp_chistics *chistics);
-
-int
-sp_drop_routine(THD *thd, stored_procedure_type type, const sp_name *name);
-
-
/**
Structure that represents element in the set of stored routines
used by statement or routine.
@@ -185,14 +409,11 @@ public:
changes.
*/
ulong m_sp_cache_version;
+
+ int sp_cache_routine(THD *thd, bool lookup_only, sp_head **sp) const;
};
-/*
- Procedures for handling sets of stored routines used by statement or routine.
-*/
-void sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
- const sp_name *rt, stored_procedure_type rt_type);
bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
const MDL_key *key, TABLE_LIST *belong_to_view);
void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx);
@@ -212,13 +433,6 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
*/
TABLE *open_proc_table_for_read(THD *thd, Open_tables_backup *backup);
-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);
-
bool load_charset(MEM_ROOT *mem_root,
Field *field,
CHARSET_INFO *dflt_cs,
@@ -231,17 +445,6 @@ bool load_collation(MEM_ROOT *mem_root,
void sp_returns_type(THD *thd,
String &result,
- sp_head *sp);
-
-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,
- const st_sp_chistics &chistics,
- const LEX_CSTRING *definer_user,
- const LEX_CSTRING *definer_host,
- sql_mode_t sql_mode);
+ const sp_head *sp);
+
#endif /* _SP_H_ */
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index bb3275316cc..9737169ede6 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -540,10 +540,10 @@ sp_head::operator delete(void *ptr, size_t size) throw()
}
-sp_head::sp_head(stored_procedure_type type)
+sp_head::sp_head(const Sp_handler *sph)
:Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP),
Database_qualified_name(&null_clex_str, &null_clex_str),
- m_type(type),
+ m_handler(sph),
m_flags(0),
m_explicit_name(false),
/*
@@ -610,7 +610,7 @@ sp_head::init(LEX *lex)
void
-sp_head::init_sp_name(THD *thd, sp_name *spname)
+sp_head::init_sp_name(THD *thd, const sp_name *spname)
{
DBUG_ENTER("sp_head::init_sp_name");
@@ -733,7 +733,7 @@ sp_head::~sp_head()
Field *
sp_head::create_result_field(uint field_max_length, const LEX_CSTRING *field_name,
- TABLE *table)
+ TABLE *table) const
{
Field *field;
LEX_CSTRING name;
@@ -960,30 +960,15 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
}
-/**
- Return appropriate error about recursion limit reaching
-
- @param thd Thread handle
-
- @remark For functions and triggers we return error about
- prohibited recursion. For stored procedures we
- return about reaching recursion limit.
-*/
-
-void sp_head::recursion_level_error(THD *thd)
+void Sp_handler_procedure::recursion_level_error(THD *thd,
+ const sp_head *sp) const
{
- if (m_type == TYPE_ENUM_PROCEDURE)
- {
- my_error(ER_SP_RECURSION_LIMIT, MYF(0),
- static_cast<int>(thd->variables.max_sp_recursion_depth),
- m_name.str);
- }
- else
- my_error(ER_SP_NO_RECURSION, MYF(0));
+ my_error(ER_SP_RECURSION_LIMIT, MYF(0),
+ static_cast<int>(thd->variables.max_sp_recursion_depth),
+ sp->m_name.str);
}
-
/**
Execute the routine. The main instruction jump loop is there.
Assume the parameters already set.
@@ -1391,7 +1376,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
@param thd thread handle
@param sp stored routine to change the context for
- @param is_proc TRUE is procedure, FALSE if function
@param save_ctx pointer to an old security context
@todo
@@ -1406,8 +1390,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
*/
bool
-set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
- Security_context **save_ctx)
+set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx)
{
*save_ctx= 0;
if (sp->suid() != SP_IS_NOT_SUID &&
@@ -1429,7 +1412,7 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
*/
if (*save_ctx &&
check_routine_access(thd, EXECUTE_ACL,
- sp->m_db.str, sp->m_name.str, is_proc, FALSE))
+ sp->m_db.str, sp->m_name.str, sp->m_handler, false))
{
sp->m_security_ctx.restore_security_context(thd, *save_ctx);
*save_ctx= 0;
@@ -1450,20 +1433,17 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
so we can omit the security context switch for performance purposes.
@param thd
- @param sphead
- @param is_proc
- @param root_pctx
@param ret_value
@retval NULL - error (access denided or EOM)
@retval !NULL - success (the invoker has rights to all %TYPE tables)
*/
-sp_rcontext *sp_head::rcontext_create(THD *thd, bool is_proc, Field *ret_value)
+sp_rcontext *sp_head::rcontext_create(THD *thd, Field *ret_value)
{
bool has_column_type_refs= m_flags & HAS_COLUMN_TYPE_REFS;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx;
if (has_column_type_refs &&
- set_routine_security_ctx(thd, this, is_proc, &save_security_ctx))
+ set_routine_security_ctx(thd, this, &save_security_ctx))
return NULL;
#endif
sp_rcontext *res= sp_rcontext::create(thd, m_pcont, ret_value,
@@ -1689,7 +1669,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
- if (!(nctx= rcontext_create(thd, false, return_value_fld)))
+ if (!(nctx= rcontext_create(thd, return_value_fld)))
{
thd->restore_active_arena(&call_arena, &backup_arena);
err_status= TRUE;
@@ -1760,7 +1740,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx;
- if (set_routine_security_ctx(thd, this, FALSE, &save_security_ctx))
+ if (set_routine_security_ctx(thd, this, &save_security_ctx))
{
err_status= TRUE;
goto err_with_cleanup;
@@ -1904,7 +1884,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (! octx)
{
/* Create a temporary old context. */
- if (!(octx= rcontext_create(thd, true, NULL)))
+ if (!(octx= rcontext_create(thd, NULL)))
{
DBUG_PRINT("error", ("Could not create octx"));
DBUG_RETURN(TRUE);
@@ -1919,7 +1899,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
thd->spcont->callers_arena= thd;
}
- if (!(nctx= rcontext_create(thd, true, NULL)))
+ if (!(nctx= rcontext_create(thd, NULL)))
{
delete nctx; /* Delete nctx if it was init() that failed. */
thd->spcont= save_spcont;
@@ -2042,7 +2022,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx= 0;
if (!err_status)
- err_status= set_routine_security_ctx(thd, this, TRUE, &save_security_ctx);
+ err_status= set_routine_security_ctx(thd, this, &save_security_ctx);
#endif
if (!err_status)
@@ -2459,27 +2439,6 @@ sp_head::set_info(longlong created, longlong modified,
void
-sp_head::set_definer(const char *definer, uint definerlen)
-{
- char user_name_holder[USERNAME_LENGTH + 1];
- LEX_CSTRING user_name= { user_name_holder, USERNAME_LENGTH };
-
- char host_name_holder[HOSTNAME_LENGTH + 1];
- LEX_CSTRING host_name= { host_name_holder, HOSTNAME_LENGTH };
-
- if (parse_user(definer, definerlen, user_name_holder, &user_name.length,
- host_name_holder, &host_name.length) &&
- user_name.length && !host_name.length)
- {
- // 'user@' -> 'user@%'
- host_name= host_not_specified;
- }
-
- set_definer(&user_name, &host_name);
-}
-
-
-void
sp_head::reset_thd_mem_root(THD *thd)
{
DBUG_ENTER("sp_head::reset_thd_mem_root");
@@ -2553,7 +2512,7 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
thd->security_ctx->priv_host)));
if (!*full_access)
return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
- sp->m_type == TYPE_ENUM_PROCEDURE);
+ sp->m_handler);
return 0;
}
@@ -2562,9 +2521,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
Collect metadata for SHOW CREATE statement for stored routines.
@param thd Thread context.
- @param type Stored routine type
- @param type Stored routine type
- (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
+ @param sph Stored routine handler
+ @param fields Item list to populate
@return Error status.
@retval FALSE on success
@@ -2572,13 +2530,11 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
*/
void
-sp_head::show_create_routine_get_fields(THD *thd, int type, List<Item> *fields)
+sp_head::show_create_routine_get_fields(THD *thd, const Sp_handler *sph,
+ List<Item> *fields)
{
- const char *col1_caption= type == TYPE_ENUM_PROCEDURE ?
- "Procedure" : "Function";
-
- const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
- "Create Procedure" : "Create Function";
+ const char *col1_caption= sph->show_create_routine_col1_caption();
+ const char *col3_caption= sph->show_create_routine_col3_caption();
MEM_ROOT *mem_root= thd->mem_root;
@@ -2625,8 +2581,7 @@ sp_head::show_create_routine_get_fields(THD *thd, int type, List<Item> *fields)
Implement SHOW CREATE statement for stored routines.
@param thd Thread context.
- @param type Stored routine type
- (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
+ @param sph Stored routine handler
@return Error status.
@retval FALSE on success
@@ -2634,13 +2589,10 @@ sp_head::show_create_routine_get_fields(THD *thd, int type, List<Item> *fields)
*/
bool
-sp_head::show_create_routine(THD *thd, int type)
+sp_head::show_create_routine(THD *thd, const Sp_handler *sph)
{
- const char *col1_caption= type == TYPE_ENUM_PROCEDURE ?
- "Procedure" : "Function";
-
- const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
- "Create Procedure" : "Create Function";
+ const char *col1_caption= sph->show_create_routine_col1_caption();
+ const char *col3_caption= sph->show_create_routine_col3_caption();
bool err_status;
@@ -2655,9 +2607,6 @@ sp_head::show_create_routine(THD *thd, int type)
DBUG_ENTER("sp_head::show_create_routine");
DBUG_PRINT("info", ("routine %s", m_name.str));
- DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
- type == TYPE_ENUM_FUNCTION);
-
if (check_show_routine_access(thd, this, &full_access))
DBUG_RETURN(TRUE);
@@ -2784,6 +2733,29 @@ bool sp_head::add_instr_jump_forward_with_backpatch(THD *thd,
}
+bool sp_head::add_instr_freturn(THD *thd, sp_pcontext *spcont,
+ Item *item, LEX *lex)
+{
+ sp_instr_freturn *i= new (thd->mem_root)
+ sp_instr_freturn(instructions(), spcont, item,
+ m_return_field_def.type_handler(), thd->lex);
+ if (i == NULL || add_instr(i))
+ return true;
+ m_flags|= sp_head::HAS_RETURN;
+ return false;
+}
+
+
+bool sp_head::add_instr_preturn(THD *thd, sp_pcontext *spcont)
+{
+ sp_instr_preturn *i= new (thd->mem_root)
+ sp_instr_preturn(instructions(), spcont);
+ if (i == NULL || add_instr(i))
+ return true;
+ return false;
+}
+
+
/*
Replace an instruction at position to "no operation".
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 1435bb460c3..f1d89a083ab 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -40,11 +40,6 @@
@{
*/
-// Values for the type enum. This reflects the order of the enum declaration
-// in the CREATE TABLE command.
-//#define TYPE_ENUM_FUNCTION 1 #define TYPE_ENUM_PROCEDURE 2 #define
-//TYPE_ENUM_TRIGGER 3 #define TYPE_ENUM_PROXY 4
-
Item::Type
sp_map_item_type(enum enum_field_types type);
@@ -173,7 +168,7 @@ public:
HAS_COLUMN_TYPE_REFS= 8192
};
- stored_procedure_type m_type;
+ const Sp_handler *m_handler;
uint m_flags; // Boolean attributes of a stored routine
Column_definition m_return_field_def; /**< This is used for FUNCTIONs only. */
@@ -220,7 +215,7 @@ public:
m_sp_cache_version= version_arg;
}
- sp_rcontext *rcontext_create(THD *thd, bool is_proc, Field *ret_value);
+ sp_rcontext *rcontext_create(THD *thd, Field *retval);
private:
/**
@@ -317,7 +312,7 @@ public:
static void
operator delete(void *ptr, size_t size) throw ();
- sp_head(stored_procedure_type type);
+ sp_head(const Sp_handler *handler);
/// Initialize after we have reset mem_root
void
@@ -325,7 +320,7 @@ public:
/** Copy sp name from parser. */
void
- init_sp_name(THD *thd, sp_name *spname);
+ init_sp_name(THD *thd, const sp_name *spname);
/** Set the body-definition start position. */
void
@@ -350,10 +345,11 @@ public:
execute_procedure(THD *thd, List<Item> *args);
static void
- show_create_routine_get_fields(THD *thd, int type, List<Item> *fields);
+ show_create_routine_get_fields(THD *thd, const Sp_handler *sph,
+ List<Item> *fields);
bool
- show_create_routine(THD *thd, int type);
+ show_create_routine(THD *thd, const Sp_handler *sph);
MEM_ROOT *get_main_mem_root() { return &main_mem_root; }
@@ -376,6 +372,12 @@ public:
spcont->last_label());
}
+ bool
+ add_instr_freturn(THD *thd, sp_pcontext *spcont, Item *item, LEX *lex);
+
+ bool
+ add_instr_preturn(THD *thd, sp_pcontext *spcont);
+
Item *adjust_assignment_source(THD *thd, Item *val, Item *val2);
/**
@param thd - the current thd
@@ -622,7 +624,7 @@ public:
char *create_string(THD *thd, ulong *lenp);
Field *create_result_field(uint field_max_length, const LEX_CSTRING *field_name,
- TABLE *table);
+ TABLE *table) const;
/**
@@ -689,7 +691,12 @@ public:
void set_info(longlong created, longlong modified,
const st_sp_chistics &chistics, sql_mode_t sql_mode);
- void set_definer(const char *definer, uint definerlen);
+ void set_definer(const char *definer, uint definerlen)
+ {
+ AUTHID tmp;
+ tmp.parse(definer, definerlen);
+ m_definer.copy(mem_root, &tmp.user, &tmp.host);
+ }
void set_definer(const LEX_CSTRING *user_name, const LEX_CSTRING *host_name)
{
m_definer.copy(mem_root, user_name, host_name);
@@ -713,8 +720,6 @@ public:
*/
void add_mark_lead(uint ip, List<sp_instr> *leads);
- void recursion_level_error(THD *thd);
-
inline sp_instr *
get_instr(uint i)
{
@@ -1859,8 +1864,7 @@ void
sp_restore_security_context(THD *thd, Security_context *backup);
bool
-set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
- Security_context **save_ctx);
+set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
TABLE_LIST *
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 79acb996740..c2b2bdc54b5 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -754,6 +754,19 @@ static int traverse_role_graph_down(ACL_USER_BASE *, void *,
int (*) (ACL_USER_BASE *, void *),
int (*) (ACL_USER_BASE *, ACL_ROLE *, void *));
+
+HASH *Sp_handler_procedure::get_priv_hash() const
+{
+ return &proc_priv_hash;
+}
+
+
+HASH *Sp_handler_function::get_priv_hash() const
+{
+ return &func_priv_hash;
+}
+
+
/*
Enumeration of ACL/GRANT tables in the mysql database
*/
@@ -4973,10 +4986,11 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
static GRANT_NAME *
routine_hash_search(const char *host, const char *ip, const char *db,
- const char *user, const char *tname, bool proc, bool exact)
+ const char *user, const char *tname, const Sp_handler *sph,
+ bool exact)
{
return (GRANT_TABLE*)
- name_hash_search(proc ? &proc_priv_hash : &func_priv_hash,
+ name_hash_search(sph->get_priv_hash(),
host, ip, db, user, tname, exact, TRUE);
}
@@ -5351,13 +5365,14 @@ table_error:
static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
TABLE *table, const LEX_USER &combo,
const char *db, const char *routine_name,
- bool is_proc, ulong rights, bool revoke_grant)
+ const Sp_handler *sph,
+ ulong rights, bool revoke_grant)
{
char grantor[USER_HOST_BUFF_SIZE];
int old_row_exists= 1;
int error=0;
ulong store_proc_rights;
- HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
+ HASH *hash= sph->get_priv_hash();
DBUG_ENTER("replace_routine_table");
if (revoke_grant && !grant_name->init_privs) // only inherited role privs
@@ -5381,9 +5396,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->field[3]->store(routine_name,(uint) strlen(routine_name),
&my_charset_latin1);
- table->field[4]->store((longlong)(is_proc ?
- TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION),
- TRUE);
+ table->field[4]->store((longlong) sph->type(), true);
store_record(table,record[1]); // store at pos 1
if (table->file->ha_index_read_idx_map(table->record[0], 0,
@@ -5503,6 +5516,23 @@ struct PRIVS_TO_MERGE
const char *db, *name;
};
+
+static enum PRIVS_TO_MERGE::what sp_privs_to_merge(stored_procedure_type type)
+{
+ switch (type) {
+ case TYPE_ENUM_FUNCTION:
+ return PRIVS_TO_MERGE::FUNC;
+ case TYPE_ENUM_PROCEDURE:
+ return PRIVS_TO_MERGE::PROC;
+ case TYPE_ENUM_TRIGGER:
+ case TYPE_ENUM_PROXY:
+ break;
+ }
+ DBUG_ASSERT(0);
+ return PRIVS_TO_MERGE::PROC;
+}
+
+
static int init_role_for_merging(ACL_ROLE *role, void *context)
{
role->counter= 0;
@@ -6627,7 +6657,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
@param thd Thread handle
@param table_list List of routines to give grant
- @param is_proc Is this a list of procedures?
+ @param sph SP handler
@param user_list List of users to give grant
@param rights Table level grant
@param revoke_grant Is this is a REVOKE command?
@@ -6637,7 +6667,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
@retval TRUE An error occurred.
*/
-bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
+bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list,
+ const Sp_handler *sph,
List <LEX_USER> &user_list, ulong rights,
bool revoke_grant, bool write_to_binlog)
{
@@ -6657,7 +6688,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
if (!revoke_grant)
{
- if (sp_exist_routines(thd, table_list, is_proc))
+ if (sph->sp_exist_routines(thd, table_list))
DBUG_RETURN(TRUE);
}
@@ -6698,7 +6729,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
db_name= table_list->db;
table_name= table_list->table_name;
grant_name= routine_hash_search(Str->host.str, NullS, db_name,
- Str->user.str, table_name, is_proc, 1);
+ Str->user.str, table_name, sph, 1);
if (!grant_name || !grant_name->init_privs)
{
if (revoke_grant)
@@ -6712,8 +6743,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
Str->user.str, table_name,
rights, TRUE);
if (!grant_name ||
- my_hash_insert(is_proc ?
- &proc_priv_hash : &func_priv_hash,(uchar*) grant_name))
+ my_hash_insert(sph->get_priv_hash(), (uchar*) grant_name))
{
result= TRUE;
continue;
@@ -6724,7 +6754,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
instead of TABLE directly. */
if (tables.procs_priv_table().no_such_table() ||
replace_routine_table(thd, grant_name, tables.procs_priv_table().table(),
- *Str, db_name, table_name, is_proc, rights,
+ *Str, db_name, table_name, sph, rights,
revoke_grant) != 0)
{
result= TRUE;
@@ -6732,7 +6762,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
}
if (Str->is_role())
propagate_role_grants(find_acl_role(Str->user.str),
- is_proc ? PRIVS_TO_MERGE::PROC : PRIVS_TO_MERGE::FUNC,
+ sp_privs_to_merge(sph->type()),
db_name, table_name);
}
thd->mem_root= old_root;
@@ -7341,16 +7371,10 @@ static bool grant_load(THD *thd,
continue;
}
}
- if (procs_priv.routine_type()->val_int() == TYPE_ENUM_PROCEDURE)
- {
- hash= &proc_priv_hash;
- }
- else
- if (procs_priv.routine_type()->val_int() == TYPE_ENUM_FUNCTION)
- {
- hash= &func_priv_hash;
- }
- else
+ uint type= procs_priv.routine_type()->val_int();
+ const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
+ type);
+ if (!sph || !(hash= sph->get_priv_hash()))
{
sql_print_warning("'procs_priv' entry '%s' "
"ignored, bad routine type",
@@ -8088,7 +8112,7 @@ bool check_grant_db(THD *thd, const char *db)
thd Thread handler
want_access Bits of privileges user needs to have
procs List of routines to check. The user should have 'want_access'
- is_proc True if the list is all procedures, else functions
+ sph SP handler
no_errors If 0 then we write an error. The error is sent directly to
the client
@@ -8098,7 +8122,8 @@ bool check_grant_db(THD *thd, const char *db)
****************************************************************************/
bool check_grant_routine(THD *thd, ulong want_access,
- TABLE_LIST *procs, bool is_proc, bool no_errors)
+ TABLE_LIST *procs, const Sp_handler *sph,
+ bool no_errors)
{
TABLE_LIST *table;
Security_context *sctx= thd->security_ctx;
@@ -8116,12 +8141,12 @@ bool check_grant_routine(THD *thd, ulong want_access,
{
GRANT_NAME *grant_proc;
if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user,
- table->table_name, is_proc, 0)))
+ table->table_name, sph, 0)))
table->grant.privilege|= grant_proc->privs;
if (role[0]) /* current role set check */
{
if ((grant_proc= routine_hash_search("", NULL, table->db, role,
- table->table_name, is_proc, 0)))
+ table->table_name, sph, 0)))
table->grant.privilege|= grant_proc->privs;
}
@@ -8170,7 +8195,7 @@ err:
*/
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
- bool is_proc)
+ const Sp_handler *sph)
{
bool no_routine_acl= 1;
GRANT_NAME *grant_proc;
@@ -8179,7 +8204,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
if ((grant_proc= routine_hash_search(sctx->priv_host,
sctx->ip, db,
sctx->priv_user,
- name, is_proc, 0)))
+ name, sph, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
if (no_routine_acl && sctx->priv_role[0]) /* current set role check */
@@ -8187,7 +8212,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
if ((grant_proc= routine_hash_search("",
NULL, db,
sctx->priv_role,
- name, is_proc, 0)))
+ name, sph, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
}
mysql_rwlock_unlock(&LOCK_grant);
@@ -10503,6 +10528,45 @@ int mysql_alter_user(THD* thd, List<LEX_USER> &users_list)
DBUG_RETURN(result);
}
+
+static bool
+mysql_revoke_sp_privs(THD *thd,
+ Grant_tables *tables,
+ const Sp_handler *sph,
+ const LEX_USER *lex_user)
+{
+ bool rc= false;
+ uint counter, revoked;
+ do {
+ HASH *hash= sph->get_priv_hash();
+ for (counter= 0, revoked= 0 ; counter < hash->records ; )
+ {
+ const char *user,*host;
+ GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
+ user= safe_str(grant_proc->user);
+ host= safe_str(grant_proc->host.hostname);
+
+ if (!strcmp(lex_user->user.str, user) &&
+ !strcmp(lex_user->host.str, host))
+ {
+ if (replace_routine_table(thd, grant_proc,
+ tables->procs_priv_table().table(),
+ *lex_user,
+ grant_proc->db, grant_proc->tname,
+ sph, ~(ulong)0, 1) == 0)
+ {
+ revoked= 1;
+ continue;
+ }
+ rc= true; // Something went wrong
+ }
+ counter++;
+ }
+ } while (revoked);
+ return rc;
+}
+
+
/*
Revoke all privileges from a list of users.
@@ -10519,7 +10583,7 @@ int mysql_alter_user(THD* thd, List<LEX_USER> &users_list)
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
{
- uint counter, revoked, is_proc;
+ uint counter, revoked;
int result;
ACL_DB *acl_db;
DBUG_ENTER("mysql_revoke_all");
@@ -10648,32 +10712,9 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
} while (revoked);
/* Remove procedure access */
- for (is_proc=0; is_proc<2; is_proc++) do {
- HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
- for (counter= 0, revoked= 0 ; counter < hash->records ; )
- {
- const char *user,*host;
- GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
- user= safe_str(grant_proc->user);
- host= safe_str(grant_proc->host.hostname);
-
- if (!strcmp(lex_user->user.str,user) &&
- !strcmp(lex_user->host.str, host))
- {
- if (replace_routine_table(thd, grant_proc,
- tables.procs_priv_table().table(),
- *lex_user,
- grant_proc->db, grant_proc->tname,
- is_proc, ~(ulong)0, 1) == 0)
- {
- revoked= 1;
- continue;
- }
- result= -1; // Something went wrong
- }
- counter++;
- }
- } while (revoked);
+ if (mysql_revoke_sp_privs(thd, &tables, &sp_handler_function, lex_user) ||
+ mysql_revoke_sp_privs(thd, &tables, &sp_handler_procedure, lex_user))
+ result= -1;
ACL_USER_BASE *user_or_role;
/* remove role grants */
@@ -10825,11 +10866,11 @@ Silence_routine_definer_errors::handle_condition(
*/
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
- bool is_proc)
+ const Sp_handler *sph)
{
uint counter, revoked;
int result;
- HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
+ HASH *hash= sph->get_priv_hash();
Silence_routine_definer_errors error_handler;
DBUG_ENTER("sp_revoke_privileges");
@@ -10865,7 +10906,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
if (replace_routine_table(thd, grant_proc,
tables.procs_priv_table().table(), lex_user,
grant_proc->db, grant_proc->tname,
- is_proc, ~(ulong)0, 1) == 0)
+ sph, ~(ulong)0, 1) == 0)
{
revoked= 1;
continue;
@@ -10890,7 +10931,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
@param thd The current thread.
@param sp_db
@param sp_name
- @param is_proc
+ @param sph
@return
@retval FALSE Success
@@ -10898,7 +10939,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
*/
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
- bool is_proc)
+ const Sp_handler *sph)
{
Security_context *sctx= thd->security_ctx;
LEX_USER *combo;
@@ -10960,7 +11001,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
as all errors will be handled later.
*/
thd->push_internal_handler(&error_handler);
- result= mysql_routine_grant(thd, tables, is_proc, user_list,
+ result= mysql_routine_grant(thd, tables, sph, user_list,
DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE);
thd->pop_internal_handler();
DBUG_RETURN(result);
@@ -11746,7 +11787,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
****************************************************************************/
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
- bool is_proc)
+ const Sp_handler *sph)
{
return FALSE;
}
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index f9646649c93..6164c6fa57d 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -215,7 +215,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
List <LEX_COLUMN> &column_list, ulong rights,
bool revoke);
-bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc,
+bool mysql_routine_grant(THD *thd, TABLE_LIST *table, const Sp_handler *sph,
List <LEX_USER> &user_list, ulong rights,
bool revoke, bool write_to_binlog);
bool grant_init();
@@ -231,7 +231,8 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
bool check_grant_all_columns(THD *thd, ulong want_access,
Field_iterator_table_ref *fields);
bool check_grant_routine(THD *thd, ulong want_access,
- TABLE_LIST *procs, bool is_proc, bool no_error);
+ TABLE_LIST *procs, const Sp_handler *sph,
+ bool no_error);
bool check_grant_db(THD *thd,const char *db);
bool check_global_access(THD *thd, ulong want_access, bool no_errors= false);
bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
@@ -257,11 +258,11 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list);
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table);
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
- bool is_proc);
+ const Sp_handler *sph);
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
- bool is_proc);
+ const Sp_handler *sph);
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
- bool is_proc);
+ const Sp_handler *sph);
bool is_acl_user(const char *host, const char *user);
int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 7041e22075b..60247c83a08 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3127,7 +3127,7 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
DEBUG_SYNC(thd, "after_shared_lock_pname");
/* Ensures the routine is up-to-date and cached, if exists. */
- if (sp_cache_routine(thd, rt, has_prelocking_list, &sp))
+ if (rt->sp_cache_routine(thd, has_prelocking_list, &sp))
DBUG_RETURN(TRUE);
/* Remember the version of the routine in the parse tree. */
@@ -3152,7 +3152,7 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
Validating routine version is unnecessary, since CALL
does not affect the prepared statement prelocked list.
*/
- if (sp_cache_routine(thd, rt, FALSE, &sp))
+ if (rt->sp_cache_routine(thd, false, &sp))
DBUG_RETURN(TRUE);
}
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 145ccb76d11..3851a258bd9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -7475,4 +7475,34 @@ void AUTHID::copy(MEM_ROOT *mem_root, const LEX_CSTRING *user_name,
}
+/*
+ Set from a string in 'user@host' format.
+ This method resebmles parse_user(),
+ but does not need temporary buffers.
+*/
+void AUTHID::parse(const char *str, size_t length)
+{
+ const char *p= strrchr(str, '@');
+ if (!p)
+ {
+ user.str= str;
+ user.length= length;
+ host= null_clex_str;
+ }
+ else
+ {
+ user.str= str;
+ user.length= (size_t) (p - str);
+ host.str= p + 1;
+ host.length= (size_t) (length - user.length - 1);
+ if (user.length && !host.length)
+ host= host_not_specified; // 'user@' -> 'user@%'
+ }
+ if (user.length > USERNAME_LENGTH)
+ user.length= USERNAME_LENGTH;
+ if (host.length > HOSTNAME_LENGTH)
+ host.length= HOSTNAME_LENGTH;
+}
+
+
#endif /* !defined(MYSQL_CLIENT) */
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 2fe788264d3..e449fb8c298 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4507,10 +4507,16 @@ void st_select_lex::set_explain_type(bool on_the_fly)
if (join)
{
bool uses_cte= false;
- for (JOIN_TAB *tab= first_explain_order_tab(join); tab;
- tab= next_explain_order_tab(join, tab))
+ for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_BUSH_ROOTS,
+ WITH_CONST_TABLES);
+ tab;
+ tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS))
{
- if (tab->table && tab->table->pos_in_table_list->with)
+ /*
+ pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
+ */
+ if (tab->table && tab->table->pos_in_table_list &&
+ tab->table->pos_in_table_list->with)
{
uses_cte= true;
break;
@@ -5143,7 +5149,7 @@ bool LEX::init_internal_variable(struct sys_var_with_base *variable,
bool LEX::is_trigger_new_or_old_reference(const LEX_CSTRING *name)
{
- return sphead && sphead->m_type == TYPE_ENUM_TRIGGER &&
+ return sphead && sphead->m_handler->type() == TYPE_ENUM_TRIGGER &&
name->length == 3 &&
(!my_strcasecmp(system_charset_info, name->str, "NEW") ||
!my_strcasecmp(system_charset_info, name->str, "OLD"));
@@ -5819,13 +5825,13 @@ sp_name *LEX::make_sp_name(THD *thd, LEX_CSTRING *name1, LEX_CSTRING *name2)
}
-sp_head *LEX::make_sp_head(THD *thd, sp_name *name,
- enum stored_procedure_type type)
+sp_head *LEX::make_sp_head(THD *thd, const sp_name *name,
+ const Sp_handler *sph)
{
sp_head *sp;
/* Order is important here: new - reset - init */
- if ((sp= new sp_head(type)))
+ if ((sp= new sp_head(sph)))
{
sp->reset_thd_mem_root(thd);
sp->init(this);
@@ -6121,7 +6127,7 @@ bool LEX::maybe_start_compound_statement(THD *thd)
{
if (!sphead)
{
- if (!make_sp_head(thd, NULL, TYPE_ENUM_PROCEDURE))
+ if (!make_sp_head(thd, NULL, &sp_handler_procedure))
return true;
sphead->set_suid(SP_IS_NOT_SUID);
sphead->set_body_start(thd, thd->m_parser_state->m_lip.get_cpp_ptr());
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 822c2554951..4fe740185d5 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1287,6 +1287,7 @@ struct st_sp_chistics
enum enum_sp_data_access daccess;
void init() { bzero(this, sizeof(*this)); }
void set(const st_sp_chistics &other) { *this= other; }
+ bool read_from_mysql_proc_row(THD *thd, TABLE *table);
};
@@ -3155,24 +3156,22 @@ public:
void set_stmt_init();
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name);
sp_name *make_sp_name(THD *thd, LEX_CSTRING *name1, LEX_CSTRING *name2);
- sp_head *make_sp_head(THD *thd, sp_name *name,
- enum stored_procedure_type type);
- sp_head *make_sp_head_no_recursive(THD *thd, sp_name *name,
- enum stored_procedure_type type)
+ sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph);
+ sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name,
+ const Sp_handler *sph)
{
if (!sphead)
- return make_sp_head(thd, name, type);
- my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0),
- stored_procedure_type_to_str(type));
+ return make_sp_head(thd, name, sph);
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str());
return NULL;
}
sp_head *make_sp_head_no_recursive(THD *thd,
DDL_options_st options, sp_name *name,
- enum stored_procedure_type type)
+ const Sp_handler *sph)
{
if (add_create_options_with_check(options))
return NULL;
- return make_sp_head_no_recursive(thd, name, type);
+ return make_sp_head_no_recursive(thd, name, sph);
}
bool init_internal_variable(struct sys_var_with_base *variable,
const LEX_CSTRING *name);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 1d4a2ac8851..0c1c78d59cf 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2937,13 +2937,13 @@ static int mysql_create_routine(THD *thd, LEX *lex)
{
if (check_routine_access(thd, ALTER_PROC_ACL, lex->sphead->m_db.str,
lex->sphead->m_name.str,
- lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
+ Sp_handler::handler(lex->sql_command), 0))
return true;
}
const LEX_CSTRING *name= lex->sphead->name();
#ifdef HAVE_DLOPEN
- if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
+ if (lex->sphead->m_handler->type() == TYPE_ENUM_FUNCTION)
{
udf_func *udf = find_udf(name->str, name->length);
@@ -2959,7 +2959,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
return true;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
- if (!sp_create_routine(thd, lex->sphead->m_type, lex->sphead))
+ if (!lex->sphead->m_handler->sp_create_routine(thd, lex->sphead))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* only add privileges if really neccessary */
@@ -3006,10 +3006,10 @@ static int mysql_create_routine(THD *thd, LEX *lex)
if (sp_automatic_privileges && !opt_noacl &&
check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
lex->sphead->m_db.str, name->str,
- lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
+ Sp_handler::handler(lex->sql_command), 1))
{
if (sp_grant_privileges(thd, lex->sphead->m_db.str, name->str,
- lex->sql_command == SQLCOM_CREATE_PROCEDURE))
+ Sp_handler::handler(lex->sql_command)))
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL));
thd->clear_error();
@@ -5353,16 +5353,16 @@ end_with_restore_list:
if (lex->type == TYPE_ENUM_PROCEDURE ||
lex->type == TYPE_ENUM_FUNCTION)
{
+ const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
+ lex->type);
uint grants= lex->all_privileges
? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
: lex->grant;
- if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
- lex->type == TYPE_ENUM_PROCEDURE, 0))
+ if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, sph, 0))
goto error;
/* Conditionally writes to binlog */
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
- res= mysql_routine_grant(thd, all_tables,
- lex->type == TYPE_ENUM_PROCEDURE,
+ res= mysql_routine_grant(thd, all_tables, sph,
lex->users_list, grants,
lex->sql_command == SQLCOM_REVOKE, TRUE);
if (!res)
@@ -5768,15 +5768,15 @@ end_with_restore_list:
goto error;
if (check_routine_access(thd, EXECUTE_ACL, lex->spname->m_db.str,
- lex->spname->m_name.str, TRUE, FALSE))
+ lex->spname->m_name.str, &sp_handler_procedure,
+ false))
goto error;
/*
By this moment all needed SPs should be in cache so no need to look
into DB.
*/
- if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
- &thd->sp_proc_cache, TRUE)))
+ if (!(sp= sp_handler_procedure.sp_find_routine(thd, lex->spname, true)))
{
/*
sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error.
@@ -5821,13 +5821,9 @@ end_with_restore_list:
case SQLCOM_ALTER_FUNCTION:
{
int sp_result;
- enum stored_procedure_type type;
- type= (lex->sql_command == SQLCOM_ALTER_PROCEDURE ?
- TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
-
+ const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str,
- lex->spname->m_name.str,
- lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
+ lex->spname->m_name.str, sph, 0))
goto error;
/*
@@ -5837,7 +5833,7 @@ end_with_restore_list:
already puts on CREATE FUNCTION.
*/
/* Conditionally writes to binlog */
- sp_result= sp_update_routine(thd, type, lex->spname, &lex->sp_chistics);
+ sp_result= sph->sp_update_routine(thd, lex->spname, &lex->sp_chistics);
switch (sp_result)
{
case SP_OK:
@@ -5899,19 +5895,17 @@ end_with_restore_list:
#endif
int sp_result;
- enum stored_procedure_type type;
- type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
- TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
+ const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
const char *db= lex->spname->m_db.str;
const char *name= lex->spname->m_name.str;
if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
- lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
+ Sp_handler::handler(lex->sql_command), 0))
goto error;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
/* Conditionally writes to binlog */
- sp_result= sp_drop_routine(thd, type, lex->spname);
+ sp_result= sph->sp_drop_routine(thd, lex->spname);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
@@ -5935,7 +5929,7 @@ end_with_restore_list:
if (sp_result != SP_KEY_NOT_FOUND &&
sp_automatic_privileges && !opt_noacl &&
sp_revoke_privileges(thd, db, name,
- lex->sql_command == SQLCOM_DROP_PROCEDURE))
+ Sp_handler::handler(lex->sql_command)))
{
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PROC_AUTO_REVOKE_FAIL,
@@ -5973,21 +5967,14 @@ end_with_restore_list:
break;
}
case SQLCOM_SHOW_CREATE_PROC:
- {
-#ifdef WITH_WSREP
- if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
-#endif /* WITH_WSREP */
- if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
- goto error;
- break;
- }
case SQLCOM_SHOW_CREATE_FUNC:
{
+ const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
#ifdef WITH_WSREP
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
#endif /* WITH_WSREP */
- if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
- goto error;
+ if (sph->sp_show_create_routine(thd, lex->spname))
+ goto error;
break;
}
case SQLCOM_SHOW_PROC_CODE:
@@ -5995,13 +5982,11 @@ end_with_restore_list:
{
#ifndef DBUG_OFF
sp_head *sp;
- stored_procedure_type type= (lex->sql_command == SQLCOM_SHOW_PROC_CODE ?
- TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
-
+ const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
#ifdef WITH_WSREP
if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
#endif /* WITH_WSREP */
- if (sp_cache_routine(thd, type, lex->spname, FALSE, &sp))
+ if (sph->sp_cache_routine(thd, lex->spname, false, &sp))
goto error;
if (!sp || sp->show_routine_code(thd))
{
@@ -7061,7 +7046,7 @@ deny:
bool
check_routine_access(THD *thd, ulong want_access, const char *db,
const char *name,
- bool is_proc, bool no_errors)
+ const Sp_handler *sph, bool no_errors)
{
TABLE_LIST tables[1];
@@ -7090,7 +7075,7 @@ check_routine_access(THD *thd, ulong want_access, const char *db,
0, no_errors))
return TRUE;
- return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
+ return check_grant_routine(thd, want_access, tables, sph, no_errors);
}
@@ -7108,7 +7093,7 @@ check_routine_access(THD *thd, ulong want_access, const char *db,
*/
bool check_some_routine_access(THD *thd, const char *db, const char *name,
- bool is_proc)
+ const Sp_handler *sph)
{
ulong save_priv;
/*
@@ -7125,7 +7110,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name,
if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, NULL, 0, 1) ||
(save_priv & SHOW_PROC_ACLS))
return FALSE;
- return check_routine_level_acl(thd, db, name, is_proc);
+ return check_routine_level_acl(thd, db, name, sph);
}
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index bf241d04e7b..c97d824ffa1 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -152,9 +152,10 @@ bool check_single_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables, bool no_errors);
bool check_routine_access(THD *thd,ulong want_access,const char *db,
const char *name,
- bool is_proc, bool no_errors);
+ const Sp_handler *sph, bool no_errors);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
-bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
+bool check_some_routine_access(THD *thd, const char *db, const char *name,
+ const Sp_handler *sph);
bool check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
bool any_combination_of_privileges_will_do,
uint number,
@@ -166,7 +167,8 @@ inline bool check_single_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables, bool no_errors)
{ return false; }
inline bool check_routine_access(THD *thd,ulong want_access, const char *db,
- const char *name, bool is_proc, bool no_errors)
+ const char *name,
+ const Sp_handler *sph, bool no_errors)
{ return false; }
inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
{
@@ -174,7 +176,8 @@ inline bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
return false;
}
inline bool check_some_routine_access(THD *thd, const char *db,
- const char *name, bool is_proc)
+ const char *name,
+ const Sp_handler *sph)
{ return false; }
inline bool
check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index dfc1e3add37..4aef8adff09 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2040,13 +2040,14 @@ static int mysql_test_show_binlogs(Prepared_statement *stmt)
TRUE error, error message is set in THD
*/
-static int mysql_test_show_create_routine(Prepared_statement *stmt, int type)
+static int mysql_test_show_create_routine(Prepared_statement *stmt,
+ const Sp_handler *sph)
{
DBUG_ENTER("mysql_test_show_binlogs");
THD *thd= stmt->thd;
List<Item> fields;
- sp_head::show_create_routine_get_fields(thd, type, &fields);
+ sp_head::show_create_routine_get_fields(thd, sph, &fields);
DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
}
@@ -2436,14 +2437,14 @@ static bool check_prepared_statement(Prepared_statement *stmt)
break;
#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SHOW_CREATE_PROC:
- if ((res= mysql_test_show_create_routine(stmt, TYPE_ENUM_PROCEDURE)) == 2)
+ if ((res= mysql_test_show_create_routine(stmt, &sp_handler_procedure)) == 2)
{
/* Statement and field info has already been sent */
DBUG_RETURN(FALSE);
}
break;
case SQLCOM_SHOW_CREATE_FUNC:
- if ((res= mysql_test_show_create_routine(stmt, TYPE_ENUM_FUNCTION)) == 2)
+ if ((res= mysql_test_show_create_routine(stmt, &sp_handler_function)) == 2)
{
/* Statement and field info has already been sent */
DBUG_RETURN(FALSE);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 438c276c096..d27d4c943df 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3405,8 +3405,14 @@ void JOIN::exec_inner()
if (zero_result_cause)
{
- if (select_lex->have_window_funcs())
+ if (select_lex->have_window_funcs() && send_row_on_empty_set())
{
+ /*
+ The query produces just one row but it has window functions.
+
+ The only way to compute the value of window function(s) is to
+ run the entire window function computation step (there is no shortcut).
+ */
const_tables= table_count;
first_select= sub_select_postjoin_aggr;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index fd0d11bf1bb..ed0d9ae15e9 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -5876,16 +5876,11 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
TABLE_SHARE share;
TABLE tbl;
CHARSET_INFO *cs= system_charset_info;
- char params_buff[MAX_FIELD_WIDTH], returns_buff[MAX_FIELD_WIDTH],
- sp_db_buff[NAME_LEN], sp_name_buff[NAME_LEN], path[FN_REFLEN],
- definer_buff[DEFINER_LENGTH + 1];
- String params(params_buff, sizeof(params_buff), cs);
- String returns(returns_buff, sizeof(returns_buff), cs);
- String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
- String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
- String definer(definer_buff, sizeof(definer_buff), cs);
+ LEX_CSTRING definer, params, returns= empty_clex_str;
+ LEX_CSTRING db, name;
+ char path[FN_REFLEN];
sp_head *sp;
- stored_procedure_type routine_type;
+ const Sp_handler *sph;
bool free_sp_head;
bool error= 0;
DBUG_ENTER("store_schema_params");
@@ -5894,48 +5889,44 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
(void) build_table_filename(path, sizeof(path), "", "", "", 0);
init_tmp_table_share(thd, &share, "", 0, "", path);
- get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_DB], &sp_db);
- get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_NAME], &sp_name);
- get_field(thd->mem_root,proc_table->field[MYSQL_PROC_FIELD_DEFINER],&definer);
- routine_type= (stored_procedure_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int();
+ proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
+ proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
+ proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
+ sph= Sp_handler::handler((stored_procedure_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int());
+ if (!sph)
+ sph= &sp_handler_procedure;
if (!full_access)
- full_access= !strcmp(sp_user, definer.ptr());
+ full_access= !strcmp(sp_user, definer.str);
if (!full_access &&
- check_some_routine_access(thd, sp_db.ptr(),sp_name.ptr(),
- routine_type == TYPE_ENUM_PROCEDURE))
+ check_some_routine_access(thd, db.str, name.str, sph))
DBUG_RETURN(0);
- params.length(0);
- get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST],
- &params);
- returns.length(0);
- if (routine_type == TYPE_ENUM_FUNCTION)
- get_field(thd->mem_root, proc_table->field[MYSQL_PROC_FIELD_RETURNS],
- &returns);
-
- sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
- (ulong) proc_table->
- field[MYSQL_PROC_FIELD_SQL_MODE]->val_int(),
- routine_type,
- returns.c_ptr_safe(),
- params.c_ptr_safe(),
- &free_sp_head);
-
+ proc_table->field[MYSQL_PROC_FIELD_PARAM_LIST]->val_str_nopad(thd->mem_root,
+ &params);
+ if (sph->type() == TYPE_ENUM_FUNCTION)
+ proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
+ &returns);
+ sp= sph->sp_load_for_information_schema(thd, proc_table, db, name,
+ params, returns,
+ (ulong) proc_table->
+ field[MYSQL_PROC_FIELD_SQL_MODE]->
+ val_int(),
+ &free_sp_head);
if (sp)
{
Field *field;
- String tmp_string;
- if (routine_type == TYPE_ENUM_FUNCTION)
+ LEX_CSTRING tmp_string;
+ if (sph->type() == TYPE_ENUM_FUNCTION)
{
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), cs);
- table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
- table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
+ table->field[1]->store(db, cs);
+ table->field[2]->store(name, cs);
table->field[3]->store((longlong) 0, TRUE);
- get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
- &tmp_string);
- table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_str_nopad(thd->mem_root,
+ &tmp_string);
+ table->field[15]->store(tmp_string, cs);
field= sp->m_return_field_def.make_field(&share, thd->mem_root,
&empty_clex_str);
field->table= &tbl;
@@ -5973,16 +5964,16 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), cs);
- table->field[1]->store(sp_db.ptr(), sp_db.length(), cs);
- table->field[2]->store(sp_name.ptr(), sp_name.length(), cs);
+ table->field[1]->store(db, cs);
+ table->field[2]->store(name, cs);
table->field[3]->store((longlong) i + 1, TRUE);
table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
table->field[4]->set_notnull();
table->field[5]->store(spvar->name.str, spvar->name.length, cs);
table->field[5]->set_notnull();
- get_field(thd->mem_root, proc_table->field[MYSQL_PROC_MYSQL_TYPE],
- &tmp_string);
- table->field[15]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_str_nopad(thd->mem_root,
+ &tmp_string);
+ table->field[15]->store(tmp_string, cs);
field= spvar->field_def.make_field(&share, thd->mem_root,
&spvar->name);
@@ -6009,63 +6000,57 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
MYSQL_TIME time;
LEX *lex= thd->lex;
CHARSET_INFO *cs= system_charset_info;
- char sp_db_buff[SAFE_NAME_LEN + 1], sp_name_buff[NAME_LEN + 1],
- definer_buff[DEFINER_LENGTH + 1],
- returns_buff[MAX_FIELD_WIDTH];
-
- String sp_db(sp_db_buff, sizeof(sp_db_buff), cs);
- String sp_name(sp_name_buff, sizeof(sp_name_buff), cs);
- String definer(definer_buff, sizeof(definer_buff), cs);
- String returns(returns_buff, sizeof(returns_buff), cs);
+ const Sp_handler *sph;
+ LEX_CSTRING db, name, definer, returns= empty_clex_str;
- proc_table->field[MYSQL_PROC_FIELD_DB]->val_str(&sp_db);
- proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str(&sp_name);
- proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str(&definer);
+ proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
+ proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
+ proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
+ sph= Sp_handler::handler((stored_procedure_type)
+ proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int());
+ if (!sph)
+ sph= &sp_handler_procedure;
if (!full_access)
- full_access= !strcmp(sp_user, definer.c_ptr_safe());
+ full_access= !strcmp(sp_user, definer.str);
if (!full_access &&
- check_some_routine_access(thd, sp_db.c_ptr_safe(), sp_name.c_ptr_safe(),
- proc_table->field[MYSQL_PROC_MYSQL_TYPE]->
- val_int() == TYPE_ENUM_PROCEDURE))
+ check_some_routine_access(thd, db.str, name.str, sph))
return 0;
if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
- proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
- TYPE_ENUM_PROCEDURE) ||
+ sph->type() == TYPE_ENUM_PROCEDURE) ||
(lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
- proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
- TYPE_ENUM_FUNCTION) ||
+ sph->type() == TYPE_ENUM_FUNCTION) ||
(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
{
restore_record(table, s->default_values);
if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
- sp_name.c_ptr_safe(), wild))
+ name.str, wild))
{
int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
- table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
+ table->field[3]->store(name, cs);
copy_field_as_string(table->field[0],
proc_table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]);
table->field[1]->store(STRING_WITH_LEN("def"), cs);
- table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
+ table->field[2]->store(db, cs);
copy_field_as_string(table->field[4],
proc_table->field[MYSQL_PROC_MYSQL_TYPE]);
- if (proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
- TYPE_ENUM_FUNCTION)
+ if (sph->type() == TYPE_ENUM_FUNCTION)
{
sp_head *sp;
bool free_sp_head;
- proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str(&returns);
- sp= sp_load_for_information_schema(thd, proc_table, &sp_db, &sp_name,
- (ulong) proc_table->
- field[MYSQL_PROC_FIELD_SQL_MODE]->
- val_int(),
- TYPE_ENUM_FUNCTION,
- returns.c_ptr_safe(),
- "", &free_sp_head);
-
+ proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
+ &returns);
+ sp= sph->sp_load_for_information_schema(thd, proc_table,
+ db, name,
+ empty_clex_str /*params*/,
+ returns,
+ (ulong) proc_table->
+ field[MYSQL_PROC_FIELD_SQL_MODE]->
+ val_int(),
+ &free_sp_head);
if (sp)
{
char path[FN_REFLEN];
@@ -6115,7 +6100,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
copy_field_as_string(table->field[26],
proc_table->field[MYSQL_PROC_FIELD_COMMENT]);
- table->field[27]->store(definer.ptr(), definer.length(), cs);
+ table->field[27]->store(definer, cs);
copy_field_as_string(table->field[28],
proc_table->
field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]);
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 845ed4c9746..adaef04fee4 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -471,6 +471,7 @@ public:
bool append(const char *s);
bool append(const LEX_STRING *ls) { return append(ls->str, ls->length); }
bool append(const LEX_CSTRING *ls) { return append(ls->str, ls->length); }
+ bool append(const LEX_CSTRING &ls) { return append(ls.str, ls.length); }
bool append(const char *s, uint32 arg_length);
bool append(const char *s, uint32 arg_length, CHARSET_INFO *cs);
bool append_ulonglong(ulonglong val);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index b3f56f314d2..92cce0666bc 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2948,7 +2948,7 @@ ev_sql_stmt:
my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
if (!lex->make_sp_head(thd, lex->event_parse_data->identifier,
- TYPE_ENUM_PROCEDURE))
+ &sp_handler_procedure))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
@@ -3046,7 +3046,7 @@ call:
lex->sql_command= SQLCOM_CALL;
lex->spname= $2;
lex->value_list.empty();
- sp_add_used_routine(lex, thd, $2, TYPE_ENUM_PROCEDURE);
+ sp_handler_procedure.add_used_routine(lex, thd, $2);
}
opt_sp_cparam_list {}
;
@@ -3880,20 +3880,9 @@ sp_proc_stmt_return:
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
-
- if (sp->m_type != TYPE_ENUM_FUNCTION)
- my_yyabort_error((ER_SP_BADRETURN, MYF(0)));
-
- sp_instr_freturn *i;
-
- i= new (thd->mem_root)
- sp_instr_freturn(sp->instructions(), lex->spcont, $3,
- sp->m_return_field_def.type_handler(), lex);
- if (i == NULL || sp->add_instr(i))
- MYSQL_YYABORT;
- sp->m_flags|= sp_head::HAS_RETURN;
-
- if (sp->restore_lex(thd))
+ if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
+ $3, lex) ||
+ sp->restore_lex(thd))
MYSQL_YYABORT;
}
;
@@ -16607,7 +16596,7 @@ trigger_tail:
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
- if (!lex->make_sp_head(thd, $4, TYPE_ENUM_TRIGGER))
+ if (!lex->make_sp_head(thd, $4, &sp_handler_trigger))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
@@ -16681,7 +16670,7 @@ sf_tail:
sp_name
{
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
- TYPE_ENUM_FUNCTION))
+ &sp_handler_function))
MYSQL_YYABORT;
}
sp_parenthesized_fdparam_list
@@ -16716,7 +16705,7 @@ sp_tail:
opt_if_not_exists sp_name
{
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
- TYPE_ENUM_PROCEDURE))
+ &sp_handler_procedure))
MYSQL_YYABORT;
}
sp_parenthesized_pdparam_list
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 114b117b7cb..7d55780d26f 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -2389,7 +2389,7 @@ ev_sql_stmt:
my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0)));
if (!lex->make_sp_head(thd, lex->event_parse_data->identifier,
- TYPE_ENUM_PROCEDURE))
+ &sp_handler_procedure))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
@@ -2492,7 +2492,7 @@ call:
lex->sql_command= SQLCOM_CALL;
lex->spname= $2;
lex->value_list.empty();
- sp_add_used_routine(lex, thd, $2, TYPE_ENUM_PROCEDURE);
+ sp_handler_procedure.add_used_routine(lex, thd, $2);
}
opt_sp_cparam_list {}
;
@@ -3380,7 +3380,7 @@ sp_statement:
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CALL;
lex->value_list.empty();
- sp_add_used_routine(lex, thd, lex->spname, TYPE_ENUM_PROCEDURE);
+ sp_handler_procedure.add_used_routine(lex, thd, lex->spname);
}
opt_sp_cparam_list
| ident_directly_assignable '.' ident
@@ -3390,7 +3390,7 @@ sp_statement:
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CALL;
lex->value_list.empty();
- sp_add_used_routine(lex, thd, lex->spname, TYPE_ENUM_PROCEDURE);
+ sp_handler_procedure.add_used_routine(lex, thd, lex->spname);
}
opt_sp_cparam_list
;
@@ -3454,36 +3454,16 @@ sp_proc_stmt_return:
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
-
- if (sp->m_type != TYPE_ENUM_FUNCTION)
- my_yyabort_error((ER_SP_BADRETURN, MYF(0)));
-
- sp_instr_freturn *i;
-
- i= new (thd->mem_root)
- sp_instr_freturn(sp->instructions(), lex->spcont, $3,
- sp->m_return_field_def.type_handler(), lex);
- if (i == NULL || sp->add_instr(i))
- MYSQL_YYABORT;
- sp->m_flags|= sp_head::HAS_RETURN;
-
- if (sp->restore_lex(thd))
+ if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
+ $3, lex) ||
+ sp->restore_lex(thd))
MYSQL_YYABORT;
}
| RETURN_SYM
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
-
- if (sp->m_type != TYPE_ENUM_PROCEDURE)
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- sp_instr_preturn *i;
- i= new (thd->mem_root)
- sp_instr_preturn(sp->instructions(), lex->spcont);
- if (i == NULL || sp->add_instr(i))
+ if (sp->m_handler->add_instr_preturn(thd, sp, lex->spcont))
MYSQL_YYABORT;
}
;
@@ -16844,7 +16824,7 @@ trigger_tail:
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
- if (!lex->make_sp_head(thd, $4, TYPE_ENUM_TRIGGER))
+ if (!lex->make_sp_head(thd, $4, &sp_handler_trigger))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
@@ -16920,7 +16900,7 @@ sf_tail:
sp_name
{
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
- TYPE_ENUM_FUNCTION))
+ &sp_handler_function))
MYSQL_YYABORT;
}
opt_sp_parenthesized_fdparam_list
@@ -16958,7 +16938,7 @@ sp_tail:
opt_if_not_exists sp_name
{
if (!Lex->make_sp_head_no_recursive(thd, $1, $2,
- TYPE_ENUM_PROCEDURE))
+ &sp_handler_procedure))
MYSQL_YYABORT;
}
opt_sp_parenthesized_pdparam_list
diff --git a/sql/structs.h b/sql/structs.h
index 982eda99d30..97702e5727b 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -221,6 +221,8 @@ struct AUTHID
l->length= strxmov(buf, user.str, "@", host.str, NullS) - buf;
}
}
+ void parse(const char *str, size_t length);
+ bool read_from_mysql_proc_row(THD *thd, TABLE *table);
};
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 87eb97e4fec..ba8312d302a 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -2236,26 +2236,23 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
sp_head *sp = thd->lex->sphead;
sql_mode_t saved_mode= thd->variables.sql_mode;
String retstr(64);
+ LEX_CSTRING returns= empty_clex_str;
retstr.set_charset(system_charset_info);
log_query.set_charset(system_charset_info);
- if (sp->m_type == TYPE_ENUM_FUNCTION)
+ if (sp->m_handler->type() == TYPE_ENUM_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
+ returns= retstr.lex_cstring();
}
- 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.c_ptr(), retstr.length(),
- sp->m_body.str, sp->m_body.length,
- sp->chistics(), &(thd->lex->definer->user),
- &(thd->lex->definer->host),
- saved_mode))
+ if (!sp->m_handler->
+ 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],
+ saved_mode))
{
WSREP_WARN("SP create string failed: schema: %s, query: %s",
(thd->db ? thd->db : "(null)"), thd->query());