1
/* Copyright (C) 2000-2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17
/* create and drop of databases */
22
#include <sys/types.h>
28
#include <drizzled/error.h>
29
#include <drizzled/gettext.h>
30
#include <drizzled/internal/m_string.h>
31
#include <drizzled/session.h>
32
#include <drizzled/schema.h>
33
#include <drizzled/sql_base.h>
34
#include <drizzled/lock.h>
35
#include <drizzled/errmsg_print.h>
36
#include <drizzled/transaction_services.h>
37
#include <drizzled/message/schema.pb.h>
38
#include <drizzled/sql_table.h>
39
#include <drizzled/plugin/storage_engine.h>
40
#include <drizzled/plugin/authorization.h>
41
#include <drizzled/pthread_globals.h>
42
#include <drizzled/charset.h>
43
#include <drizzled/internal/my_sys.h>
44
#include <drizzled/catalog/instance.h>
45
#include <boost/thread/mutex.hpp>
57
session Thread handler
58
db Name of database to create
59
Function assumes that this is already validated.
60
create_info Database create options (like character set)
63
1. Report back to client that command succeeded (my_ok)
64
2. Report errors to client
65
3. Log event to binary log
73
bool create(Session &session, const message::Schema &schema_message, const bool is_if_not_exists)
78
Do not create database if another thread is holding read lock.
79
Wait for global read lock before acquiring session->catalog()->schemaLock().
80
After wait_if_global_read_lock() we have protection against another
81
global read lock. If we would acquire session->catalog()->schemaLock() first,
82
another thread could step in and get the global read lock before we
83
reach wait_if_global_read_lock(). If this thread tries the same as we
84
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
85
Furthermore wait_if_global_read_lock() checks if the current thread
86
has the global read lock and refuses the operation with
87
ER_CANT_UPDATE_WITH_READLOCK if applicable.
89
if (session.wait_if_global_read_lock(false, true))
94
assert(schema_message.has_name());
95
assert(schema_message.has_collation());
97
// @todo push this lock down into the engine
99
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
101
// Check to see if it exists already.
102
identifier::Schema schema_identifier(schema_message.name());
103
if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
105
if (not is_if_not_exists)
107
my_error(ER_DB_CREATE_EXISTS, schema_identifier);
112
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
113
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
114
schema_message.name().c_str());
118
else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
120
my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
125
TransactionServices::createSchema(session, schema_message);
129
session.startWaitingGlobalReadLock();
135
/* db-name is already validated when we come here */
137
bool alter(Session &session,
138
const message::Schema &schema_message,
139
const message::Schema &original_schema)
142
Do not alter database if another thread is holding read lock.
143
Wait for global read lock before acquiring session->catalog()->schemaLock().
144
After wait_if_global_read_lock() we have protection against another
145
global read lock. If we would acquire session->catalog()->schemaLock() first,
146
another thread could step in and get the global read lock before we
147
reach wait_if_global_read_lock(). If this thread tries the same as we
148
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
149
Furthermore wait_if_global_read_lock() checks if the current thread
150
has the global read lock and refuses the operation with
151
ER_CANT_UPDATE_WITH_READLOCK if applicable.
153
if ((session.wait_if_global_read_lock(false, true)))
158
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
160
identifier::Schema schema_idenifier(schema_message.name());
161
if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
163
my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
167
/* Change options if current database is being altered. */
168
success= plugin::StorageEngine::alterSchema(schema_message);
172
TransactionServices::alterSchema(session, original_schema, schema_message);
177
my_error(ER_ALTER_SCHEMA, schema_idenifier);
180
session.startWaitingGlobalReadLock();
187
Drop all tables in a database and the database itself
191
session Thread handle
192
db Database name in the case given by user
193
It's already validated and set to lower case
194
(if needed) when we come here
195
if_exists Don't give error if database doesn't exists
196
silent Don't generate errors
199
false ok (Database dropped)
203
bool drop(Session &session, const identifier::Schema &schema_identifier, bool if_exists)
206
Do not drop database if another thread is holding read lock.
207
Wait for global read lock before acquiring session->catalog()->schemaLock().
208
After wait_if_global_read_lock() we have protection against another
209
global read lock. If we would acquire session->catalog()->schemaLock() first,
210
another thread could step in and get the global read lock before we
211
reach wait_if_global_read_lock(). If this thread tries the same as we
212
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
213
Furthermore wait_if_global_read_lock() checks if the current thread
214
has the global read lock and refuses the operation with
215
ER_CANT_UPDATE_WITH_READLOCK if applicable.
217
if (session.wait_if_global_read_lock(false, true))
224
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
225
if (message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier))
227
error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
231
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE, ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
232
schema_identifier.getSQLPath().c_str());
237
my_error(ER_DB_DROP_EXISTS, schema_identifier);
242
If this database was the client's selected database, we silently
243
change the client's selected database to nothing (to have an empty
244
SELECT DATABASE() in the future). For this we free() session->db and set
247
if (not error and schema_identifier.compare(*session.schema()))
248
session.set_schema("");
250
session.startWaitingGlobalReadLock();
256
@brief Change the current database and its attributes unconditionally.
258
@param session thread handle
259
@param new_db_name database name
260
@param force_switch if force_switch is false, then the operation will fail if
262
- new_db_name is NULL or empty;
264
- OR new database name is invalid
265
(check_db_name() failed);
267
- OR user has no privilege on the new database;
269
- OR new database does not exist;
271
if force_switch is true, then
273
- if new_db_name is NULL or empty, the current
274
database will be NULL, @@collation_database will
275
be set to @@collation_server, the operation will
278
- if new database name is invalid
279
(check_db_name() failed), the current database
280
will be NULL, @@collation_database will be set to
281
@@collation_server, but the operation will fail;
283
- user privileges will not be checked
284
(Session::db_access however is updated);
286
TODO: is this really the intention?
287
(see sp-security.test).
289
- if new database does not exist,the current database
290
will be NULL, @@collation_database will be set to
291
@@collation_server, a warning will be thrown, the
292
operation will succeed.
294
@details The function checks that the database name corresponds to a
295
valid and existent database, checks access rights and changes the current
296
database with database attributes (@@collation_database session variable,
299
This function is not the only way to switch the database that is
300
currently employed. When the replication slave thread switches the
301
database before executing a query, it calls session->set_db directly.
302
However, if the query, in turn, uses a stored routine, the stored routine
303
will use this function, even if it's run on the slave.
305
This function allocates the name of the database on the system heap: this
306
is necessary to be able to uniformly change the database from any module
307
of the server. Up to 5.0 different modules were using different memory to
308
store the name of the database, and this led to memory corruption:
309
a stack pointer set by Stored Procedures was used by replication after
310
the stack address was long gone.
312
@return Operation status
313
@retval false Success
317
bool change(Session &session, const identifier::Schema &schema_identifier)
320
if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
322
/* Error message is set in isAuthorized */
326
if (not check(session, schema_identifier))
328
my_error(ER_WRONG_DB_NAME, schema_identifier);
333
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
335
my_error(ER_BAD_DB_ERROR, schema_identifier);
337
/* The operation failed. */
342
session.set_schema(schema_identifier.getSchemaName());
348
@brief Internal implementation: switch current database to a valid one.
350
@param session Thread context.
351
@param new_db_name Name of the database to switch to. The function will
352
take ownership of the name (the caller must not free
353
the allocated memory). If the name is NULL, we're
354
going to switch to NULL db.
355
@param new_db_charset Character set of the new database.
360
Check if database name is valid
364
org_name Name of database and length
371
bool check(Session &session, const identifier::Schema &schema_identifier)
373
if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
375
return schema_identifier.isValid();
378
} /* namespace schema */
380
} /* namespace drizzled */