summaryrefslogtreecommitdiff
path: root/sql/sql_db.cc
diff options
context:
space:
mode:
authorunknown <jani@ua141d10.elisa.omakaista.fi>2007-03-29 17:27:42 +0300
committerunknown <jani@ua141d10.elisa.omakaista.fi>2007-03-29 17:27:42 +0300
commit374718ff456af3c210df6b4638b2a43b89b9762a (patch)
tree94d5a320e9c08b8f33e5b1e51f794fe67b8c9cc7 /sql/sql_db.cc
parent4bcc759f71bf256f20180b5e585b726a2eb1583d (diff)
parent00aaa9a3d482f726d903489ad142b2ddccceaf8a (diff)
downloadmariadb-git-374718ff456af3c210df6b4638b2a43b89b9762a.tar.gz
Merge ua141d10.elisa.omakaista.fi:/home/my/bk/mysql-5.0-marvel
into ua141d10.elisa.omakaista.fi:/home/my/bk/mysql-5.1-marvel client/mysql.cc: Auto merged client/mysqlbinlog.cc: Auto merged BitKeeper/deleted/.del-my_lread.c: Auto merged BitKeeper/deleted/.del-my_lwrite.c: Auto merged BitKeeper/deleted/.del-raid.cc~488f5fa6538394e1: Auto merged BitKeeper/deleted/.del-raid.h~2d2503a66b128ac6: Auto merged client/mysqldump.c: Auto merged extra/perror.c: Auto merged include/my_sys.h: Auto merged libmysql/libmysql.c: Auto merged libmysqld/libmysqld.c: Auto merged mysql-test/r/mysqlbinlog2.result: Auto merged mysql-test/r/sp-security.result: Auto merged mysql-test/r/view_grant.result: Auto merged mysql-test/t/grant.test: Auto merged mysql-test/t/sp-security.test: Auto merged mysql-test/t/sp.test: Auto merged mysql-test/t/sp_trans.test: Auto merged mysql-test/t/view_grant.test: Auto merged mysys/default.c: Auto merged mysys/hash.c: Auto merged mysys/mf_iocache.c: Auto merged mysys/mf_keycache.c: Auto merged mysys/my_alloc.c: Auto merged mysys/my_dup.c: Auto merged mysys/my_getwd.c: Auto merged mysys/my_handler.c: Auto merged mysys/my_lib.c: Auto merged mysys/my_malloc.c: Auto merged mysys/my_pread.c: Auto merged mysys/my_read.c: Auto merged mysys/my_seek.c: Auto merged mysys/my_static.c: Auto merged mysys/safemalloc.c: Auto merged mysys/thr_alarm.c: Auto merged mysys/typelib.c: Auto merged sql/handler.cc: Auto merged sql/item.cc: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_func.h: Auto merged sql/item_subselect.cc: Auto merged sql/log_event.cc: Auto merged sql/net_serv.cc: Auto merged sql/opt_range.cc: Auto merged sql/slave.cc: Auto merged sql/sp.cc: Auto merged sql/sp_head.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_cache.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_delete.cc: Auto merged sql/sql_load.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_repl.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_view.cc: Auto merged sql/strfunc.cc: Auto merged sql/table.cc: Auto merged sql/tztime.cc: Auto merged sql/unireg.cc: Auto merged sql-common/client.c: Auto merged sql-common/my_time.c: Auto merged storage/archive/ha_archive.cc: Auto merged storage/heap/_check.c: Auto merged storage/heap/hp_delete.c: Auto merged storage/heap/hp_hash.c: Auto merged storage/heap/hp_open.c: Auto merged storage/heap/hp_rkey.c: Auto merged storage/heap/hp_rrnd.c: Auto merged storage/heap/hp_write.c: Auto merged storage/innobase/handler/ha_innodb.cc: Auto merged storage/myisam/mi_close.c: Auto merged storage/myisam/mi_delete.c: Auto merged storage/myisam/mi_dynrec.c: Auto merged storage/myisam/mi_keycache.c: Auto merged storage/myisam/mi_page.c: Auto merged storage/myisam/mi_statrec.c: Auto merged storage/myisam/myisamchk.c: Auto merged storage/myisammrg/myrg_extra.c: Auto merged storage/ndb/src/mgmclient/CommandInterpreter.cpp: Auto merged tests/mysql_client_test.c: Auto merged mysql-test/r/grant.result: Merged from 5.0 mysql-test/r/sp.result: Merged from 5.0 mysql-test/r/sp_trans.result: Merged from 5.0 mysql-test/t/mysqlbinlog2.test: Merged from 5.0 mysys/thr_lock.c: Merged from 5.0 sql/ha_ndbcluster.cc: Merged from 5.0 sql/log.cc: Merged from 5.0 sql/mysql_priv.h: Merged from 5.0 sql/mysqld.cc: Merged from 5.0 sql/set_var.cc: Merged from 5.0 sql/sql_db.cc: Merged from 5.0 sql/sql_insert.cc: Merged from 5.0 sql/sql_parse.cc: Merged from 5.0 sql/sql_show.cc: Merged from 5.0 sql/sql_update.cc: Merged from 5.0
Diffstat (limited to 'sql/sql_db.cc')
-rw-r--r--sql/sql_db.cc330
1 files changed, 215 insertions, 115 deletions
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 4fd35b7e6e8..4e96a987d99 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -577,7 +577,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
DBUG_ENTER("mysql_create_db");
/* do not create 'information_schema' db */
- if (!my_strcasecmp(system_charset_info, db, information_schema_name.str))
+ if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.str))
{
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
DBUG_RETURN(-1);
@@ -1256,155 +1256,253 @@ err:
}
-/*
- Change the current database.
+/**
+ @brief Internal implementation: switch current database to a valid one.
- SYNOPSIS
- mysql_change_db()
- thd thread handle
- name database name
- no_access_check if TRUE, don't do access check. In this
- case name may be ""
+ @param thd Thread context.
+ @param new_db_name Name of the database to switch to. The function will
+ take ownership of the name (the caller must not free
+ the allocated memory). If the name is NULL, we're
+ going to switch to NULL db.
+ @param new_db_access Privileges of the new database.
+ @param new_db_charset Character set of the new database.
+*/
- DESCRIPTION
- Check that the database name corresponds to a valid and
- existent database, check access rights (unless called with
- no_access_check), and set the current database. This function
- is called to change the current database upon user request
- (COM_CHANGE_DB command) or temporarily, to execute a stored
- routine.
+static void mysql_change_db_impl(THD *thd,
+ LEX_STRING *new_db_name,
+ ulong new_db_access,
+ CHARSET_INFO *new_db_charset)
+{
+ /* 1. Change current database in THD. */
- NOTES
- This function is not the only way to switch the database that
- is currently employed. When the replication slave thread
- switches the database before executing a query, it calls
- thd->set_db directly. However, if the query, in turn, uses
- a stored routine, the stored routine will use this function,
- even if it's run on the slave.
-
- This function allocates the name of the database on the system
- heap: this is necessary to be able to uniformly change the
- database from any module of the server. Up to 5.0 different
- modules were using different memory to store the name of the
- database, and this led to memory corruption: a stack pointer
- set by Stored Procedures was used by replication after the
- stack address was long gone.
-
- This function does not send anything, including error
- messages, to the client. If that should be sent to the client,
- call net_send_error after this function.
+ if (new_db_name == NULL)
+ {
+ /*
+ THD::set_db() does all the job -- it frees previous database name and
+ sets the new one.
+ */
- RETURN VALUES
- 0 OK
- 1 error
+ thd->set_db(NULL, 0);
+ }
+ else if (new_db_name == &INFORMATION_SCHEMA_NAME)
+ {
+ /*
+ Here we must use THD::set_db(), because we want to copy
+ INFORMATION_SCHEMA_NAME constant.
+ */
+
+ thd->set_db(INFORMATION_SCHEMA_NAME.str, INFORMATION_SCHEMA_NAME.length);
+ }
+ else
+ {
+ /*
+ Here we already have a copy of database name to be used in THD. So,
+ we just call THD::reset_db(). Since THD::reset_db() does not releases
+ the previous database name, we should do it explicitly.
+ */
+
+ x_free(thd->db);
+
+ thd->reset_db(new_db_name->str, new_db_name->length);
+ }
+
+ /* 2. Update security context. */
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ thd->security_ctx->db_access= new_db_access;
+#endif
+
+ /* 3. Update db-charset environment variables. */
+
+ thd->db_charset= new_db_charset;
+ thd->variables.collation_database= new_db_charset;
+}
+
+
+/**
+ @brief Change the current database.
+
+ @param thd thread handle
+ @param name database name
+ @param force_switch if this flag is set (TRUE), mysql_change_db() will
+ switch to NULL db if the specified database is not
+ available anymore. Corresponding warning will be
+ thrown in this case. This flag is used to change
+ database in stored-routine-execution code.
+
+ @details Check that the database name corresponds to a valid and existent
+ database, check access rights (unless called with no_access_check), and
+ set the current database. This function is called to change the current
+ database upon user request (COM_CHANGE_DB command) or temporarily, to
+ execute a stored routine.
+
+ This function is not the only way to switch the database that is
+ currently employed. When the replication slave thread switches the
+ database before executing a query, it calls thd->set_db directly.
+ However, if the query, in turn, uses a stored routine, the stored routine
+ will use this function, even if it's run on the slave.
+
+ This function allocates the name of the database on the system heap: this
+ is necessary to be able to uniformly change the database from any module
+ of the server. Up to 5.0 different modules were using different memory to
+ store the name of the database, and this led to memory corruption:
+ a stack pointer set by Stored Procedures was used by replication after
+ the stack address was long gone.
+
+ @return Operation status
+ @retval FALSE Success
+ @retval TRUE Error
*/
-bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
+bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
{
- LEX_STRING db_name;
- bool system_db= 0;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- ulong db_access;
+ LEX_STRING new_db_file_name;
+
Security_context *sctx= thd->security_ctx;
- LINT_INIT(db_access);
-#endif
+ ulong db_access= sctx->db_access;
+
DBUG_ENTER("mysql_change_db");
- DBUG_PRINT("enter",("name: '%s'",name));
+ DBUG_PRINT("enter",("name: '%s'", new_db_name->str));
- if (name == NULL || name[0] == '\0' && no_access_check == FALSE)
+ if (new_db_name == NULL ||
+ new_db_name->length == 0)
{
- my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
- DBUG_RETURN(1); /* purecov: inspected */
+ if (force_switch)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR));
+
+ /* Change db to NULL. */
+
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+
+ DBUG_RETURN(FALSE);
+ }
+ else
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+
+ DBUG_RETURN(TRUE);
+ }
}
- else if (name[0] == '\0')
+
+ if (my_strcasecmp(system_charset_info, new_db_name->str,
+ INFORMATION_SCHEMA_NAME.str) == 0)
{
- /* Called from SP to restore the original database, which was NULL */
- DBUG_ASSERT(no_access_check);
- system_db= 1;
- db_name.str= NULL;
- db_name.length= 0;
- goto end;
+ /* Switch database to INFORMATION_SCHEMA. */
+
+ mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL,
+ system_charset_info);
+
+ DBUG_RETURN(FALSE);
}
+
/*
Now we need to make a copy because check_db_name requires a
- non-constant argument. TODO: fix check_db_name.
+ non-constant argument. Actually, it takes database file name.
+
+ TODO: fix check_db_name().
*/
- if ((db_name.str= my_strdup(name, MYF(MY_WME))) == NULL)
- DBUG_RETURN(1); /* the error is set */
- db_name.length= strlen(db_name.str);
- if (check_db_name(&db_name))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
- my_free(db_name.str, MYF(0));
- DBUG_RETURN(1);
- }
- DBUG_PRINT("info",("Use database: %s", db_name.str));
- if (!my_strcasecmp(system_charset_info, db_name.str,
- information_schema_name.str))
+
+ new_db_file_name.str= my_strndup(new_db_name->str, new_db_name->length,
+ MYF(MY_WME));
+ new_db_file_name.length= new_db_name->length;
+
+ if (new_db_file_name.str == NULL)
+ DBUG_RETURN(TRUE); /* the error is set */
+
+ /*
+ NOTE: if check_db_name() fails, we should throw an error in any case,
+ even if we are called from sp_head::execute().
+
+ It's next to impossible however to get this error when we are called
+ from sp_head::execute(). But let's switch database to NULL in this case
+ to be sure.
+ */
+
+ if (check_db_name(new_db_file_name.str))
{
- system_db= 1;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- db_access= SELECT_ACL;
-#endif
- goto end;
+ my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+
+ if (force_switch)
+ {
+ /* Change db to NULL. */
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+ }
+ DBUG_RETURN(TRUE);
}
+ DBUG_PRINT("info",("Use database: %s", new_db_file_name.str));
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!no_access_check)
+ if (!force_switch) /* FIXME: this is BUG#27337. */
{
- if (test_all_bits(sctx->master_access, DB_ACLS))
- db_access=DB_ACLS;
- else
- db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user,
- db_name.str, 0) |
- sctx->master_access);
- if (!(db_access & DB_ACLS) && (!grant_option ||
- check_grant_db(thd, db_name.str)))
+ db_access= (test_all_bits(sctx->master_access, DB_ACLS) ?
+ DB_ACLS :
+ acl_get(sctx->host,
+ sctx->ip,
+ sctx->priv_user,
+ new_db_file_name.str,
+ FALSE) | sctx->master_access);
+
+ if (!force_switch &&
+ !(db_access & DB_ACLS) &&
+ (!grant_option || check_grant_db(thd, new_db_file_name.str)))
{
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user,
sctx->priv_host,
- db_name.str);
- general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
- sctx->priv_user, sctx->priv_host, db_name.str);
- my_free(db_name.str, MYF(0));
- DBUG_RETURN(1);
+ new_db_file_name.str);
+ mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
+ sctx->priv_user, sctx->priv_host, new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+ DBUG_RETURN(TRUE);
}
}
#endif
- if (check_db_dir_existence(db_name.str))
+ if (check_db_dir_existence(new_db_file_name.str))
{
- my_error(ER_BAD_DB_ERROR, MYF(0), db_name.str);
- my_free(db_name.str, MYF(0));
- DBUG_RETURN(1);
- }
+ if (force_switch)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
+ new_db_file_name.str);
-end:
- x_free(thd->db);
- DBUG_ASSERT(db_name.str == NULL || db_name.str[0] != '\0');
- thd->reset_db(db_name.str, db_name.length); // THD::~THD will free this
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!no_access_check)
- sctx->db_access= db_access;
-#endif
- if (system_db)
- {
- thd->db_charset= system_charset_info;
- thd->variables.collation_database= system_charset_info;
+ my_free(new_db_file_name.str, MYF(0));
+
+ /* Change db to NULL. */
+
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+
+ DBUG_RETURN(FALSE);
+ }
+ else
+ {
+ my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
}
- else
+
+ /*
+ NOTE: in mysql_change_db_impl() new_db_file_name is assigned to THD
+ attributes and will be freed in THD::~THD().
+ */
+
{
- HA_CREATE_INFO create;
+ HA_CREATE_INFO db_options;
- load_db_opt_by_name(thd, db_name.str, &create);
+ load_db_opt_by_name(thd, new_db_name->str, &db_options);
- thd->db_charset= create.default_table_charset ?
- create.default_table_charset :
- thd->variables.collation_server;
- thd->variables.collation_database= thd->db_charset;
+ mysql_change_db_impl(thd, &new_db_file_name, db_access,
+ db_options.default_table_charset ?
+ db_options.default_table_charset :
+ thd->variables.collation_server);
}
- DBUG_RETURN(0);
+
+ DBUG_RETURN(FALSE);
}
@@ -1581,8 +1679,8 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
Failed to move all tables from the old database to the new one.
In the best case mysql_rename_tables() moved all tables back to the old
database. In the worst case mysql_rename_tables() moved some tables
- to the new database, then failed, then started to move the tables back, and
- then failed again. In this situation we have some tables in the
+ to the new database, then failed, then started to move the tables back,
+ and then failed again. In this situation we have some tables in the
old database and some tables in the new database.
Let's delete the option file, and then the new database directory.
If some tables were left in the new directory, rmdir() will fail.
@@ -1718,6 +1816,8 @@ exit:
DBUG_RETURN(error);
}
+
+
/*
Check if there is directory for the database name.