~ubuntu-branches/ubuntu/trusty/drizzle/trusty

1.2.9 by Monty Taylor
Import upstream version 2011.03.11
1
/* Copyright (C) 2000-2003 MySQL AB
2
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.
6
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.
11
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 */
15
16
17
/* create and drop of databases */
18
#include <config.h>
19
20
#include <fcntl.h>
21
#include <sys/stat.h>
22
#include <sys/types.h>
23
24
#include <set>
25
#include <string>
26
#include <fstream>
27
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>
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
44
#include <drizzled/catalog/instance.h>
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
45
#include <boost/thread/mutex.hpp>
46
47
using namespace std;
48
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
49
namespace drizzled {
50
namespace schema {
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
51
52
/*
53
  Create a database
54
55
  SYNOPSIS
56
  create_db()
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)
61
62
  SIDE-EFFECTS
63
   1. Report back to client that command succeeded (my_ok)
64
   2. Report errors to client
65
   3. Log event to binary log
66
67
  RETURN VALUES
68
  false ok
69
  true  Error
70
71
*/
72
73
bool create(Session &session, const message::Schema &schema_message, const bool is_if_not_exists)
74
{
75
  bool error= false;
76
77
  /*
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.
88
  */
89
  if (session.wait_if_global_read_lock(false, true))
90
  {
91
    return false;
92
  }
93
94
  assert(schema_message.has_name());
95
  assert(schema_message.has_collation());
96
97
  // @todo push this lock down into the engine
98
  {
99
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
100
1.1.7 by Tobias Frost
Import upstream version 7.2.3
101
    // Check to see if it exists already.
102
    identifier::Schema schema_identifier(session.catalog().identifier(),
103
                                         schema_message.name());
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
104
    if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
105
    {
106
      if (not is_if_not_exists)
107
      {
108
        my_error(ER_DB_CREATE_EXISTS, schema_identifier);
109
        error= true;
110
      }
111
      else
112
      {
113
        push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
114
                            ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
115
                            schema_message.name().c_str());
116
        session.my_ok();
117
      }
118
    }
119
    else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it 
120
    {
121
      my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
122
      error= true;
123
    }
124
    else // Created !
125
    {
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
126
      TransactionServices::createSchema(session, schema_message);
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
127
      session.my_ok(1);
128
    }
129
  }
130
  session.startWaitingGlobalReadLock();
131
132
  return error;
133
}
134
135
136
/* db-name is already validated when we come here */
137
138
bool alter(Session &session,
139
           const message::Schema &schema_message,
140
           const message::Schema &original_schema)
141
{
142
  /*
143
    Do not alter database if another thread is holding read lock.
144
    Wait for global read lock before acquiring session->catalog()->schemaLock().
145
    After wait_if_global_read_lock() we have protection against another
146
    global read lock. If we would acquire session->catalog()->schemaLock() first,
147
    another thread could step in and get the global read lock before we
148
    reach wait_if_global_read_lock(). If this thread tries the same as we
149
    (admin a db), it would then go and wait on session->catalog()->schemaLock()...
150
    Furthermore wait_if_global_read_lock() checks if the current thread
151
    has the global read lock and refuses the operation with
152
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
153
  */
154
  if ((session.wait_if_global_read_lock(false, true)))
155
    return false;
156
157
  bool success;
158
  {
159
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
160
1.1.7 by Tobias Frost
Import upstream version 7.2.3
161
    identifier::Schema schema_idenifier(session.catalog().identifier(),
162
                                        schema_message.name());
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
163
    if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
164
    {
165
      my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
166
      return false;
167
    }
168
169
    /* Change options if current database is being altered. */
170
    success= plugin::StorageEngine::alterSchema(schema_message);
171
172
    if (success)
173
    {
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
174
      TransactionServices::alterSchema(session, original_schema, schema_message);
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
175
      session.my_ok(1);
176
    }
177
    else
178
    {
179
      my_error(ER_ALTER_SCHEMA, schema_idenifier);
180
    }
181
  }
182
  session.startWaitingGlobalReadLock();
183
184
  return success;
185
}
186
187
188
/*
189
  Drop all tables in a database and the database itself
190
191
  SYNOPSIS
192
    rm_db()
193
    session			Thread handle
194
    db			Database name in the case given by user
195
		        It's already validated and set to lower case
196
                        (if needed) when we come here
197
    if_exists		Don't give error if database doesn't exists
198
    silent		Don't generate errors
199
200
  RETURN
201
    false ok (Database dropped)
202
    ERROR Error
203
*/
204
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
205
bool drop(Session &session, const identifier::Schema &schema_identifier, bool if_exists)
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
206
{
207
  /*
208
    Do not drop database if another thread is holding read lock.
209
    Wait for global read lock before acquiring session->catalog()->schemaLock().
210
    After wait_if_global_read_lock() we have protection against another
211
    global read lock. If we would acquire session->catalog()->schemaLock() first,
212
    another thread could step in and get the global read lock before we
213
    reach wait_if_global_read_lock(). If this thread tries the same as we
214
    (admin a db), it would then go and wait on session->catalog()->schemaLock()...
215
    Furthermore wait_if_global_read_lock() checks if the current thread
216
    has the global read lock and refuses the operation with
217
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
218
  */
219
  if (session.wait_if_global_read_lock(false, true))
220
  {
221
    return true;
222
  }
223
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
224
  bool error= false;
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
225
  {
226
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
227
    if (message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier))
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
228
    {
229
      error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
230
    }
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
231
    else if (if_exists)
232
    {
233
      push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE, ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
234
                          schema_identifier.getSQLPath().c_str());
235
    }
236
    else
237
    {
238
      error= true;
239
      my_error(ER_DB_DROP_EXISTS, schema_identifier);
240
    }
241
  };
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
242
243
  /*
244
    If this database was the client's selected database, we silently
245
    change the client's selected database to nothing (to have an empty
246
    SELECT DATABASE() in the future). For this we free() session->db and set
247
    it to 0.
248
  */
249
  if (not error and schema_identifier.compare(*session.schema()))
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
250
    session.set_schema("");
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
251
252
  session.startWaitingGlobalReadLock();
253
254
  return error;
255
}
256
257
/**
258
  @brief Change the current database and its attributes unconditionally.
259
260
  @param session          thread handle
261
  @param new_db_name  database name
262
  @param force_switch if force_switch is false, then the operation will fail if
263
264
                        - new_db_name is NULL or empty;
265
266
                        - OR new database name is invalid
267
                          (check_db_name() failed);
268
269
                        - OR user has no privilege on the new database;
270
271
                        - OR new database does not exist;
272
273
                      if force_switch is true, then
274
275
                        - if new_db_name is NULL or empty, the current
276
                          database will be NULL, @@collation_database will
277
                          be set to @@collation_server, the operation will
278
                          succeed.
279
280
                        - if new database name is invalid
281
                          (check_db_name() failed), the current database
282
                          will be NULL, @@collation_database will be set to
283
                          @@collation_server, but the operation will fail;
284
285
                        - user privileges will not be checked
286
                          (Session::db_access however is updated);
287
288
                          TODO: is this really the intention?
289
                                (see sp-security.test).
290
291
                        - if new database does not exist,the current database
292
                          will be NULL, @@collation_database will be set to
293
                          @@collation_server, a warning will be thrown, the
294
                          operation will succeed.
295
296
  @details The function checks that the database name corresponds to a
297
  valid and existent database, checks access rights and changes the current
298
  database with database attributes (@@collation_database session variable,
299
  Session::db_access).
300
301
  This function is not the only way to switch the database that is
302
  currently employed. When the replication slave thread switches the
303
  database before executing a query, it calls session->set_db directly.
304
  However, if the query, in turn, uses a stored routine, the stored routine
305
  will use this function, even if it's run on the slave.
306
307
  This function allocates the name of the database on the system heap: this
308
  is necessary to be able to uniformly change the database from any module
309
  of the server. Up to 5.0 different modules were using different memory to
310
  store the name of the database, and this led to memory corruption:
311
  a stack pointer set by Stored Procedures was used by replication after
312
  the stack address was long gone.
313
314
  @return Operation status
315
    @retval false Success
316
    @retval true  Error
317
*/
318
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
319
bool change(Session &session, const identifier::Schema &schema_identifier)
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
320
{
321
322
  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
323
  {
324
    /* Error message is set in isAuthorized */
325
    return true;
326
  }
327
328
  if (not check(session, schema_identifier))
329
  {
330
    my_error(ER_WRONG_DB_NAME, schema_identifier);
331
332
    return true;
333
  }
334
335
  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
336
  {
337
    my_error(ER_BAD_DB_ERROR, schema_identifier);
338
339
    /* The operation failed. */
340
341
    return true;
342
  }
343
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
344
  session.set_schema(schema_identifier.getSchemaName());
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
345
346
  return false;
347
}
348
349
/**
350
  @brief Internal implementation: switch current database to a valid one.
351
352
  @param session            Thread context.
353
  @param new_db_name    Name of the database to switch to. The function will
354
                        take ownership of the name (the caller must not free
355
                        the allocated memory). If the name is NULL, we're
356
                        going to switch to NULL db.
357
  @param new_db_charset Character set of the new database.
358
*/
359
360
361
/*
362
  Check if database name is valid
363
364
  SYNPOSIS
365
    check()
366
    org_name		Name of database and length
367
368
  RETURN
369
    false error
370
    true ok
371
*/
372
1.1.3 by Tobias Frost
Import upstream version 2012.01.30
373
bool check(Session &session, const identifier::Schema &schema_identifier)
1.2.9 by Monty Taylor
Import upstream version 2011.03.11
374
{
375
  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
376
    return false;
377
  return schema_identifier.isValid();
378
}
379
380
} /* namespace schema */
381
382
} /* namespace drizzled */