summaryrefslogtreecommitdiff
path: root/sql/sp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sp.cc')
-rw-r--r--sql/sp.cc1585
1 files changed, 790 insertions, 795 deletions
diff --git a/sql/sp.cc b/sql/sp.cc
index 3af51b82521..cc545992857 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -13,7 +13,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
#include "mysql_priv.h"
#include "sp.h"
#include "sp_head.h"
@@ -37,7 +36,8 @@ static int
db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
ulong sql_mode, const char *params, const char *returns,
const char *body, st_sp_chistics &chistics,
- const char *definer, longlong created, longlong modified);
+ const char *definer, longlong created, longlong modified,
+ Stored_program_creation_ctx *creation_ctx);
/*
*
@@ -49,7 +49,7 @@ enum
{
MYSQL_PROC_FIELD_DB = 0,
MYSQL_PROC_FIELD_NAME,
- MYSQL_PROC_FIELD_TYPE,
+ MYSQL_PROC_MYSQL_TYPE,
MYSQL_PROC_FIELD_SPECIFIC_NAME,
MYSQL_PROC_FIELD_LANGUAGE,
MYSQL_PROC_FIELD_ACCESS,
@@ -63,143 +63,273 @@ enum
MYSQL_PROC_FIELD_MODIFIED,
MYSQL_PROC_FIELD_SQL_MODE,
MYSQL_PROC_FIELD_COMMENT,
+ MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT,
+ MYSQL_PROC_FIELD_COLLATION_CONNECTION,
+ MYSQL_PROC_FIELD_DB_COLLATION,
+ MYSQL_PROC_FIELD_BODY_UTF8,
MYSQL_PROC_FIELD_COUNT
};
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
+/*************************************************************************/
-/*
- Close mysql.proc, opened with open_proc_table_for_read().
-
- SYNOPSIS
- close_proc_table()
- thd Thread context
- backup Pointer to Open_tables_state instance which holds
- information about tables which were open before we
- decided to access mysql.proc.
+/**
+ Stored_routine_creation_ctx -- creation context of stored routines
+ (stored procedures and functions).
*/
-void close_proc_table(THD *thd, Open_tables_state *backup)
+class Stored_routine_creation_ctx : public Stored_program_creation_ctx,
+ public Sql_alloc
{
- close_thread_tables(thd);
- thd->restore_backup_open_tables_state(backup);
+public:
+ static Stored_routine_creation_ctx *
+ load_from_db(THD *thd, const sp_name *name, TABLE *proc_tbl);
+
+public:
+ virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root)
+ {
+ return new (mem_root) Stored_routine_creation_ctx(m_client_cs,
+ m_connection_cl,
+ m_db_cl);
+ }
+
+protected:
+ virtual Object_creation_ctx *create_backup_ctx(THD *thd) const
+ {
+ DBUG_ENTER("Stored_routine_creation_ctx::create_backup_ctx");
+ DBUG_RETURN(new Stored_routine_creation_ctx(thd));
+ }
+
+private:
+ Stored_routine_creation_ctx(THD *thd)
+ : Stored_program_creation_ctx(thd)
+ { }
+
+ Stored_routine_creation_ctx(CHARSET_INFO *client_cs,
+ CHARSET_INFO *connection_cl,
+ CHARSET_INFO *db_cl)
+ : Stored_program_creation_ctx(client_cs, connection_cl, db_cl)
+ { }
+};
+
+/**************************************************************************
+ Stored_routine_creation_ctx implementation.
+**************************************************************************/
+
+bool load_charset(MEM_ROOT *mem_root,
+ Field *field,
+ CHARSET_INFO *dflt_cs,
+ CHARSET_INFO **cs)
+{
+ String cs_name;
+
+ if (get_field(mem_root, field, &cs_name))
+ {
+ *cs= dflt_cs;
+ return TRUE;
+ }
+
+ *cs= get_charset_by_csname(cs_name.c_ptr(), MY_CS_PRIMARY, MYF(0));
+
+ if (*cs == NULL)
+ {
+ *cs= dflt_cs;
+ return TRUE;
+ }
+
+ return FALSE;
}
+/*************************************************************************/
-/*
- Open the mysql.proc table for read.
+bool load_collation(MEM_ROOT *mem_root,
+ Field *field,
+ CHARSET_INFO *dflt_cl,
+ CHARSET_INFO **cl)
+{
+ String cl_name;
- SYNOPSIS
- open_proc_table_for_read()
- thd Thread context
- backup Pointer to Open_tables_state instance where information about
- currently open tables will be saved, and from which will be
- restored when we will end work with mysql.proc.
-
- NOTES
- Thanks to restrictions which we put on opening and locking of
- this table for writing, we can open and lock it for reading
- even when we already have some other tables open and locked.
- One must call close_proc_table() to close table opened with
- this call.
-
- RETURN
- 0 Error
- # Pointer to TABLE object of mysql.proc
-*/
+ if (get_field(mem_root, field, &cl_name))
+ {
+ *cl= dflt_cl;
+ return TRUE;
+ }
-TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
+ *cl= get_charset_by_name(cl_name.c_ptr(), MYF(0));
+
+ if (*cl == NULL)
+ {
+ *cl= dflt_cl;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*************************************************************************/
+
+Stored_routine_creation_ctx *
+Stored_routine_creation_ctx::load_from_db(THD *thd,
+ const sp_name *name,
+ TABLE *proc_tbl)
{
- TABLE_LIST tables;
- TABLE *table;
- bool not_used;
- DBUG_ENTER("open_proc_table");
+ /* Load character set/collation attributes. */
+
+ CHARSET_INFO *client_cs;
+ CHARSET_INFO *connection_cl;
+ CHARSET_INFO *db_cl;
- thd->reset_n_backup_open_tables_state(backup);
+ const char *db_name= thd->strmake(name->m_db.str, name->m_db.length);
+ const char *sr_name= thd->strmake(name->m_name.str, name->m_name.length);
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*)"proc";
- if (!(table= open_table(thd, &tables, thd->mem_root, &not_used,
- MYSQL_LOCK_IGNORE_FLUSH)))
+ bool invalid_creation_ctx= FALSE;
+
+ if (load_charset(thd->mem_root,
+ proc_tbl->field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT],
+ thd->variables.character_set_client,
+ &client_cs))
{
- thd->restore_backup_open_tables_state(backup);
- DBUG_RETURN(0);
+ sql_print_warning("Stored routine '%s'.'%s': invalid value "
+ "in column mysql.proc.character_set_client.",
+ (const char *) db_name,
+ (const char *) sr_name);
+
+ invalid_creation_ctx= TRUE;
+ }
+
+ if (load_collation(thd->mem_root,
+ proc_tbl->field[MYSQL_PROC_FIELD_COLLATION_CONNECTION],
+ thd->variables.collation_connection,
+ &connection_cl))
+ {
+ sql_print_warning("Stored routine '%s'.'%s': invalid value "
+ "in column mysql.proc.collation_connection.",
+ (const char *) db_name,
+ (const char *) sr_name);
+
+ invalid_creation_ctx= TRUE;
+ }
+
+ if (load_collation(thd->mem_root,
+ proc_tbl->field[MYSQL_PROC_FIELD_DB_COLLATION],
+ NULL,
+ &db_cl))
+ {
+ sql_print_warning("Stored routine '%s'.'%s': invalid value "
+ "in column mysql.proc.db_collation.",
+ (const char *) db_name,
+ (const char *) sr_name);
+
+ invalid_creation_ctx= TRUE;
}
- DBUG_ASSERT(table->s->system_table);
+ if (invalid_creation_ctx)
+ {
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_SR_INVALID_CREATION_CTX,
+ ER(ER_SR_INVALID_CREATION_CTX),
+ (const char *) db_name,
+ (const char *) sr_name);
+ }
- table->reginfo.lock_type= TL_READ;
/*
- We have to ensure we are not blocked by a flush tables, as this
- could lead to a deadlock if we have other tables opened.
+ If we failed to retrieve the database collation, load the default one
+ from the disk.
*/
- if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
- MYSQL_LOCK_IGNORE_FLUSH, &not_used)))
- {
- close_proc_table(thd, backup);
+
+ if (!db_cl)
+ db_cl= get_default_db_collation(thd, name->m_db.str);
+
+ /* Create the context. */
+
+ return new Stored_routine_creation_ctx(client_cs, connection_cl, db_cl);
+}
+
+/*************************************************************************/
+
+/**
+ Open the mysql.proc table for read.
+
+ @param thd Thread context
+ @param backup Pointer to Open_tables_state instance where information about
+ currently open tables will be saved, and from which will be
+ restored when we will end work with mysql.proc.
+
+ @retval
+ 0 Error
+ @retval
+ \# Pointer to TABLE object of mysql.proc
+*/
+
+TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
+{
+ DBUG_ENTER("open_proc_table_for_read");
+
+ TABLE_LIST table;
+ bzero((char*) &table, sizeof(table));
+ table.db= (char*) "mysql";
+ table.table_name= table.alias= (char*)"proc";
+ table.lock_type= TL_READ;
+
+ if (!open_system_tables_for_read(thd, &table, backup))
+ DBUG_RETURN(table.table);
+ else
DBUG_RETURN(0);
- }
- DBUG_RETURN(table);
}
-/*
+/**
Open the mysql.proc table for update.
- SYNOPSIS
- open_proc_table_for_update()
- thd Thread context
+ @param thd Thread context
- NOTES
+ @note
Table opened with this call should closed using close_thread_tables().
- RETURN
+ @retval
0 Error
- # Pointer to TABLE object of mysql.proc
+ @retval
+ \# Pointer to TABLE object of mysql.proc
*/
static TABLE *open_proc_table_for_update(THD *thd)
{
- TABLE_LIST tables;
- TABLE *table;
- DBUG_ENTER("open_proc_table");
+ DBUG_ENTER("open_proc_table_for_update");
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*)"proc";
- tables.lock_type= TL_WRITE;
+ TABLE_LIST table;
+ bzero((char*) &table, sizeof(table));
+ table.db= (char*) "mysql";
+ table.table_name= table.alias= (char*)"proc";
+ table.lock_type= TL_WRITE;
- table= open_ltable(thd, &tables, TL_WRITE);
-
- DBUG_RETURN(table);
+ DBUG_RETURN(open_system_table_for_update(thd, &table));
}
-/*
+/**
Find row in open mysql.proc table representing stored routine.
- SYNOPSIS
- db_find_routine_aux()
- thd Thread context
- type Type of routine to find (function or procedure)
- name Name of routine
- table TABLE object for open mysql.proc table.
+ @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.
- RETURN VALUE
- SP_OK - Routine found
- SP_KEY_NOT_FOUND- No routine with given name
+ @retval
+ SP_OK Routine found
+ @retval
+ SP_KEY_NOT_FOUND No routine with given name
*/
static int
db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
{
- byte key[MAX_KEY_LENGTH]; // db, name, optional key length type
+ 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, name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("type: %d name: %.*s",
+ type, (int) name->m_name.length, name->m_name.str));
/*
Create key to find row. We have to use field->store() to be able to
@@ -217,34 +347,32 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
key_copy(key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx(table->record[0], 0,
- key, table->key_info->key_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read_idx_map(table->record[0], 0, key, HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
DBUG_RETURN(SP_KEY_NOT_FOUND);
DBUG_RETURN(SP_OK);
}
-/*
+/**
Find routine definition in mysql.proc table and create corresponding
sp_head object for it.
- SYNOPSIS
- db_find_routine()
- thd Thread context
- type Type of routine (TYPE_ENUM_PROCEDURE/...)
- name Name of routine
- sphp Out parameter in which pointer to created sp_head
- object is returned (0 in case of error).
+ @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).
- NOTE
+ @note
This function may damage current LEX during execution, so it is good
idea to create temporary LEX and make it active before calling it.
- RETURN VALUE
- 0 - Success
- non-0 - Error (may be one of special codes like SP_KEY_NOT_FOUND)
+ @retval
+ 0 Success
+ @retval
+ non-0 Error (may be one of special codes like SP_KEY_NOT_FOUND)
*/
static int
@@ -261,17 +389,22 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
uint length;
char buff[65];
String str(buff, sizeof(buff), &my_charset_bin);
- ulong sql_mode;
bool saved_time_zone_used= thd->time_zone_used;
+ ulong sql_mode, saved_mode= thd->variables.sql_mode;
Open_tables_state open_tables_state_backup;
+ Stored_program_creation_ctx *creation_ctx;
+
DBUG_ENTER("db_find_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, name->m_name.length, name->m_name.str));
+ type, (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)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+ /* Reset sql_mode during data dictionary operations. */
+ thd->variables.sql_mode= 0;
+
if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
goto done;
@@ -364,13 +497,14 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
chistics.comment.str= ptr;
chistics.comment.length= length;
- close_proc_table(thd, &open_tables_state_backup);
+ creation_ctx= Stored_routine_creation_ctx::load_from_db(thd, name, table);
+
+ close_system_tables(thd, &open_tables_state_backup);
table= 0;
ret= db_load_routine(thd, type, name, sphp,
sql_mode, params, returns, body, chistics,
- definer, created, modified);
-
+ definer, created, modified, creation_ctx);
done:
/*
Restore the time zone flag as the timezone usage in proc table
@@ -378,34 +512,62 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
*/
thd->time_zone_used= saved_time_zone_used;
if (table)
- close_proc_table(thd, &open_tables_state_backup);
+ close_system_tables(thd, &open_tables_state_backup);
+ thd->variables.sql_mode= saved_mode;
DBUG_RETURN(ret);
}
+/**
+ Silence DEPRECATED SYNTAX warnings when loading a stored procedure
+ into the cache.
+*/
+struct Silence_deprecated_warning : public Internal_error_handler
+{
+public:
+ virtual bool handle_error(uint sql_errno, const char *message,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd);
+};
+
+bool
+Silence_deprecated_warning::handle_error(uint sql_errno, const char *message,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd)
+{
+ if (sql_errno == ER_WARN_DEPRECATED_SYNTAX &&
+ level == MYSQL_ERROR::WARN_LEVEL_WARN)
+ return TRUE;
+
+ return FALSE;
+}
+
+
static int
db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
ulong sql_mode, const char *params, const char *returns,
const char *body, st_sp_chistics &chistics,
- const char *definer, longlong created, longlong modified)
+ const char *definer, longlong created, longlong modified,
+ Stored_program_creation_ctx *creation_ctx)
{
LEX *old_lex= thd->lex, newlex;
String defstr;
- char old_db_buf[NAME_LEN+1];
- LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
- bool dbchanged;
+ char saved_cur_db_name_buf[NAME_LEN+1];
+ LEX_STRING saved_cur_db_name=
+ { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
+ bool cur_db_changed;
ulong old_sql_mode= thd->variables.sql_mode;
ha_rows old_select_limit= thd->variables.select_limit;
sp_rcontext *old_spcont= thd->spcont;
-
+ Silence_deprecated_warning warning_handler;
+
char definer_user_name_holder[USERNAME_LENGTH + 1];
- LEX_STRING_WITH_INIT definer_user_name(definer_user_name_holder,
- USERNAME_LENGTH);
+ LEX_STRING definer_user_name= { definer_user_name_holder,
+ USERNAME_LENGTH };
char definer_host_name_holder[HOSTNAME_LENGTH + 1];
- LEX_STRING_WITH_INIT definer_host_name(definer_host_name_holder,
- HOSTNAME_LENGTH);
-
+ LEX_STRING definer_host_name= { definer_host_name_holder, HOSTNAME_LENGTH };
+
int ret;
thd->variables.sql_mode= sql_mode;
@@ -414,11 +576,11 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
thd->lex= &newlex;
newlex.current_select= NULL;
- parse_user(definer, (uint) strlen(definer),
+ parse_user(definer, strlen(definer),
definer_user_name.str, &definer_user_name.length,
definer_host_name.str, &definer_host_name.length);
- defstr.set_charset(system_charset_info);
+ defstr.set_charset(creation_ctx->get_client_cs());
/*
We have to add DEFINER clause and provide proper routine characterstics in
@@ -439,49 +601,66 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
goto end;
}
- if ((ret= sp_use_new_db(thd, name->m_db, &old_db, 1, &dbchanged)))
+ /*
+ Change the current database (if needed).
+
+ TODO: why do we force switch here?
+ */
+
+ if (mysql_opt_change_db(thd, &name->m_db, &saved_cur_db_name, TRUE,
+ &cur_db_changed))
+ {
+ ret= SP_INTERNAL_ERROR;
goto end;
+ }
+
+ thd->spcont= NULL;
{
Parser_state parser_state(thd, defstr.c_ptr(), defstr.length());
- thd->m_parser_state= &parser_state;
+
lex_start(thd);
- thd->spcont= NULL;
- ret= MYSQLparse(thd);
- thd->m_parser_state= NULL;
- if (ret == 0)
- {
- /*
- Not strictly necessary to invoke this method here, since we know
- that we've parsed CREATE PROCEDURE/FUNCTION and not an
- UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to
- maintain the invariant that this method is called for each
- distinct statement, in case its logic is extended with other
- types of analyses in future.
- */
- newlex.set_trg_event_type_for_tables();
- }
- }
+ thd->push_internal_handler(&warning_handler);
+ ret= parse_sql(thd, & parser_state, creation_ctx) || newlex.sphead == NULL;
+ thd->pop_internal_handler();
- if (ret || thd->is_fatal_error || newlex.sphead == NULL)
- {
- sp_head *sp= newlex.sphead;
+ /*
+ Force switching back to the saved current database (if changed),
+ because it may be NULL. In this case, mysql_change_db() would
+ generate an error.
+ */
- if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
+ if (cur_db_changed && mysql_change_db(thd, &saved_cur_db_name, TRUE))
+ {
+ delete newlex.sphead;
+ ret= SP_INTERNAL_ERROR;
goto end;
- delete sp;
- ret= SP_PARSE_ERROR;
- }
- else
- {
- if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
+ }
+
+ if (ret)
+ {
+ delete newlex.sphead;
+ ret= SP_PARSE_ERROR;
goto end;
+ }
+
*sphp= newlex.sphead;
(*sphp)->set_definer(&definer_user_name, &definer_host_name);
(*sphp)->set_info(created, modified, &chistics, sql_mode);
+ (*sphp)->set_creation_ctx(creation_ctx);
(*sphp)->optimize();
+ /*
+ Not strictly necessary to invoke this method here, since we know
+ that we've parsed CREATE PROCEDURE/FUNCTION and not an
+ UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to
+ maintain the invariant that this method is called for each
+ distinct statement, in case its logic is extended with other
+ types of analyses in future.
+ */
+ newlex.set_trg_event_type_for_tables();
}
+
end:
lex_end(thd->lex);
thd->spcont= old_spcont;
@@ -496,10 +675,12 @@ static void
sp_returns_type(THD *thd, String &result, sp_head *sp)
{
TABLE table;
+ TABLE_SHARE share;
Field *field;
- bzero(&table, sizeof(table));
+ bzero((char*) &table, sizeof(table));
+ bzero((char*) &share, sizeof(share));
table.in_use= thd;
- table.s = &table.share_not_to_be_used;
+ table.s = &share;
field= sp->create_result_field(0, 0, &table);
field->sql_type(result);
@@ -512,17 +693,65 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
delete field;
}
-static int
-db_create_routine(THD *thd, int type, sp_head *sp)
+
+/**
+ Write stored-routine object into mysql.proc.
+
+ This operation stores attributes of the stored procedure/function into
+ 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
+ that there are no locked tables in this thread at the time of
+ invocation.
+ Unlike some other DDL statements, *does* close the tables
+ in the end, since the call to this function is normally
+ followed by an implicit grant (sp_grant_privileges())
+ and this subsequent call opens and closes mysql.procs_priv.
+
+ @return Error code. SP_OK is returned on success. Other
+ SP_ constants are used to indicate about errors.
+*/
+
+int
+sp_create_routine(THD *thd, int type, sp_head *sp)
{
int ret;
TABLE *table;
char definer[USER_HOST_BUFF_SIZE];
- DBUG_ENTER("db_create_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length,
+ ulong saved_mode= thd->variables.sql_mode;
+
+ CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str);
+
+ enum_check_fields saved_count_cuted_fields;
+
+ bool store_failed= FALSE;
+
+ DBUG_ENTER("sp_create_routine");
+ DBUG_PRINT("enter", ("type: %d name: %.*s",type, (int) sp->m_name.length,
sp->m_name.str));
String retstr(64);
+ DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
+ type == TYPE_ENUM_FUNCTION);
+
+ /* Reset sql_mode during data dictionary operations. */
+ thd->variables.sql_mode= 0;
+
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
+ saved_count_cuted_fields= thd->count_cuted_fields;
+ thd->count_cuted_fields= CHECK_FIELD_WARN;
+
if (!(table= open_proc_table_for_update(thd)))
ret= SP_OPEN_TABLE_FAILED;
else
@@ -530,7 +759,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
restore_record(table, s->default_values); // Get default values for fields
/* NOTE: all needed privilege checks have been already done. */
- strxmov(definer, thd->lex->definer->user.str, "@",
+ strxnmov(definer, sizeof(definer)-1, thd->lex->definer->user.str, "@",
thd->lex->definer->host.str, NullS);
if (table->s->fields < MYSQL_PROC_FIELD_COUNT)
@@ -552,42 +781,76 @@ db_create_routine(THD *thd, int type, sp_head *sp)
ret= SP_BODY_TOO_LONG;
goto done;
}
- table->field[MYSQL_PROC_FIELD_DB]->
- store(sp->m_db.str, sp->m_db.length, system_charset_info);
- table->field[MYSQL_PROC_FIELD_NAME]->
- store(sp->m_name.str, sp->m_name.length, system_charset_info);
- table->field[MYSQL_PROC_FIELD_TYPE]->
- store((longlong)type, 1);
- table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]->
- store(sp->m_name.str, sp->m_name.length, system_charset_info);
+
+ store_failed=
+ table->field[MYSQL_PROC_FIELD_DB]->
+ store(sp->m_db.str, sp->m_db.length, system_charset_info);
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_NAME]->
+ store(sp->m_name.str, sp->m_name.length, system_charset_info);
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_MYSQL_TYPE]->
+ store((longlong)type, TRUE);
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]->
+ store(sp->m_name.str, sp->m_name.length, system_charset_info);
+
if (sp->m_chistics->daccess != SP_DEFAULT_ACCESS)
- table->field[MYSQL_PROC_FIELD_ACCESS]->
- store((longlong)sp->m_chistics->daccess, 1);
- table->field[MYSQL_PROC_FIELD_DETERMINISTIC]->
- store((longlong)(sp->m_chistics->detistic ? 1 : 2), 1);
+ {
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_ACCESS]->
+ store((longlong)sp->m_chistics->daccess, TRUE);
+ }
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_DETERMINISTIC]->
+ store((longlong)(sp->m_chistics->detistic ? 1 : 2), TRUE);
+
if (sp->m_chistics->suid != SP_IS_DEFAULT_SUID)
- table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
- store((longlong)sp->m_chistics->suid, 1);
- table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
- store(sp->m_params.str, sp->m_params.length, system_charset_info);
+ {
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
+ store((longlong)sp->m_chistics->suid, TRUE);
+ }
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
+ store(sp->m_params.str, sp->m_params.length, system_charset_info);
+
if (sp->m_type == TYPE_ENUM_FUNCTION)
{
sp_returns_type(thd, retstr, sp);
- table->field[MYSQL_PROC_FIELD_RETURNS]->
- store(retstr.ptr(), retstr.length(), system_charset_info);
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_RETURNS]->
+ store(retstr.ptr(), retstr.length(), system_charset_info);
}
- table->field[MYSQL_PROC_FIELD_BODY]->
- store(sp->m_body.str, sp->m_body.length, system_charset_info);
- table->field[MYSQL_PROC_FIELD_DEFINER]->
- store(definer, (uint)strlen(definer), system_charset_info);
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_BODY]->
+ store(sp->m_body.str, sp->m_body.length, system_charset_info);
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_DEFINER]->
+ store(definer, (uint)strlen(definer), system_charset_info);
+
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time();
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
- table->field[MYSQL_PROC_FIELD_SQL_MODE]->
- store((longlong)thd->variables.sql_mode, 1);
+
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_SQL_MODE]->
+ store((longlong)saved_mode, TRUE);
+
if (sp->m_chistics->comment.str)
- table->field[MYSQL_PROC_FIELD_COMMENT]->
- store(sp->m_chistics->comment.str, sp->m_chistics->comment.length,
- system_charset_info);
+ {
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_COMMENT]->
+ store(sp->m_chistics->comment.str, sp->m_chistics->comment.length,
+ system_charset_info);
+ }
if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
!trust_function_creators && mysql_bin_log.is_open())
@@ -619,8 +882,38 @@ db_create_routine(THD *thd, int type, sp_head *sp)
}
}
+ table->field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]->set_notnull();
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT]->store(
+ thd->charset()->csname,
+ strlen(thd->charset()->csname),
+ system_charset_info);
+
+ table->field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]->set_notnull();
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_COLLATION_CONNECTION]->store(
+ thd->variables.collation_connection->name,
+ strlen(thd->variables.collation_connection->name),
+ system_charset_info);
+
+ table->field[MYSQL_PROC_FIELD_DB_COLLATION]->set_notnull();
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_DB_COLLATION]->store(
+ db_cs->name, strlen(db_cs->name), system_charset_info);
+
+ table->field[MYSQL_PROC_FIELD_BODY_UTF8]->set_notnull();
+ store_failed= store_failed ||
+ table->field[MYSQL_PROC_FIELD_BODY_UTF8]->store(
+ sp->m_body_utf8.str, sp->m_body_utf8.length, system_charset_info);
+
+ if (store_failed)
+ {
+ ret= SP_FLD_STORE_FAILED;
+ goto done;
+ }
+
ret= SP_OK;
- if (table->file->write_row(table->record[0]))
+ if (table->file->ha_write_row(table->record[0]))
ret= SP_WRITE_ROW_FAILED;
else if (mysql_bin_log.is_open())
{
@@ -645,44 +938,67 @@ db_create_routine(THD *thd, int type, sp_head *sp)
}
/* Such a statement can always go directly to binlog, no trans cache */
- Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0,
- FALSE);
- mysql_bin_log.write(&qinfo);
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+ log_query.c_ptr(), log_query.length(), FALSE, FALSE);
}
}
done:
+ thd->count_cuted_fields= saved_count_cuted_fields;
+ thd->variables.sql_mode= saved_mode;
+
close_thread_tables(thd);
DBUG_RETURN(ret);
}
-static int
-db_drop_routine(THD *thd, int type, sp_name *name)
+/**
+ Delete the record for the stored routine object from mysql.proc.
+
+ The operation deletes the record for the stored routine specified by name
+ 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
+ used to indicate about errors.
+*/
+
+int
+sp_drop_routine(THD *thd, int type, sp_name *name)
{
TABLE *table;
int ret;
- DBUG_ENTER("db_drop_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, name->m_name.length, name->m_name.str));
+ 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);
+
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
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 (table->file->delete_row(table->record[0]))
+ if (table->file->ha_delete_row(table->record[0]))
ret= SP_DELETE_ROW_FAILED;
}
if (ret == SP_OK)
{
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
+ sp_cache_invalidate();
}
close_thread_tables(thd);
@@ -690,14 +1006,40 @@ db_drop_routine(THD *thd, int type, sp_name *name)
}
-static int
-db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
+/**
+ Find and updated the record for the stored routine object in mysql.proc.
+
+ The operation finds the record for the stored routine specified by name
+ in the mysql.proc table and updates it with new attributes. After
+ 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.
+
+ @return Error code. SP_OK is returned on success. Other SP_ constants are
+ used to indicate about errors.
+*/
+
+int
+sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
{
TABLE *table;
int ret;
- DBUG_ENTER("db_update_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, name->m_name.length, name->m_name.str));
+ DBUG_ENTER("sp_update_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);
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
@@ -708,26 +1050,25 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
if (chistics->suid != SP_IS_DEFAULT_SUID)
table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
- store((longlong)chistics->suid, 1);
+ store((longlong)chistics->suid, TRUE);
if (chistics->daccess != SP_DEFAULT_ACCESS)
table->field[MYSQL_PROC_FIELD_ACCESS]->
- store((longlong)chistics->daccess, 1);
+ store((longlong)chistics->daccess, TRUE);
if (chistics->comment.str)
table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str,
chistics->comment.length,
system_charset_info);
- if ((table->file->update_row(table->record[1],table->record[0])))
+ if ((ret= table->file->ha_update_row(table->record[1],table->record[0])) &&
+ ret != HA_ERR_RECORD_IS_THE_SAME)
ret= SP_WRITE_ROW_FAILED;
+ else
+ ret= 0;
}
if (ret == SP_OK)
{
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
+ sp_cache_invalidate();
}
close_thread_tables(thd);
@@ -735,187 +1076,13 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
}
-struct st_used_field
-{
- const char *field_name;
- uint field_length;
- enum enum_field_types field_type;
- Field *field;
-};
-
-static struct st_used_field init_fields[]=
-{
- { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0},
- { "Name", NAME_LEN, MYSQL_TYPE_STRING, 0},
- { "Type", 9, MYSQL_TYPE_STRING, 0},
- { "Definer", 77, MYSQL_TYPE_STRING, 0},
- { "Modified", 0, MYSQL_TYPE_TIMESTAMP, 0},
- { "Created", 0, MYSQL_TYPE_TIMESTAMP, 0},
- { "Security_type", 1, MYSQL_TYPE_STRING, 0},
- { "Comment", NAME_LEN, MYSQL_TYPE_STRING, 0},
- { 0, 0, MYSQL_TYPE_STRING, 0}
-};
-
-
-static int
-print_field_values(THD *thd, TABLE *table,
- struct st_used_field *used_fields,
- int type, const char *wild)
-{
- Protocol *protocol= thd->protocol;
-
- if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type)
- {
- String db_string;
- String name_string;
- struct st_used_field *used_field= used_fields;
-
- if (get_field(thd->mem_root, used_field->field, &db_string))
- db_string.set_ascii("", 0);
- used_field+= 1;
- get_field(thd->mem_root, used_field->field, &name_string);
-
- if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0))
- {
- protocol->prepare_for_resend();
- protocol->store(&db_string);
- protocol->store(&name_string);
- for (used_field++;
- used_field->field_name;
- used_field++)
- {
- switch (used_field->field_type) {
- case MYSQL_TYPE_TIMESTAMP:
- {
- MYSQL_TIME tmp_time;
-
- bzero((char *)&tmp_time, sizeof(tmp_time));
- ((Field_timestamp *) used_field->field)->get_time(&tmp_time);
- protocol->store(&tmp_time);
- }
- break;
- default:
- {
- String tmp_string;
-
- get_field(thd->mem_root, used_field->field, &tmp_string);
- protocol->store(&tmp_string);
- }
- break;
- }
- }
- if (protocol->write())
- return SP_INTERNAL_ERROR;
- }
- }
-
- return SP_OK;
-}
-
-
-static int
-db_show_routine_status(THD *thd, int type, const char *wild)
-{
- TABLE *table;
- TABLE_LIST tables;
- int res;
- DBUG_ENTER("db_show_routine_status");
-
- memset(&tables, 0, sizeof(tables));
- tables.db= (char*)"mysql";
- tables.table_name= tables.alias= (char*)"proc";
-
- if (! (table= open_ltable(thd, &tables, TL_READ)))
- {
- res= SP_OPEN_TABLE_FAILED;
- goto done;
- }
- else
- {
- Item *item;
- List<Item> field_list;
- struct st_used_field *used_field;
- TABLE_LIST *leaves= 0;
- st_used_field used_fields[array_elements(init_fields)];
-
- memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields));
- /* Init header */
- for (used_field= &used_fields[0];
- used_field->field_name;
- used_field++)
- {
- switch (used_field->field_type) {
- case MYSQL_TYPE_TIMESTAMP:
- field_list.push_back(item=new Item_datetime(used_field->field_name));
- break;
- default:
- field_list.push_back(item=new Item_empty_string(used_field->field_name,
- used_field->
- field_length));
- break;
- }
- }
- /* Print header */
- if (thd->protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
- Protocol::SEND_EOF))
- {
- res= SP_INTERNAL_ERROR;
- goto err_case;
- }
-
- /*
- Init fields
-
- tables is not VIEW for sure => we can pass 0 as condition
- */
- thd->lex->select_lex.context.resolve_in_table_list_only(&tables);
- setup_tables(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
- &tables, 0, &leaves, FALSE);
- for (used_field= &used_fields[0];
- used_field->field_name;
- used_field++)
- {
- Item_field *field= new Item_field(&thd->lex->select_lex.context,
- "mysql", "proc",
- used_field->field_name);
- if (!field ||
- !(used_field->field= find_field_in_tables(thd, field, &tables, NULL,
- 0, REPORT_ALL_ERRORS, 1,
- TRUE)))
- {
- res= SP_INTERNAL_ERROR;
- goto err_case1;
- }
- }
-
- table->file->ha_index_init(0);
- if ((res= table->file->index_first(table->record[0])))
- {
- res= (res == HA_ERR_END_OF_FILE) ? 0 : SP_INTERNAL_ERROR;
- goto err_case1;
- }
- if ((res= print_field_values(thd, table, used_fields, type, wild)))
- goto err_case1;
- while (!table->file->index_next(table->record[0]))
- {
- if ((res= print_field_values(thd, table, used_fields, type, wild)))
- goto err_case1;
- }
- res= SP_OK;
- }
-
-err_case1:
- send_eof(thd);
-err_case:
- table->file->ha_index_end();
- close_thread_tables(thd);
-done:
- DBUG_RETURN(res);
-}
+/**
+ Drop all routines in database 'db'
+ @note Close the thread tables, the calling code might want to
+ delete from other system tables afterwards.
+*/
-/* Drop all routines in database 'db' */
int
sp_drop_db_routines(THD *thd, char *db)
{
@@ -929,21 +1096,21 @@ sp_drop_db_routines(THD *thd, char *db)
if (!(table= open_proc_table_for_update(thd)))
goto err;
- table->field[MYSQL_PROC_FIELD_DB]->store(db, (uint) strlen(db), system_charset_info);
+ table->field[MYSQL_PROC_FIELD_DB]->store(db, strlen(db), system_charset_info);
key_len= table->key_info->key_part[0].store_length;
ret= SP_OK;
- table->file->ha_index_init(0);
- if (! table->file->index_read(table->record[0],
- (byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
- key_len, HA_READ_KEY_EXACT))
+ table->file->ha_index_init(0, 1);
+ if (! table->file->index_read_map(table->record[0],
+ (uchar *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
+ (key_part_map)1, HA_READ_KEY_EXACT))
{
int nxtres;
bool deleted= FALSE;
do
{
- if (! table->file->delete_row(table->record[0]))
+ if (! table->file->ha_delete_row(table->record[0]))
deleted= TRUE; /* We deleted something */
else
{
@@ -952,7 +1119,7 @@ sp_drop_db_routines(THD *thd, char *db)
break;
}
} while (! (nxtres= table->file->index_next_same(table->record[0],
- (byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
+ (uchar *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
key_len)));
if (nxtres != HA_ERR_END_OF_FILE)
ret= SP_KEY_NOT_FOUND;
@@ -968,26 +1135,78 @@ err:
}
-/*****************************************************************************
- PROCEDURE
-******************************************************************************/
+/**
+ Implement SHOW CREATE statement for stored routines.
-/*
+ The operation finds the stored routine object specified by name and then
+ 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.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+
+bool
+sp_show_create_routine(THD *thd, int type, sp_name *name)
+{
+ bool err_status= TRUE;
+ sp_head *sp;
+ sp_cache **cache = type == TYPE_ENUM_PROCEDURE ?
+ &thd->sp_proc_cache : &thd->sp_func_cache;
+
+ DBUG_ENTER("sp_show_create_routine");
+ DBUG_PRINT("enter", ("name: %.*s",
+ (int) name->m_name.length,
+ name->m_name.str));
+
+ DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
+ type == TYPE_ENUM_FUNCTION);
+
+ if (type == TYPE_ENUM_PROCEDURE)
+ {
+ /*
+ SHOW CREATE PROCEDURE may require two instances of one sp_head
+ object when SHOW CREATE PROCEDURE is called for the procedure that
+ is being executed. Basically, there is no actual recursion, so we
+ increase the recursion limit for this statement (kind of hack).
+
+ SHOW CREATE FUNCTION does not require this because SHOW CREATE
+ statements are prohibitted within stored functions.
+ */
+
+ thd->variables.max_sp_recursion_depth++;
+ }
+
+ if ((sp= sp_find_routine(thd, type, name, cache, FALSE)))
+ err_status= sp->show_create_routine(thd, type);
+
+ if (type == TYPE_ENUM_PROCEDURE)
+ thd->variables.max_sp_recursion_depth--;
+
+ DBUG_RETURN(err_status);
+}
+
+
+/**
Obtain object representing stored procedure/function by its name from
stored procedures cache and looking into mysql.proc if needed.
- SYNOPSIS
- sp_find_routine()
- thd - thread context
- type - type of object (TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE)
- name - name of procedure
- cp - hash to look routine in
- cache_only - if true perform cache-only lookup
- (Don't look in mysql.proc).
-
- RETURN VALUE
- Non-0 pointer to sp_head object for the procedure, or
- 0 - in case of error.
+ @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
+ (Don't look in mysql.proc).
+
+ @retval
+ NonNULL pointer to sp_head object for the procedure
+ @retval
+ NULL in case of error.
*/
sp_head *
@@ -999,9 +1218,9 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
thd->variables.max_sp_recursion_depth :
0);
DBUG_ENTER("sp_find_routine");
- DBUG_PRINT("enter", ("name: %.*s.%.*s, type: %d, cache only %d",
- name->m_db.length, name->m_db.str,
- name->m_name.length, name->m_name.str,
+ DBUG_PRINT("enter", ("name: %.*s.%.*s type: %d cache only %d",
+ (int) name->m_db.length, name->m_db.str,
+ (int) name->m_name.length, name->m_name.str,
type, cache_only));
if ((sp= sp_cache_lookup(cp, name)))
@@ -1020,7 +1239,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp));
if (sp->m_first_free_instance)
{
- DBUG_PRINT("info", ("first free: 0x%lx, level: %lu, flags %x",
+ DBUG_PRINT("info", ("first free: 0x%lx level: %lu flags %x",
(ulong)sp->m_first_free_instance,
sp->m_first_free_instance->m_recursion_level,
sp->m_first_free_instance->m_flags));
@@ -1055,7 +1274,8 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
if (db_load_routine(thd, type, name, &new_sp,
sp->m_sql_mode, sp->m_params.str, returns,
sp->m_body.str, *sp->m_chistics, definer,
- sp->m_created, sp->m_modified) == SP_OK)
+ sp->m_created, sp->m_modified,
+ sp->get_creation_ctx()) == SP_OK)
{
sp->m_last_cached_sp->m_next_cached_sp= new_sp;
new_sp->m_recursion_level= level;
@@ -1082,7 +1302,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
}
-/*
+/**
This is used by sql_acl.cc:mysql_routine_grant() and is used to find
the routines in 'routines'.
*/
@@ -1099,8 +1319,8 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error)
sp_name *name;
LEX_STRING lex_db;
LEX_STRING lex_name;
- lex_db.length= (uint) strlen(routine->db);
- lex_name.length= (uint) strlen(routine->table_name);
+ lex_db.length= strlen(routine->db);
+ lex_name.length= strlen(routine->table_name);
lex_db.str= thd->strmake(routine->db, lex_db.length);
lex_name.str= thd->strmake(routine->table_name, lex_name.length);
name= new sp_name(lex_db, lex_name, true);
@@ -1131,18 +1351,17 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error)
}
-/*
+/**
Check if a routine exists in the mysql.proc table, without actually
- parsing the definition. (Used for dropping)
+ parsing the definition. (Used for dropping).
- SYNOPSIS
- sp_routine_exists_in_table()
- thd - thread context
- name - name of procedure
+ @param thd thread context
+ @param name name of procedure
- RETURN VALUE
- 0 - Success
- non-0 - Error; SP_OPEN_TABLE_FAILED or SP_KEY_NOT_FOUND
+ @retval
+ 0 Success
+ @retval
+ non-0 Error; SP_OPEN_TABLE_FAILED or SP_KEY_NOT_FOUND
*/
int
@@ -1158,158 +1377,13 @@ sp_routine_exists_in_table(THD *thd, int type, sp_name *name)
{
if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
ret= SP_KEY_NOT_FOUND;
- close_proc_table(thd, &open_tables_state_backup);
+ close_system_tables(thd, &open_tables_state_backup);
}
return ret;
}
-int
-sp_create_procedure(THD *thd, sp_head *sp)
-{
- int ret;
- DBUG_ENTER("sp_create_procedure");
- DBUG_PRINT("enter", ("name: %.*s", sp->m_name.length, sp->m_name.str));
-
- ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp);
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_drop_procedure(THD *thd, sp_name *name)
-{
- int ret;
- DBUG_ENTER("sp_drop_procedure");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
- if (!ret)
- sp_cache_invalidate();
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
-{
- int ret;
- DBUG_ENTER("sp_update_procedure");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
- if (!ret)
- sp_cache_invalidate();
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_show_create_procedure(THD *thd, sp_name *name)
-{
- int ret= SP_KEY_NOT_FOUND;
- sp_head *sp;
- DBUG_ENTER("sp_show_create_procedure");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- /*
- Increase the recursion limit for this statement. SHOW CREATE PROCEDURE
- does not do actual recursion.
- */
- thd->variables.max_sp_recursion_depth++;
- if ((sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, name,
- &thd->sp_proc_cache, FALSE)))
- ret= sp->show_create_procedure(thd);
-
- thd->variables.max_sp_recursion_depth--;
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_show_status_procedure(THD *thd, const char *wild)
-{
- int ret;
- DBUG_ENTER("sp_show_status_procedure");
-
- ret= db_show_routine_status(thd, TYPE_ENUM_PROCEDURE, wild);
- DBUG_RETURN(ret);
-}
-
-
-/*****************************************************************************
- FUNCTION
-******************************************************************************/
-
-int
-sp_create_function(THD *thd, sp_head *sp)
-{
- int ret;
- DBUG_ENTER("sp_create_function");
- DBUG_PRINT("enter", ("name: %.*s", sp->m_name.length, sp->m_name.str));
-
- ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp);
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_drop_function(THD *thd, sp_name *name)
-{
- int ret;
- DBUG_ENTER("sp_drop_function");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
- if (!ret)
- sp_cache_invalidate();
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
-{
- int ret;
- DBUG_ENTER("sp_update_procedure");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
- if (!ret)
- sp_cache_invalidate();
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_show_create_function(THD *thd, sp_name *name)
-{
- sp_head *sp;
- DBUG_ENTER("sp_show_create_function");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- if ((sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, name,
- &thd->sp_func_cache, FALSE)))
- {
- int ret= sp->show_create_function(thd);
-
- DBUG_RETURN(ret);
- }
- DBUG_RETURN(SP_KEY_NOT_FOUND);
-}
-
-
-int
-sp_show_status_function(THD *thd, const char *wild)
-{
- int ret;
- DBUG_ENTER("sp_show_status_function");
- ret= db_show_routine_status(thd, TYPE_ENUM_FUNCTION, wild);
- DBUG_RETURN(ret);
-}
-
-
-/*
+/**
Structure that represents element in the set of stored routines
used by statement or routine.
*/
@@ -1317,14 +1391,16 @@ struct Sroutine_hash_entry;
struct Sroutine_hash_entry
{
- /* Set key consisting of one-byte routine type and quoted routine name. */
+ /**
+ Set key consisting of one-byte routine type and quoted routine name.
+ */
LEX_STRING key;
- /*
+ /**
Next element in list linking all routines in set. See also comments
for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
*/
Sroutine_hash_entry *next;
- /*
+ /**
Uppermost view which directly or indirectly uses this routine.
0 if routine is not used in view. Note that it also can be 0 if
statement uses routine both via view and directly.
@@ -1333,32 +1409,31 @@ struct Sroutine_hash_entry
};
-extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first)
+extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
+ my_bool first)
{
Sroutine_hash_entry *rn= (Sroutine_hash_entry *)ptr;
*plen= rn->key.length;
- return (byte *)rn->key.str;
+ return (uchar *)rn->key.str;
}
-/*
+/**
Check if
- current statement (the one in thd->lex) needs table prelocking
- first routine in thd->lex->sroutines_list needs to execute its body in
prelocked mode.
- SYNOPSIS
- sp_get_prelocking_info()
- thd Current thread, thd->lex is the statement to be
- checked.
- need_prelocking OUT TRUE - prelocked mode should be activated
- before executing the statement
- FALSE - Don't activate prelocking
- first_no_prelocking OUT TRUE - Tables used by first routine in
- thd->lex->sroutines_list should be
- prelocked.
- FALSE - Otherwise.
- NOTES
+ @param thd Current thread, thd->lex is the statement to be
+ checked.
+ @param[out] need_prelocking TRUE - prelocked mode should be activated
+ before executing the statement;
+ FALSE - Don't activate prelocking
+ @param[out] first_no_prelocking TRUE - Tables used by first routine in
+ thd->lex->sroutines_list should be
+ prelocked. FALSE - Otherwise.
+
+ @note
This function assumes that for any "CALL proc(...)" statement routines_list
will have 'proc' as first element (it may have several, consider e.g.
"proc(sp_func(...)))". This property is currently guaranted by the parser.
@@ -1378,36 +1453,37 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
}
-/*
+/**
Auxilary function that adds new element to the set of stored routines
used by statement.
- SYNOPSIS
- add_used_routine()
- lex LEX representing statement
- arena Arena in which memory for new element will be allocated
- key Key for the hash representing set
- belong_to_view Uppermost view which uses this routine
- (0 if routine is not used by view)
+ In case when statement uses stored routines but does not need
+ prelocking (i.e. it does not use any tables) we will access the
+ elements of LEX::sroutines set on prepared statement re-execution.
+ Because of this we have to allocate memory for both hash element
+ and copy of its key in persistent arena.
- NOTES
- Will also add element to end of 'LEX::sroutines_list' list.
+ @param lex LEX representing statement
+ @param arena Arena in which memory for new element will be
+ allocated
+ @param key Key for the hash representing set
+ @param belong_to_view Uppermost view which uses this routine
+ (0 if routine is not used by view)
- In case when statement uses stored routines but does not need
- prelocking (i.e. it does not use any tables) we will access the
- elements of LEX::sroutines set on prepared statement re-execution.
- Because of this we have to allocate memory for both hash element
- and copy of its key in persistent arena.
+ @note
+ Will also add element to end of 'LEX::sroutines_list' list.
- TODO
+ @todo
When we will got rid of these accesses on re-executions we will be
able to allocate memory for hash elements in non-persitent arena
and directly use key values from sp_head::m_sroutines sets instead
of making their copies.
- RETURN VALUE
- TRUE - new element was added.
- FALSE - element was not added (because it is already present in the set).
+ @retval
+ TRUE new element was added.
+ @retval
+ FALSE element was not added (because it is already present in
+ the set).
*/
static bool add_used_routine(LEX *lex, Query_arena *arena,
@@ -1418,7 +1494,7 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
Query_tables_list::START_SROUTINES_HASH_SIZE,
0, 0, sp_sroutine_key, 0, 0);
- if (!hash_search(&lex->sroutines, (byte *)key->str, key->length))
+ if (!hash_search(&lex->sroutines, (uchar *)key->str, key->length))
{
Sroutine_hash_entry *rn=
(Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) +
@@ -1428,8 +1504,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
rn->key.length= key->length;
rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry);
memcpy(rn->key.str, key->str, key->length + 1);
- my_hash_insert(&lex->sroutines, (byte *)rn);
- lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
+ my_hash_insert(&lex->sroutines, (uchar *)rn);
+ lex->sroutines_list.link_in_list((uchar *)rn, (uchar **)&rn->next);
rn->belong_to_view= belong_to_view;
return TRUE;
}
@@ -1437,24 +1513,22 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
}
-/*
+/**
Add routine which is explicitly used by statement to the set of stored
routines used by this statement.
- SYNOPSIS
- sp_add_used_routine()
- lex - LEX representing statement
- arena - arena in which memory for new element of the set
- will be allocated
- rt - routine name
- rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...)
+ To be friendly towards prepared statements one should pass
+ persistent arena as second argument.
+
+ @param lex LEX representing statement
+ @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/...)
- NOTES
+ @note
Will also add element to end of 'LEX::sroutines_list' list (and will
take into account that this is explicitly used routine).
-
- To be friendly towards prepared statements one should pass
- persistent arena as second argument.
*/
void sp_add_used_routine(LEX *lex, Query_arena *arena,
@@ -1467,13 +1541,11 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena,
}
-/*
+/**
Remove routines which are only indirectly used by statement from
the set of routines used by this statement.
- SYNOPSIS
- sp_remove_not_own_routines()
- lex LEX representing statement
+ @param lex LEX representing statement
*/
void sp_remove_not_own_routines(LEX *lex)
@@ -1487,7 +1559,7 @@ void sp_remove_not_own_routines(LEX *lex)
but we want to be more future-proof.
*/
next_rt= not_own_rt->next;
- hash_delete(&lex->sroutines, (byte *)not_own_rt);
+ hash_delete(&lex->sroutines, (uchar *)not_own_rt);
}
*(Sroutine_hash_entry **)lex->sroutines_list_own_last= NULL;
@@ -1496,16 +1568,14 @@ void sp_remove_not_own_routines(LEX *lex)
}
-/*
+/**
Merge contents of two hashes representing sets of routines used
by statements or by other routines.
- SYNOPSIS
- sp_update_sp_used_routines()
- dst - hash to which elements should be added
- src - hash from which elements merged
+ @param dst hash to which elements should be added
+ @param src hash from which elements merged
- NOTE
+ @note
This procedure won't create new Sroutine_hash_entry objects,
instead it will simply add elements from source to destination
hash. Thus time of life of elements in destination hash becomes
@@ -1519,24 +1589,23 @@ void sp_update_sp_used_routines(HASH *dst, HASH *src)
for (uint i=0 ; i < src->records ; i++)
{
Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
- if (!hash_search(dst, (byte *)rt->key.str, rt->key.length))
- my_hash_insert(dst, (byte *)rt);
+ if (!hash_search(dst, (uchar *)rt->key.str, rt->key.length))
+ my_hash_insert(dst, (uchar *)rt);
}
}
-/*
+/**
Add contents of hash representing set of routines to the set of
routines used by statement.
- SYNOPSIS
- sp_update_stmt_used_routines()
- thd Thread context
- lex LEX representing statement
- src Hash representing set from which routines will be added
- belong_to_view Uppermost view which uses these routines, 0 if none
+ @param thd Thread context
+ @param lex LEX representing statement
+ @param src Hash representing set from which routines will
+ be added
+ @param belong_to_view Uppermost view which uses these routines, 0 if none
- NOTE
+ @note
It will also add elements to end of 'LEX::sroutines_list' list.
*/
@@ -1552,18 +1621,17 @@ sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src,
}
-/*
+/**
Add contents of list representing set of routines to the set of
routines used by statement.
- SYNOPSIS
- sp_update_stmt_used_routines()
- thd Thread context
- lex LEX representing statement
- src List representing set from which routines will be added
- belong_to_view Uppermost view which uses these routines, 0 if none
+ @param thd Thread context
+ @param lex LEX representing statement
+ @param src List representing set from which routines will
+ be added
+ @param belong_to_view Uppermost view which uses these routines, 0 if none
- NOTE
+ @note
It will also add elements to end of 'LEX::sroutines_list' list.
*/
@@ -1576,37 +1644,36 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src,
}
-/*
+/**
Cache sub-set of routines used by statement, add tables used by these
routines to statement table list. Do the same for all routines used
by these routines.
- SYNOPSIS
- sp_cache_routines_and_add_tables_aux()
- thd - thread context
- lex - LEX representing statement
- start - first routine from the list of routines to be cached
- (this list defines mentioned sub-set).
- first_no_prelock - If true, don't add tables or cache routines used by
- the body of the first routine (i.e. *start)
- will be executed in non-prelocked mode.
- tabs_changed - Set to TRUE some tables were added, FALSE otherwise
- NOTE
+ @param thd thread context
+ @param lex LEX representing statement
+ @param start first routine from the list of routines to be cached
+ (this list defines mentioned sub-set).
+ @param first_no_prelock If true, don't add tables or cache routines used by
+ the body of the first routine (i.e. *start)
+ will be executed in non-prelocked mode.
+ @param tabs_changed Set to TRUE some tables were added, FALSE otherwise
+
+ @note
If some function is missing this won't be reported here.
Instead this fact will be discovered during query execution.
- RETURN VALUE
- 0 - success
- non-0 - failure
+ @retval
+ 0 success
+ @retval
+ non-0 failure
*/
static int
sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
Sroutine_hash_entry *start,
- bool first_no_prelock, bool *tabs_changed)
+ bool first_no_prelock)
{
int ret= 0;
- bool tabschnd= 0; /* Set if tables changed */
bool first= TRUE;
DBUG_ENTER("sp_cache_routines_and_add_tables_aux");
@@ -1646,7 +1713,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
an error with it's return value without calling my_error(), we
set the generic "mysql.proc table corrupt" error here.
*/
- if (!thd->net.report_error)
+ if (! thd->is_error())
{
/*
SP allows full NAME_LEN chars thus he have to allocate enough
@@ -1655,10 +1722,8 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
rest of the server checks agains NAME_LEN bytes and not chars.
Hence, the overrun happens only if the name is in length > 32 and
uses multibyte (cyrillic, greek, etc.)
-
- !! Change 3 with SYSTEM_CHARSET_MBMAXLEN when it's defined.
*/
- char n[NAME_LEN*3*2+2];
+ char n[NAME_LEN*2+2];
/* m_qname.str is not always \0 terminated */
memcpy(n, name.m_qname.str, name.m_qname.length);
@@ -1674,61 +1739,57 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
{
sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines,
rt->belong_to_view);
- tabschnd|=
- sp->add_used_tables_to_table_list(thd, &lex->query_tables_last,
- rt->belong_to_view);
+ (void)sp->add_used_tables_to_table_list(thd, &lex->query_tables_last,
+ rt->belong_to_view);
}
+ sp->propagate_attributes(lex);
}
first= FALSE;
}
- if (tabs_changed) /* it can be NULL */
- *tabs_changed= tabschnd;
DBUG_RETURN(ret);
}
-/*
+/**
Cache all routines from the set of used by statement, add tables used
by those routines to statement table list. Do the same for all routines
used by those routines.
- SYNOPSIS
- sp_cache_routines_and_add_tables()
- thd - thread context
- lex - LEX representing statement
- first_no_prelock - If true, don't add tables or cache routines used by
- the body of the first routine (i.e. *start)
- tabs_changed - Set to TRUE some tables were added, FALSE otherwise
-
- RETURN VALUE
- 0 - success
- non-0 - failure
+ @param thd thread context
+ @param lex LEX representing statement
+ @param first_no_prelock If true, don't add tables or cache routines used by
+ the body of the first routine (i.e. *start)
+
+ @retval
+ 0 success
+ @retval
+ non-0 failure
*/
int
-sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock,
- bool *tabs_changed)
+sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock)
{
return sp_cache_routines_and_add_tables_aux(thd, lex,
(Sroutine_hash_entry *)lex->sroutines_list.first,
- first_no_prelock, tabs_changed);
+ first_no_prelock);
}
-/*
- Add all routines used by view to the set of routines used by statement.
+/**
+ Add all routines used by view to the set of routines used by
+ statement.
+
Add tables used by those routines to statement table list. Do the same
for all routines used by these routines.
- SYNOPSIS
- sp_cache_routines_and_add_tables_for_view()
- thd Thread context
- lex LEX representing statement
- view Table list element representing view
+ @param thd Thread context
+ @param lex LEX representing statement
+ @param view Table list element representing view
- RETURN VALUE
- 0 - success
- non-0 - failure
+ @retval
+ 0 success
+ @retval
+ non-0 failure
*/
int
@@ -1738,26 +1799,24 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, TABLE_LIST *view)
(Sroutine_hash_entry **)lex->sroutines_list.next;
sp_update_stmt_used_routines(thd, lex, &view->view->sroutines_list,
view->top_table());
- return sp_cache_routines_and_add_tables_aux(thd, lex,
- *last_cached_routine_ptr, FALSE,
- NULL);
+ return sp_cache_routines_and_add_tables_aux(thd, lex,
+ *last_cached_routine_ptr, FALSE);
}
-/*
+/**
Add triggers for table to the set of routines used by statement.
Add tables used by them to statement table list. Do the same for
all implicitly used routines.
- SYNOPSIS
- sp_cache_routines_and_add_tables_for_triggers()
- thd thread context
- lex LEX respresenting statement
- table Table list element for table with trigger
+ @param thd thread context
+ @param lex LEX respresenting statement
+ @param table Table list element for table with trigger
- RETURN VALUE
- 0 - success
- non-0 - failure
+ @retval
+ 0 success
+ @retval
+ non-0 failure
*/
int
@@ -1787,6 +1846,7 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
{
trigger->add_used_tables_to_table_list(thd, &lex->query_tables_last,
table->belong_to_view);
+ trigger->propagate_attributes(lex);
sp_update_stmt_used_routines(thd, lex,
&trigger->m_sroutines,
table->belong_to_view);
@@ -1797,15 +1857,17 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
}
ret= sp_cache_routines_and_add_tables_aux(thd, lex,
*last_cached_routine_ptr,
- FALSE, NULL);
+ FALSE);
return ret;
}
-/*
- * Generates the CREATE... string from the table information.
- * Returns TRUE on success, FALSE on (alloc) failure.
- */
+/**
+ Generates the CREATE... string from the table information.
+
+ @return
+ Returns TRUE on success, FALSE on (alloc) failure.
+*/
static bool
create_string(THD *thd, String *buf,
int type,
@@ -1873,70 +1935,3 @@ create_string(THD *thd, String *buf,
buf->append(body, bodylen);
return TRUE;
}
-
-
-
-/*
- Change the current database if needed.
-
- SYNOPSIS
- sp_use_new_db()
- thd thread handle
- new_db new database name (a string and its length)
- old_db [IN] str points to a buffer where to store the old
- database, length contains the size of the buffer
- [OUT] if old db was not NULL, its name is copied
- to the buffer pointed at by str and length is updated
- accordingly. Otherwise str[0] is set to '\0' and length
- is set to 0. The out parameter should be used only if
- the database name has been changed (see dbchangedp).
- dbchangedp [OUT] is set to TRUE if the current database is changed,
- FALSE otherwise. A database is not changed if the old
- name is the same as the new one, both names are empty,
- or an error has occurred.
-
- RETURN VALUE
- 0 success
- 1 access denied or out of memory (the error message is
- set in THD)
-*/
-
-int
-sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db,
- bool no_access_check, bool *dbchangedp)
-{
- int ret;
- DBUG_ENTER("sp_use_new_db");
- DBUG_PRINT("enter", ("newdb: %s", new_db.str));
-
- /*
- A stored routine always belongs to some database. The
- old database (old_db) might be NULL, but to restore the
- old database we will use mysql_change_db.
- */
- DBUG_ASSERT(new_db.str && new_db.length);
-
- if (thd->db)
- {
- old_db->length= (uint) (strmake(old_db->str, thd->db, old_db->length - 1) -
- old_db->str);
- }
- else
- {
- old_db->str[0]= '\0';
- old_db->length= 0;
- }
-
- /* Don't change the database if the new name is the same as the old one. */
- if (my_strcasecmp(system_charset_info, old_db->str, new_db.str) == 0)
- {
- *dbchangedp= FALSE;
- DBUG_RETURN(0);
- }
-
- ret= mysql_change_db(thd, &new_db, no_access_check);
-
- *dbchangedp= ret == 0;
- DBUG_RETURN(ret);
-}
-