~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

  • Committer: Jay Pipes
  • Date: 2010-03-09 20:02:29 UTC
  • mto: This revision was merged to the branch mainline in revision 1339.
  • Revision ID: jpipes@serialcoder-20100309200229-dfrliy4fads9vyf4
Fixes Bug #535296 by only incrementing ha_commit_count when its a normal transaction commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
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 */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
 
17
17
/* create and drop of databases */
18
 
#include <config.h>
 
18
#include "config.h"
19
19
 
20
20
#include <fcntl.h>
21
21
#include <sys/stat.h>
25
25
#include <string>
26
26
#include <fstream>
27
27
 
28
 
#include <drizzled/error.h>
 
28
#include <drizzled/message/schema.pb.h>
 
29
#include "drizzled/error.h"
29
30
#include <drizzled/gettext.h>
30
31
#include <drizzled/my_hash.h>
31
 
#include <drizzled/internal/m_string.h>
 
32
#include "drizzled/internal/m_string.h"
32
33
#include <drizzled/session.h>
33
 
#include <drizzled/schema.h>
 
34
#include <drizzled/db.h>
34
35
#include <drizzled/sql_base.h>
35
36
#include <drizzled/lock.h>
36
37
#include <drizzled/errmsg_print.h>
37
 
#include <drizzled/transaction_services.h>
 
38
#include <drizzled/replication_services.h>
38
39
#include <drizzled/message/schema.pb.h>
39
 
#include <drizzled/sql_table.h>
40
 
#include <drizzled/plugin/storage_engine.h>
41
 
#include <drizzled/plugin/authorization.h>
42
 
#include <drizzled/global_charset_info.h>
43
 
#include <drizzled/pthread_globals.h>
44
 
#include <drizzled/charset.h>
45
 
#include <drizzled/internal/my_sys.h>
 
40
#include "drizzled/sql_table.h"
 
41
#include "drizzled/plugin/storage_engine.h"
 
42
#include "drizzled/plugin/authorization.h"
 
43
#include "drizzled/global_charset_info.h"
 
44
#include "drizzled/pthread_globals.h"
 
45
#include "drizzled/charset.h"
46
46
 
47
 
#include <boost/thread/mutex.hpp>
 
47
#include "drizzled/internal/my_sys.h"
48
48
 
49
49
#define MAX_DROP_TABLE_Q_LEN      1024
50
50
 
53
53
namespace drizzled
54
54
{
55
55
 
56
 
namespace schema
57
 
{
58
 
 
59
 
static void change_db_impl(Session &session);
60
 
static void change_db_impl(Session &session, identifier::Schema &schema_identifier);
 
56
static long mysql_rm_known_files(Session *session,
 
57
                                 const string &db, const char *path,
 
58
                                 plugin::TableNameList &dropped_tables);
 
59
static void mysql_change_db_impl(Session *session, LEX_STRING *new_db_name);
61
60
 
62
61
/*
63
62
  Create a database
64
63
 
65
64
  SYNOPSIS
66
 
  create_db()
 
65
  mysql_create_db()
67
66
  session               Thread handler
68
67
  db            Name of database to create
69
68
                Function assumes that this is already validated.
80
79
 
81
80
*/
82
81
 
83
 
bool create(Session &session, const message::Schema &schema_message, const bool is_if_not_exists)
 
82
bool mysql_create_db(Session *session, const message::Schema &schema_message, const bool is_if_not_exists)
84
83
{
85
 
  TransactionServices &transaction_services= TransactionServices::singleton();
 
84
  ReplicationServices &replication_services= ReplicationServices::singleton();
86
85
  bool error= false;
87
86
 
88
87
  /*
89
88
    Do not create database if another thread is holding read lock.
90
 
    Wait for global read lock before acquiring session->catalog()->schemaLock().
 
89
    Wait for global read lock before acquiring LOCK_create_db.
91
90
    After wait_if_global_read_lock() we have protection against another
92
 
    global read lock. If we would acquire session->catalog()->schemaLock() first,
 
91
    global read lock. If we would acquire LOCK_create_db first,
93
92
    another thread could step in and get the global read lock before we
94
93
    reach wait_if_global_read_lock(). If this thread tries the same as we
95
 
    (admin a db), it would then go and wait on session->catalog()->schemaLock()...
 
94
    (admin a db), it would then go and wait on LOCK_create_db...
96
95
    Furthermore wait_if_global_read_lock() checks if the current thread
97
96
    has the global read lock and refuses the operation with
98
97
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
99
98
  */
100
 
  if (session.wait_if_global_read_lock(false, true))
 
99
  if (wait_if_global_read_lock(session, 0, 1))
101
100
  {
102
101
    return false;
103
102
  }
106
105
  assert(schema_message.has_collation());
107
106
 
108
107
  // @todo push this lock down into the engine
 
108
  pthread_mutex_lock(&LOCK_create_db);
 
109
 
 
110
  // Check to see if it exists already.
 
111
  if (plugin::StorageEngine::doesSchemaExist(schema_message.name()))
109
112
  {
110
 
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
111
 
 
112
 
    // Check to see if it exists already.  
113
 
    identifier::Schema schema_identifier(schema_message.name());
114
 
    if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
115
 
    {
116
 
      if (not is_if_not_exists)
117
 
      {
118
 
        my_error(ER_DB_CREATE_EXISTS, schema_identifier);
119
 
        error= true;
120
 
      }
121
 
      else
122
 
      {
123
 
        push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
124
 
                            ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
125
 
                            schema_message.name().c_str());
126
 
        session.my_ok();
127
 
      }
128
 
    }
129
 
    else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it 
130
 
    {
131
 
      my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
 
113
    if (not is_if_not_exists)
 
114
    {
 
115
      my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
132
116
      error= true;
133
117
    }
134
 
    else // Created !
 
118
    else
135
119
    {
136
 
      transaction_services.createSchema(session, schema_message);
137
 
      session.my_ok(1);
 
120
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
121
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
 
122
                          schema_message.name().c_str());
 
123
      session->my_ok();
138
124
    }
139
125
  }
140
 
  session.startWaitingGlobalReadLock();
 
126
  else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it 
 
127
  {
 
128
    my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
 
129
    error= true;
 
130
  }
 
131
  else // Created !
 
132
  {
 
133
    replication_services.createSchema(session, schema_message);
 
134
    session->my_ok(1);
 
135
  }
 
136
 
 
137
  pthread_mutex_unlock(&LOCK_create_db);
 
138
  start_waiting_global_read_lock(session);
141
139
 
142
140
  return error;
143
141
}
145
143
 
146
144
/* db-name is already validated when we come here */
147
145
 
148
 
bool alter(Session &session,
149
 
           const message::Schema &schema_message,
150
 
           const message::Schema &original_schema)
 
146
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
151
147
{
152
 
  TransactionServices &transaction_services= TransactionServices::singleton();
 
148
  ReplicationServices &replication_services= ReplicationServices::singleton();
153
149
 
154
150
  /*
155
151
    Do not alter database if another thread is holding read lock.
156
 
    Wait for global read lock before acquiring session->catalog()->schemaLock().
 
152
    Wait for global read lock before acquiring LOCK_create_db.
157
153
    After wait_if_global_read_lock() we have protection against another
158
 
    global read lock. If we would acquire session->catalog()->schemaLock() first,
 
154
    global read lock. If we would acquire LOCK_create_db first,
159
155
    another thread could step in and get the global read lock before we
160
156
    reach wait_if_global_read_lock(). If this thread tries the same as we
161
 
    (admin a db), it would then go and wait on session->catalog()->schemaLock()...
 
157
    (admin a db), it would then go and wait on LOCK_create_db...
162
158
    Furthermore wait_if_global_read_lock() checks if the current thread
163
159
    has the global read lock and refuses the operation with
164
160
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
165
161
  */
166
 
  if ((session.wait_if_global_read_lock(false, true)))
167
 
    return false;
168
 
 
169
 
  bool success;
170
 
  {
171
 
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
172
 
 
173
 
    identifier::Schema schema_idenifier(schema_message.name());
174
 
    if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
175
 
    {
176
 
      my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
177
 
      return false;
178
 
    }
179
 
 
180
 
    /* Change options if current database is being altered. */
181
 
    success= plugin::StorageEngine::alterSchema(schema_message);
182
 
 
183
 
    if (success)
184
 
    {
185
 
      transaction_services.alterSchema(session, original_schema, schema_message);
186
 
      session.my_ok(1);
187
 
    }
188
 
    else
189
 
    {
190
 
      my_error(ER_ALTER_SCHEMA, schema_idenifier);
191
 
    }
192
 
  }
193
 
  session.startWaitingGlobalReadLock();
 
162
  if ((wait_if_global_read_lock(session, 0, 1)))
 
163
    return false;
 
164
 
 
165
  pthread_mutex_lock(&LOCK_create_db);
 
166
 
 
167
  if (not plugin::StorageEngine::doesSchemaExist(schema_message.name()))
 
168
  {
 
169
    my_error(ER_SCHEMA_DOES_NOT_EXIST, MYF(0), schema_message.name().c_str());
 
170
    return false;
 
171
  }
 
172
 
 
173
  /* Change options if current database is being altered. */
 
174
  bool success= plugin::StorageEngine::alterSchema(schema_message);
 
175
 
 
176
  if (success)
 
177
  {
 
178
    replication_services.rawStatement(session, session->getQueryString());
 
179
    session->my_ok(1);
 
180
  }
 
181
  else
 
182
  {
 
183
    my_error(ER_ALTER_SCHEMA, MYF(0), schema_message.name().c_str());
 
184
  }
 
185
 
 
186
  pthread_mutex_unlock(&LOCK_create_db);
 
187
  start_waiting_global_read_lock(session);
194
188
 
195
189
  return success;
196
190
}
200
194
  Drop all tables in a database and the database itself
201
195
 
202
196
  SYNOPSIS
203
 
    rm_db()
 
197
    mysql_rm_db()
204
198
    session                     Thread handle
205
199
    db                  Database name in the case given by user
206
200
                        It's already validated and set to lower case
213
207
    ERROR Error
214
208
*/
215
209
 
216
 
bool drop(Session &session, identifier::Schema &schema_identifier, const bool if_exists)
 
210
bool mysql_rm_db(Session *session, const std::string &schema_name, const bool if_exists)
217
211
{
218
 
  bool error= false;
 
212
  long deleted=0;
 
213
  int error= false;
 
214
  char  path[FN_REFLEN+16];
 
215
  uint32_t length;
 
216
  plugin::TableNameList dropped_tables;
 
217
  message::Schema schema_proto;
219
218
 
220
219
  /*
221
220
    Do not drop database if another thread is holding read lock.
222
 
    Wait for global read lock before acquiring session->catalog()->schemaLock().
 
221
    Wait for global read lock before acquiring LOCK_create_db.
223
222
    After wait_if_global_read_lock() we have protection against another
224
 
    global read lock. If we would acquire session->catalog()->schemaLock() first,
 
223
    global read lock. If we would acquire LOCK_create_db first,
225
224
    another thread could step in and get the global read lock before we
226
225
    reach wait_if_global_read_lock(). If this thread tries the same as we
227
 
    (admin a db), it would then go and wait on session->catalog()->schemaLock()...
 
226
    (admin a db), it would then go and wait on LOCK_create_db...
228
227
    Furthermore wait_if_global_read_lock() checks if the current thread
229
228
    has the global read lock and refuses the operation with
230
229
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
231
230
  */
232
 
  if (session.wait_if_global_read_lock(false, true))
 
231
  if (wait_if_global_read_lock(session, 0, 1))
233
232
  {
234
 
    return true;
 
233
    return -1;
235
234
  }
236
235
 
237
 
  do
 
236
  pthread_mutex_lock(&LOCK_create_db);
 
237
 
 
238
 
 
239
  length= build_table_filename(path, sizeof(path),
 
240
                               schema_name.c_str(), "", false);
 
241
  path[length]= '\0';                           // Remove file name
 
242
 
 
243
  /* See if the schema exists */
 
244
  if (not plugin::StorageEngine::doesSchemaExist(schema_name))
238
245
  {
239
 
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
240
 
    message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier);
241
 
 
242
 
    /* See if the schema exists */
243
 
    if (not message)
 
246
    if (if_exists)
244
247
    {
245
 
      if (if_exists)
246
 
      {
247
 
        std::string path;
248
 
        schema_identifier.getSQLPath(path);
249
 
 
250
 
        push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
251
 
                            ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
252
 
                            path.c_str());
253
 
      }
254
 
      else
255
 
      {
256
 
        error= true;
257
 
        my_error(ER_DB_DROP_EXISTS, schema_identifier);
258
 
        break;
259
 
      }
 
248
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
249
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
 
250
                          path);
260
251
    }
261
252
    else
262
253
    {
263
 
      error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
264
 
    }
265
 
 
266
 
  } while (0);
267
 
 
 
254
      error= -1;
 
255
      my_error(ER_DB_DROP_EXISTS, MYF(0), path);
 
256
      goto exit;
 
257
    }
 
258
  }
 
259
  else
 
260
  {
 
261
    pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
 
262
    remove_db_from_cache(schema_name);
 
263
    pthread_mutex_unlock(&LOCK_open);
 
264
 
 
265
 
 
266
    error= -1;
 
267
    deleted= mysql_rm_known_files(session, schema_name,
 
268
                                  path, dropped_tables);
 
269
    if (deleted >= 0)
 
270
    {
 
271
      error= 0;
 
272
    }
 
273
  }
 
274
  if (deleted >= 0)
 
275
  {
 
276
    assert(! session->query.empty());
 
277
 
 
278
    ReplicationServices &replication_services= ReplicationServices::singleton();
 
279
    replication_services.dropSchema(session, schema_name);
 
280
    session->clear_error();
 
281
    session->server_status|= SERVER_STATUS_DB_DROPPED;
 
282
    session->my_ok((uint32_t) deleted);
 
283
    session->server_status&= ~SERVER_STATUS_DB_DROPPED;
 
284
  }
 
285
  else
 
286
  {
 
287
    char *query, *query_pos, *query_end, *query_data_start;
 
288
    uint32_t db_len;
 
289
 
 
290
    if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
 
291
      goto exit; /* not much else we can do */
 
292
    query_pos= query_data_start= strcpy(query,"drop table ")+11;
 
293
    query_end= query + MAX_DROP_TABLE_Q_LEN;
 
294
    db_len= schema_name.length();
 
295
 
 
296
    ReplicationServices &replication_services= ReplicationServices::singleton();
 
297
    for (plugin::TableNameList::iterator it= dropped_tables.begin();
 
298
         it != dropped_tables.end();
 
299
         it++)
 
300
    {
 
301
      uint32_t tbl_name_len;
 
302
 
 
303
      /* 3 for the quotes and the comma*/
 
304
      tbl_name_len= (*it).length() + 3;
 
305
      if (query_pos + tbl_name_len + 1 >= query_end)
 
306
      {
 
307
        /* These DDL methods and logging protected with LOCK_create_db */
 
308
        replication_services.rawStatement(session, query);
 
309
        query_pos= query_data_start;
 
310
      }
 
311
 
 
312
      *query_pos++ = '`';
 
313
      query_pos= strcpy(query_pos, (*it).c_str()) + (tbl_name_len-3);
 
314
      *query_pos++ = '`';
 
315
      *query_pos++ = ',';
 
316
    }
 
317
 
 
318
    if (query_pos != query_data_start)
 
319
    {
 
320
      /* These DDL methods and logging protected with LOCK_create_db */
 
321
      replication_services.rawStatement(session, query);
 
322
    }
 
323
  }
 
324
 
 
325
exit:
268
326
  /*
269
327
    If this database was the client's selected database, we silently
270
328
    change the client's selected database to nothing (to have an empty
271
329
    SELECT DATABASE() in the future). For this we free() session->db and set
272
330
    it to 0.
273
331
  */
274
 
  if (not error and schema_identifier.compare(*session.schema()))
275
 
    change_db_impl(session);
276
 
 
277
 
  session.startWaitingGlobalReadLock();
 
332
  if (not session->db.empty() && session->db.compare(schema_name) == 0)
 
333
    mysql_change_db_impl(session, NULL);
 
334
  pthread_mutex_unlock(&LOCK_create_db);
 
335
  start_waiting_global_read_lock(session);
278
336
 
279
337
  return error;
280
338
}
281
339
 
 
340
 
 
341
static int rm_table_part2(Session *session, TableList *tables)
 
342
{
 
343
  TableList *table;
 
344
  String wrong_tables;
 
345
  int error= 0;
 
346
  bool foreign_key_error= false;
 
347
 
 
348
  pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
 
349
 
 
350
  /*
 
351
    If we have the table in the definition cache, we don't have to check the
 
352
    .frm cursor to find if the table is a normal table (not view) and what
 
353
    engine to use.
 
354
  */
 
355
 
 
356
  for (table= tables; table; table= table->next_local)
 
357
  {
 
358
    TableShare *share;
 
359
    table->db_type= NULL;
 
360
    if ((share= TableShare::getShare(table->db, table->table_name)))
 
361
      table->db_type= share->db_type();
 
362
  }
 
363
 
 
364
  if (lock_table_names_exclusively(session, tables))
 
365
  {
 
366
    pthread_mutex_unlock(&LOCK_open);
 
367
    return 1;
 
368
  }
 
369
 
 
370
  /* Don't give warnings for not found errors, as we already generate notes */
 
371
  session->no_warnings_for_error= 1;
 
372
 
 
373
  for (table= tables; table; table= table->next_local)
 
374
  {
 
375
    char *db=table->db;
 
376
    plugin::StorageEngine *table_type;
 
377
 
 
378
    error= session->drop_temporary_table(table);
 
379
 
 
380
    switch (error) {
 
381
    case  0:
 
382
      // removed temporary table
 
383
      continue;
 
384
    case -1:
 
385
      error= 1;
 
386
      goto err_with_placeholders;
 
387
    default:
 
388
      // temporary table not found
 
389
      error= 0;
 
390
    }
 
391
 
 
392
    table_type= table->db_type;
 
393
 
 
394
    {
 
395
      Table *locked_table;
 
396
      abort_locked_tables(session, db, table->table_name);
 
397
      remove_table_from_cache(session, db, table->table_name,
 
398
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
399
                              RTFC_CHECK_KILLED_FLAG);
 
400
      /*
 
401
        If the table was used in lock tables, remember it so that
 
402
        unlock_table_names can free it
 
403
      */
 
404
      if ((locked_table= drop_locked_tables(session, db, table->table_name)))
 
405
        table->table= locked_table;
 
406
 
 
407
      if (session->killed)
 
408
      {
 
409
        error= -1;
 
410
        goto err_with_placeholders;
 
411
      }
 
412
    }
 
413
 
 
414
    TableIdentifier identifier(db, table->table_name);
 
415
 
 
416
    if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
 
417
    {
 
418
      // Table was not found on disk and table can't be created from engine
 
419
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
420
                          ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 
421
                          table->table_name);
 
422
    }
 
423
    else
 
424
    {
 
425
      error= plugin::StorageEngine::dropTable(*session, identifier);
 
426
 
 
427
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
 
428
      {
 
429
        error= 0;
 
430
        session->clear_error();
 
431
      }
 
432
 
 
433
      if (error == HA_ERR_ROW_IS_REFERENCED)
 
434
      {
 
435
        /* the table is referenced by a foreign key constraint */
 
436
        foreign_key_error= true;
 
437
      }
 
438
    }
 
439
 
 
440
    if (error == 0 || (foreign_key_error == false))
 
441
        write_bin_log_drop_table(session, true, db, table->table_name);
 
442
 
 
443
    if (error)
 
444
    {
 
445
      if (wrong_tables.length())
 
446
        wrong_tables.append(',');
 
447
      wrong_tables.append(String(table->table_name,system_charset_info));
 
448
    }
 
449
  }
 
450
  /*
 
451
    It's safe to unlock LOCK_open: we have an exclusive lock
 
452
    on the table name.
 
453
  */
 
454
  pthread_mutex_unlock(&LOCK_open);
 
455
  error= 0;
 
456
  if (wrong_tables.length())
 
457
  {
 
458
    if (not foreign_key_error)
 
459
      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
 
460
                      wrong_tables.c_ptr());
 
461
    else
 
462
    {
 
463
      my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
 
464
    }
 
465
    error= 1;
 
466
  }
 
467
 
 
468
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
 
469
err_with_placeholders:
 
470
  unlock_table_names(tables, NULL);
 
471
  pthread_mutex_unlock(&LOCK_open);
 
472
  session->no_warnings_for_error= 0;
 
473
 
 
474
  return(error);
 
475
}
 
476
 
 
477
/*
 
478
  Removes files with known extensions plus.
 
479
  session MUST be set when calling this function!
 
480
*/
 
481
 
 
482
static long mysql_rm_known_files(Session *session,
 
483
                                 const string &db,
 
484
                                 const char *org_path,
 
485
                                 plugin::TableNameList &dropped_tables)
 
486
{
 
487
  CachedDirectory dirp(org_path);
 
488
  if (dirp.fail())
 
489
    return 0;
 
490
 
 
491
  long deleted= 0;
 
492
  TableList *tot_list= NULL, **tot_list_next;
 
493
 
 
494
  tot_list_next= &tot_list;
 
495
 
 
496
  plugin::StorageEngine::getTableNames(db, dropped_tables);
 
497
 
 
498
  for (plugin::TableNameList::iterator it= dropped_tables.begin();
 
499
       it != dropped_tables.end();
 
500
       it++)
 
501
  {
 
502
    size_t db_len= db.size();
 
503
 
 
504
    /* Drop the table nicely */
 
505
    TableList *table_list=(TableList*)
 
506
      session->calloc(sizeof(*table_list) +
 
507
                      db_len + 1 +
 
508
                      (*it).length() + 1);
 
509
 
 
510
    if (not table_list)
 
511
      return -1;
 
512
 
 
513
    table_list->db= (char*) (table_list+1);
 
514
    table_list->table_name= strcpy(table_list->db, db.c_str()) + db_len + 1;
 
515
    filename_to_tablename((*it).c_str(), table_list->table_name,
 
516
                          (*it).size() + 1);
 
517
    table_list->alias= table_list->table_name;  // If lower_case_table_names=2
 
518
    table_list->internal_tmp_table= (strncmp((*it).c_str(),
 
519
                                             TMP_FILE_PREFIX,
 
520
                                             strlen(TMP_FILE_PREFIX)) == 0);
 
521
    /* Link into list */
 
522
    (*tot_list_next)= table_list;
 
523
    tot_list_next= &table_list->next_local;
 
524
    deleted++;
 
525
  }
 
526
  if (session->killed)
 
527
    return -1;
 
528
 
 
529
  if (tot_list)
 
530
  {
 
531
    if (rm_table_part2(session, tot_list))
 
532
      return -1;
 
533
  }
 
534
 
 
535
  if (not plugin::StorageEngine::dropSchema(db))
 
536
  {
 
537
    my_error(ER_DROP_SCHEMA, MYF(0), db.c_str());
 
538
    return -1;
 
539
  }
 
540
 
 
541
  return deleted;
 
542
}
 
543
 
282
544
/**
283
545
  @brief Change the current database and its attributes unconditionally.
284
546
 
341
603
    @retval true  Error
342
604
*/
343
605
 
344
 
bool change(Session &session, identifier::Schema &schema_identifier)
 
606
bool mysql_change_db(Session *session, const std::string &new_db_name)
345
607
{
346
608
 
347
 
  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
 
609
  assert(not new_db_name.empty());
 
610
 
 
611
  if (not plugin::Authorization::isAuthorized(session->getSecurityContext(),
 
612
                                              new_db_name))
348
613
  {
349
614
    /* Error message is set in isAuthorized */
350
615
    return true;
351
616
  }
352
617
 
353
 
  if (not check(session, schema_identifier))
 
618
 
 
619
  /*
 
620
    Now we need to make a copy because check_db_name requires a
 
621
    non-constant argument. Actually, it takes database file name.
 
622
 
 
623
    TODO: fix check_db_name().
 
624
  */
 
625
 
 
626
  LEX_STRING new_db_file_name;
 
627
  new_db_file_name.length= new_db_name.length();
 
628
  new_db_file_name.str= (char *)malloc(new_db_name.length() + 1);
 
629
  if (new_db_file_name.str == NULL)
 
630
    return true;                             /* the error is set */
 
631
  memcpy(new_db_file_name.str, new_db_name.c_str(), new_db_name.length());
 
632
  new_db_file_name.str[new_db_name.length()]= 0;
 
633
 
 
634
 
 
635
  /*
 
636
    NOTE: if check_db_name() fails, we should throw an error in any case,
 
637
    even if we are called from sp_head::execute().
 
638
 
 
639
    It's next to impossible however to get this error when we are called
 
640
    from sp_head::execute(). But let's switch the current database to NULL
 
641
    in this case to be sure.
 
642
  */
 
643
 
 
644
  if (check_db_name(&new_db_file_name))
354
645
  {
355
 
    my_error(ER_WRONG_DB_NAME, schema_identifier);
 
646
    my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
 
647
    free(new_db_file_name.str);
356
648
 
357
649
    return true;
358
650
  }
359
651
 
360
 
  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
 
652
  if (not plugin::StorageEngine::doesSchemaExist(new_db_file_name.str))
361
653
  {
362
 
    my_error(ER_BAD_DB_ERROR, schema_identifier);
 
654
    /* Report an error and free new_db_file_name. */
 
655
 
 
656
    my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
 
657
    free(new_db_file_name.str);
363
658
 
364
659
    /* The operation failed. */
365
660
 
366
661
    return true;
367
662
  }
368
663
 
369
 
  change_db_impl(session, schema_identifier);
 
664
  mysql_change_db_impl(session, &new_db_file_name);
 
665
  free(new_db_file_name.str);
370
666
 
371
667
  return false;
372
668
}
382
678
  @param new_db_charset Character set of the new database.
383
679
*/
384
680
 
385
 
static void change_db_impl(Session &session, identifier::Schema &schema_identifier)
 
681
static void mysql_change_db_impl(Session *session, LEX_STRING *new_db_name)
386
682
{
387
683
  /* 1. Change current database in Session. */
388
684
 
389
 
#if 0
390
685
  if (new_db_name == NULL)
391
686
  {
392
687
    /*
397
692
    session->set_db(NULL, 0);
398
693
  }
399
694
  else
400
 
#endif
401
695
  {
402
696
    /*
403
697
      Here we already have a copy of database name to be used in Session. So,
405
699
      the previous database name, we should do it explicitly.
406
700
    */
407
701
 
408
 
    session.set_db(schema_identifier.getSchemaName());
409
 
  }
410
 
}
411
 
 
412
 
static void change_db_impl(Session &session)
413
 
{
414
 
  session.set_db(string());
415
 
}
416
 
 
417
 
/*
418
 
  Check if database name is valid
419
 
 
420
 
  SYNPOSIS
421
 
    check()
422
 
    org_name            Name of database and length
423
 
 
424
 
  RETURN
425
 
    false error
426
 
    true ok
427
 
*/
428
 
 
429
 
bool check(Session &session, identifier::Schema &schema_identifier)
430
 
{
431
 
  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
432
 
  {
433
 
    return false;
434
 
  }
435
 
 
436
 
  return schema_identifier.isValid();
437
 
}
438
 
 
439
 
} /* namespace schema */
 
702
    session->set_db(new_db_name->str, new_db_name->length);
 
703
  }
 
704
}
440
705
 
441
706
} /* namespace drizzled */