~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

  • Committer: Monty Taylor
  • Date: 2010-03-11 18:27:20 UTC
  • mfrom: (1333 staging)
  • mto: This revision was merged to the branch mainline in revision 1348.
  • Revision ID: mordred@inaugust.com-20100311182720-hd1h87y6cb1b1mp0
Merged trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
#include <drizzled/replication_services.h>
39
39
#include <drizzled/message/schema.pb.h>
40
40
#include "drizzled/sql_table.h"
41
 
#include "drizzled/plugin/info_schema_table.h"
 
41
#include "drizzled/plugin/storage_engine.h"
 
42
#include "drizzled/plugin/authorization.h"
42
43
#include "drizzled/global_charset_info.h"
43
44
#include "drizzled/pthread_globals.h"
44
45
#include "drizzled/charset.h"
45
46
 
46
47
#include "drizzled/internal/my_sys.h"
47
48
 
48
 
#define MY_DB_OPT_FILE "db.opt"
49
49
#define MAX_DROP_TABLE_Q_LEN      1024
50
50
 
51
51
using namespace std;
53
53
namespace drizzled
54
54
{
55
55
 
56
 
const string del_exts[]= {".dfe", ".blk", ".arz", ".BAK", ".TMD", ".opt"};
57
 
static set<string> deletable_extentions(del_exts, &del_exts[sizeof(del_exts)/sizeof(del_exts[0])]);
58
 
 
59
 
 
60
 
static long mysql_rm_known_files(Session *session, CachedDirectory &dirp,
 
56
static long mysql_rm_known_files(Session *session,
61
57
                                 const string &db, const char *path,
62
 
                                 TableList **dropped_tables);
 
58
                                 plugin::TableNameList &dropped_tables);
63
59
static void mysql_change_db_impl(Session *session, LEX_STRING *new_db_name);
64
60
 
65
 
/**
66
 
  Return default database collation.
67
 
 
68
 
  @param session     Thread context.
69
 
  @param db_name Database name.
70
 
 
71
 
  @return CHARSET_INFO object. The operation always return valid character
72
 
    set, even if the database does not exist.
73
 
*/
74
 
 
75
 
const CHARSET_INFO *get_default_db_collation(const char *db_name)
76
 
{
77
 
  message::Schema db;
78
 
 
79
 
  get_database_metadata(db_name, &db);
80
 
 
81
 
  /* If for some reason the db.opt file lacks a collation,
82
 
     we just return the default */
83
 
 
84
 
  if (db.has_collation())
85
 
  {
86
 
    const string buffer= db.collation();
87
 
    const CHARSET_INFO* cs= get_charset_by_name(buffer.c_str());
88
 
 
89
 
    if (!cs)
90
 
    {
91
 
      errmsg_printf(ERRMSG_LVL_ERROR,
92
 
                    _("Error while loading database options: '%s':"),db_name);
93
 
      errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
94
 
 
95
 
      return default_charset_info;
96
 
    }
97
 
 
98
 
    return cs;
99
 
  }
100
 
 
101
 
  return default_charset_info;
102
 
}
103
 
 
104
 
/* path is path to database, not schema file */
105
 
static int write_schema_file(const char *path, const message::Schema &db)
106
 
{
107
 
  char schema_file_tmp[FN_REFLEN];
108
 
  string schema_file(path);
109
 
 
110
 
  snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path, FN_LIBCHAR, MY_DB_OPT_FILE);
111
 
 
112
 
  schema_file.append(1, FN_LIBCHAR);
113
 
  schema_file.append(MY_DB_OPT_FILE);
114
 
 
115
 
  int fd= mkstemp(schema_file_tmp);
116
 
 
117
 
  if (fd==-1)
118
 
    return errno;
119
 
 
120
 
 
121
 
  if (!db.SerializeToFileDescriptor(fd))
122
 
  {
123
 
    close(fd);
124
 
    unlink(schema_file_tmp);
125
 
    return -1;
126
 
  }
127
 
 
128
 
  if (rename(schema_file_tmp, schema_file.c_str()) == -1)
129
 
  {
130
 
    close(fd);
131
 
    return errno;
132
 
  }
133
 
 
134
 
  close(fd);
135
 
  return 0;
136
 
}
137
 
 
138
 
int get_database_metadata(const char *dbname, message::Schema *db)
139
 
{
140
 
  char db_opt_path[FN_REFLEN];
141
 
  size_t length;
142
 
 
143
 
  /*
144
 
    Pass an empty file name, and the database options file name as extension
145
 
    to avoid table name to file name encoding.
146
 
  */
147
 
  length= build_table_filename(db_opt_path, sizeof(db_opt_path),
148
 
                              dbname, "", false);
149
 
  strcpy(db_opt_path + length, MY_DB_OPT_FILE);
150
 
 
151
 
  int fd= open(db_opt_path, O_RDONLY);
152
 
 
153
 
  if (fd == -1)
154
 
    return errno;
155
 
 
156
 
  if (!db->ParseFromFileDescriptor(fd))
157
 
  {
158
 
    close(fd);
159
 
    return -1;
160
 
  }
161
 
  close(fd);
162
 
 
163
 
  return 0;
164
 
}
165
 
 
166
61
/*
167
62
  Create a database
168
63
 
184
79
 
185
80
*/
186
81
 
187
 
bool mysql_create_db(Session *session, const char *db, message::Schema *schema_message, bool is_if_not_exists)
 
82
bool mysql_create_db(Session *session, const message::Schema &schema_message, const bool is_if_not_exists)
188
83
{
189
84
  ReplicationServices &replication_services= ReplicationServices::singleton();
190
 
  long result= 1;
191
 
  int error_erno;
192
85
  bool error= false;
193
86
 
194
 
  /* do not create 'information_schema' db */
195
 
  if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.c_str()))
196
 
  {
197
 
    my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
198
 
    return(-1);
199
 
  }
200
 
 
201
 
  schema_message->set_name(db);
202
 
 
203
87
  /*
204
88
    Do not create database if another thread is holding read lock.
205
89
    Wait for global read lock before acquiring LOCK_create_db.
214
98
  */
215
99
  if (wait_if_global_read_lock(session, 0, 1))
216
100
  {
217
 
    error= true;
218
 
    goto exit2;
 
101
    return false;
219
102
  }
220
103
 
 
104
  assert(schema_message.has_name());
 
105
  assert(schema_message.has_collation());
 
106
 
 
107
  // @todo push this lock down into the engine
221
108
  pthread_mutex_lock(&LOCK_create_db);
222
109
 
223
 
  /* check directory */
224
 
  char   path[FN_REFLEN+16];
225
 
  uint32_t path_len;
226
 
  path_len= build_table_filename(path, sizeof(path), db, "", false);
227
 
  path[path_len-1]= 0;                    // remove last '/' from path
228
 
 
229
 
  if (mkdir(path, 0777) == -1)
 
110
  // Check to see if it exists already.
 
111
  if (plugin::StorageEngine::doesSchemaExist(schema_message.name()))
230
112
  {
231
 
    if (errno == EEXIST)
232
 
    {
233
 
      if (! is_if_not_exists)
234
 
      {
235
 
        my_error(ER_DB_CREATE_EXISTS, MYF(0), path);
236
 
        error= true;
237
 
        goto exit;
238
 
      }
 
113
    if (not is_if_not_exists)
 
114
    {
 
115
      my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
 
116
      error= true;
 
117
    }
 
118
    else
 
119
    {
239
120
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
240
 
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
241
 
                          path);
 
121
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
 
122
                          schema_message.name().c_str());
242
123
      session->my_ok();
243
 
      error= false;
244
 
      goto exit;
245
 
    }
246
 
 
247
 
    my_error(ER_CANT_CREATE_DB, MYF(0), path, errno);
248
 
    error= true;
249
 
    goto exit;
250
 
  }
251
 
 
252
 
  error_erno= write_schema_file(path, *schema_message);
253
 
  if (error_erno && error_erno != EEXIST)
254
 
  {
255
 
    if (rmdir(path) >= 0)
256
 
    {
257
 
      error= true;
258
 
      goto exit;
259
 
    }
260
 
  }
261
 
  else if (error_erno)
262
 
    error= true;
263
 
 
264
 
  replication_services.rawStatement(session, session->query, session->query_length);
265
 
  session->my_ok(result);
266
 
 
267
 
exit:
 
124
    }
 
125
  }
 
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
 
268
137
  pthread_mutex_unlock(&LOCK_create_db);
269
138
  start_waiting_global_read_lock(session);
270
 
exit2:
 
139
 
271
140
  return error;
272
141
}
273
142
 
274
143
 
275
144
/* db-name is already validated when we come here */
276
145
 
277
 
bool mysql_alter_db(Session *session, const char *db, message::Schema *schema_message)
 
146
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
278
147
{
279
148
  ReplicationServices &replication_services= ReplicationServices::singleton();
280
 
  long result=1;
281
 
  int error= 0;
282
 
  char   path[FN_REFLEN+16];
283
 
  uint32_t path_len;
284
149
 
285
150
  /*
286
151
    Do not alter database if another thread is holding read lock.
294
159
    has the global read lock and refuses the operation with
295
160
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
296
161
  */
297
 
  if ((error=wait_if_global_read_lock(session,0,1)))
298
 
    goto exit;
299
 
 
300
 
  assert(schema_message);
301
 
 
302
 
  schema_message->set_name(db);
 
162
  if ((wait_if_global_read_lock(session, 0, 1)))
 
163
    return false;
303
164
 
304
165
  pthread_mutex_lock(&LOCK_create_db);
305
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
 
306
173
  /* Change options if current database is being altered. */
307
 
  path_len= build_table_filename(path, sizeof(path), db, "", false);
308
 
  path[path_len-1]= 0;                    // Remove last '/' from path
309
 
 
310
 
  error= write_schema_file(path, *schema_message);
311
 
  if (error && error != EEXIST)
312
 
  {
313
 
    /* TODO: find some witty way of getting back an error message */
314
 
    pthread_mutex_unlock(&LOCK_create_db);
315
 
    goto exit;
316
 
  }
317
 
 
318
 
  replication_services.rawStatement(session, session->getQueryString(), session->getQueryLength());
319
 
  session->my_ok(result);
 
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
  }
320
185
 
321
186
  pthread_mutex_unlock(&LOCK_create_db);
322
187
  start_waiting_global_read_lock(session);
323
 
exit:
324
 
  return error ? true : false;
 
188
 
 
189
  return success;
325
190
}
326
191
 
327
192
 
342
207
    ERROR Error
343
208
*/
344
209
 
345
 
bool mysql_rm_db(Session *session, char *db, bool if_exists)
 
210
bool mysql_rm_db(Session *session, const std::string &schema_name, const bool if_exists)
346
211
{
347
212
  long deleted=0;
348
213
  int error= false;
349
214
  char  path[FN_REFLEN+16];
350
215
  uint32_t length;
351
 
  TableList *dropped_tables= NULL;
352
 
 
353
 
  if (db && (strcmp(db, "information_schema") == 0))
354
 
  {
355
 
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
356
 
    return true;
357
 
  }
358
 
 
 
216
  plugin::TableNameList dropped_tables;
 
217
  message::Schema schema_proto;
359
218
 
360
219
  /*
361
220
    Do not drop database if another thread is holding read lock.
376
235
 
377
236
  pthread_mutex_lock(&LOCK_create_db);
378
237
 
 
238
 
379
239
  length= build_table_filename(path, sizeof(path),
380
 
                               db, "", false);
381
 
  strcpy(path+length, MY_DB_OPT_FILE);         // Append db option file name
382
 
  unlink(path);
 
240
                               schema_name.c_str(), "", false);
383
241
  path[length]= '\0';                           // Remove file name
384
242
 
385
 
  /* See if the directory exists */
386
 
  CachedDirectory dirp(path);
387
 
  if (dirp.fail())
 
243
  /* See if the schema exists */
 
244
  if (not plugin::StorageEngine::doesSchemaExist(schema_name))
388
245
  {
389
 
    if (!if_exists)
 
246
    if (if_exists)
 
247
    {
 
248
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
249
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
 
250
                          path);
 
251
    }
 
252
    else
390
253
    {
391
254
      error= -1;
392
255
      my_error(ER_DB_DROP_EXISTS, MYF(0), path);
393
256
      goto exit;
394
257
    }
395
 
    else
396
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
397
 
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
398
 
                          path);
399
258
  }
400
259
  else
401
260
  {
402
261
    pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
403
 
    remove_db_from_cache(db);
 
262
    remove_db_from_cache(schema_name);
404
263
    pthread_mutex_unlock(&LOCK_open);
405
264
 
406
265
 
407
266
    error= -1;
408
 
    deleted= mysql_rm_known_files(session, dirp, db,
409
 
                                  path, &dropped_tables);
 
267
    deleted= mysql_rm_known_files(session, schema_name,
 
268
                                  path, dropped_tables);
410
269
    if (deleted >= 0)
411
270
    {
412
 
      plugin::StorageEngine::dropDatabase(path);
413
 
      error = 0;
 
271
      error= 0;
414
272
    }
415
273
  }
416
274
  if (deleted >= 0)
417
275
  {
418
 
    const char *query;
419
 
    uint32_t query_length;
420
 
 
421
 
    assert(session->query);
422
 
 
423
 
    query= session->query;
424
 
    query_length= session->query_length;
 
276
    assert(! session->query.empty());
425
277
 
426
278
    ReplicationServices &replication_services= ReplicationServices::singleton();
427
 
    replication_services.rawStatement(session, session->getQueryString(), session->getQueryLength());
 
279
    replication_services.dropSchema(session, schema_name);
428
280
    session->clear_error();
429
281
    session->server_status|= SERVER_STATUS_DB_DROPPED;
430
282
    session->my_ok((uint32_t) deleted);
433
285
  else
434
286
  {
435
287
    char *query, *query_pos, *query_end, *query_data_start;
436
 
    TableList *tbl;
437
288
    uint32_t db_len;
438
289
 
439
290
    if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
440
291
      goto exit; /* not much else we can do */
441
292
    query_pos= query_data_start= strcpy(query,"drop table ")+11;
442
293
    query_end= query + MAX_DROP_TABLE_Q_LEN;
443
 
    db_len= strlen(db);
 
294
    db_len= schema_name.length();
444
295
 
445
296
    ReplicationServices &replication_services= ReplicationServices::singleton();
446
 
    for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
 
297
    for (plugin::TableNameList::iterator it= dropped_tables.begin();
 
298
         it != dropped_tables.end();
 
299
         it++)
447
300
    {
448
301
      uint32_t tbl_name_len;
449
302
 
450
303
      /* 3 for the quotes and the comma*/
451
 
      tbl_name_len= strlen(tbl->table_name) + 3;
 
304
      tbl_name_len= (*it).length() + 3;
452
305
      if (query_pos + tbl_name_len + 1 >= query_end)
453
306
      {
454
307
        /* These DDL methods and logging protected with LOCK_create_db */
455
 
        replication_services.rawStatement(session, query, (size_t) (query_pos -1 - query));
 
308
        replication_services.rawStatement(session, query);
456
309
        query_pos= query_data_start;
457
310
      }
458
311
 
459
312
      *query_pos++ = '`';
460
 
      query_pos= strcpy(query_pos,tbl->table_name) + (tbl_name_len-3);
 
313
      query_pos= strcpy(query_pos, (*it).c_str()) + (tbl_name_len-3);
461
314
      *query_pos++ = '`';
462
315
      *query_pos++ = ',';
463
316
    }
465
318
    if (query_pos != query_data_start)
466
319
    {
467
320
      /* These DDL methods and logging protected with LOCK_create_db */
468
 
      replication_services.rawStatement(session, query, (size_t) (query_pos -1 - query));
 
321
      replication_services.rawStatement(session, query);
469
322
    }
470
323
  }
471
324
 
476
329
    SELECT DATABASE() in the future). For this we free() session->db and set
477
330
    it to 0.
478
331
  */
479
 
  if (! session->db.empty() && session->db.compare(db) == 0)
 
332
  if (not session->db.empty() && session->db.compare(schema_name) == 0)
480
333
    mysql_change_db_impl(session, NULL);
481
334
  pthread_mutex_unlock(&LOCK_create_db);
482
335
  start_waiting_global_read_lock(session);
 
336
 
483
337
  return error;
484
338
}
485
339
 
557
411
      }
558
412
    }
559
413
 
560
 
    TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? INTERNAL_TMP_TABLE : NO_TMP_TABLE);
 
414
    TableIdentifier identifier(db, table->table_name);
561
415
 
562
 
    if ((table_type == NULL
563
 
          && (plugin::StorageEngine::getTableDefinition(*session,
564
 
                                                        identifier) != EEXIST)))
 
416
    if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
565
417
    {
566
418
      // Table was not found on disk and table can't be created from engine
567
419
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
570
422
    }
571
423
    else
572
424
    {
573
 
      error= plugin::StorageEngine::dropTable(*session,
574
 
                                              identifier,
575
 
                                              false);
 
425
      error= plugin::StorageEngine::dropTable(*session, identifier);
576
426
 
577
427
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
578
428
      {
605
455
  error= 0;
606
456
  if (wrong_tables.length())
607
457
  {
608
 
    if (!foreign_key_error)
 
458
    if (not foreign_key_error)
609
459
      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
610
460
                      wrong_tables.c_ptr());
611
461
    else
629
479
  session MUST be set when calling this function!
630
480
*/
631
481
 
632
 
static long mysql_rm_known_files(Session *session, CachedDirectory &dirp,
 
482
static long mysql_rm_known_files(Session *session,
633
483
                                 const string &db,
634
484
                                 const char *org_path,
635
 
                                 TableList **dropped_tables)
 
485
                                 plugin::TableNameList &dropped_tables)
636
486
{
637
 
 
 
487
  CachedDirectory dirp(org_path);
 
488
  if (dirp.fail())
 
489
    return 0;
638
490
 
639
491
  long deleted= 0;
640
 
  char filePath[FN_REFLEN];
641
492
  TableList *tot_list= NULL, **tot_list_next;
642
493
 
643
494
  tot_list_next= &tot_list;
644
495
 
645
 
  for (CachedDirectory::Entries::const_iterator iter= dirp.getEntries().begin();
646
 
       iter != dirp.getEntries().end() && !session->killed;
647
 
       ++iter)
 
496
  plugin::StorageEngine::getTableNames(db, dropped_tables);
 
497
 
 
498
  for (plugin::TableNameList::iterator it= dropped_tables.begin();
 
499
       it != dropped_tables.end();
 
500
       it++)
648
501
  {
649
 
    string filename((*iter)->filename);
650
 
 
651
 
    /* skiping . and .. */
652
 
    if (filename[0] == '.' && (!filename[1] ||
653
 
       (filename[1] == '.' &&  !filename[2])))
654
 
      continue;
655
 
 
656
 
    string extension("");
657
 
    size_t ext_pos= filename.rfind('.');
658
 
    if (ext_pos != string::npos)
659
 
    {
660
 
      extension= filename.substr(ext_pos);
661
 
    }
662
 
    if (deletable_extentions.find(extension) == deletable_extentions.end())
663
 
    {
664
 
      /*
665
 
        ass ass ass.
666
 
 
667
 
        strange checking for magic extensions that are then deleted if
668
 
        not reg_ext (i.e. .frm).
669
 
 
670
 
        and (previously) we'd err out on drop database if files not matching
671
 
        engine ha_known_exts() or deletable_extensions were present.
672
 
 
673
 
        presumably this was to avoid deleting other user data... except if that
674
 
        data happened to be in files ending in .BAK, .opt or .TMD. *fun*
675
 
       */
676
 
      continue;
677
 
    }
678
 
    /* just for safety we use files_charset_info */
679
 
    if (!my_strcasecmp(files_charset_info, extension.c_str(), ".dfe"))
680
 
    {
681
 
      size_t db_len= db.size();
682
 
 
683
 
      /* Drop the table nicely */
684
 
      filename.erase(ext_pos);
685
 
      TableList *table_list=(TableList*)
686
 
                             session->calloc(sizeof(*table_list) +
687
 
                                             db_len + 1 +
688
 
                                             filename.size() + 1);
689
 
 
690
 
      if (!table_list)
691
 
        return -1;
692
 
      table_list->db= (char*) (table_list+1);
693
 
      table_list->table_name= strcpy(table_list->db, db.c_str()) + db_len + 1;
694
 
      filename_to_tablename(filename.c_str(), table_list->table_name,
695
 
                            filename.size() + 1);
696
 
      table_list->alias= table_list->table_name;  // If lower_case_table_names=2
697
 
      table_list->internal_tmp_table= (strncmp(filename.c_str(),
698
 
                                               TMP_FILE_PREFIX,
699
 
                                               strlen(TMP_FILE_PREFIX)) == 0);
700
 
      /* Link into list */
701
 
      (*tot_list_next)= table_list;
702
 
      tot_list_next= &table_list->next_local;
703
 
      deleted++;
704
 
    }
705
 
    else
706
 
    {
707
 
      sprintf(filePath, "%s/%s", org_path, filename.c_str());
708
 
      if (internal::my_delete_with_symlink(filePath,MYF(MY_WME)))
709
 
      {
710
 
        return -1;
711
 
      }
712
 
    }
 
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++;
713
525
  }
714
526
  if (session->killed)
715
527
    return -1;
720
532
      return -1;
721
533
  }
722
534
 
723
 
  if (dropped_tables)
724
 
    *dropped_tables= tot_list;
725
 
 
726
 
  if (rmdir(org_path))
 
535
  if (not plugin::StorageEngine::dropSchema(db))
727
536
  {
728
 
    my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, errno);
 
537
    my_error(ER_DROP_SCHEMA, MYF(0), db.c_str());
729
538
    return -1;
730
539
  }
731
540
 
794
603
    @retval true  Error
795
604
*/
796
605
 
797
 
bool mysql_change_db(Session *session, const LEX_STRING *new_db_name, bool force_switch)
 
606
bool mysql_change_db(Session *session, const std::string &new_db_name)
798
607
{
799
 
  LEX_STRING new_db_file_name;
800
 
  const CHARSET_INFO *db_default_cl;
801
 
 
802
 
  assert(new_db_name);
803
 
  assert(new_db_name->length);
804
 
 
805
 
  if (my_strcasecmp(system_charset_info, new_db_name->str,
806
 
                    INFORMATION_SCHEMA_NAME.c_str()) == 0)
 
608
 
 
609
  assert(not new_db_name.empty());
 
610
 
 
611
  if (not plugin::Authorization::isAuthorized(session->getSecurityContext(),
 
612
                                              new_db_name))
807
613
  {
808
 
    /* Switch the current database to INFORMATION_SCHEMA. */
809
 
    /* const_cast<> is safe here: mysql_change_db_impl does a copy */
810
 
    LEX_STRING is_name= { const_cast<char *>(INFORMATION_SCHEMA_NAME.c_str()),
811
 
                          INFORMATION_SCHEMA_NAME.length() };
812
 
    mysql_change_db_impl(session, &is_name);
813
 
 
814
 
    return false;
 
614
    /* Error message is set in isAuthorized */
 
615
    return true;
815
616
  }
816
617
 
 
618
 
817
619
  /*
818
620
    Now we need to make a copy because check_db_name requires a
819
621
    non-constant argument. Actually, it takes database file name.
821
623
    TODO: fix check_db_name().
822
624
  */
823
625
 
824
 
  new_db_file_name.length= new_db_name->length;
825
 
  new_db_file_name.str= (char *)malloc(new_db_name->length + 1);
 
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);
826
629
  if (new_db_file_name.str == NULL)
827
630
    return true;                             /* the error is set */
828
 
  memcpy(new_db_file_name.str, new_db_name->str, new_db_name->length);
829
 
  new_db_file_name.str[new_db_name->length]= 0;
 
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;
830
633
 
831
634
 
832
635
  /*
843
646
    my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
844
647
    free(new_db_file_name.str);
845
648
 
846
 
    if (force_switch)
847
 
      mysql_change_db_impl(session, NULL);
848
 
 
849
649
    return true;
850
650
  }
851
651
 
852
 
  if (check_db_dir_existence(new_db_file_name.str))
 
652
  if (not plugin::StorageEngine::doesSchemaExist(new_db_file_name.str))
853
653
  {
854
 
    if (force_switch)
855
 
    {
856
 
      /* Throw a warning and free new_db_file_name. */
857
 
 
858
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
859
 
                          ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
860
 
                          new_db_file_name.str);
861
 
 
862
 
      free(new_db_file_name.str);
863
 
 
864
 
      /* Change db to NULL. */
865
 
 
866
 
      mysql_change_db_impl(session, NULL);
867
 
 
868
 
      /* The operation succeed. */
869
 
 
870
 
      return false;
871
 
    }
872
 
    else
873
 
    {
874
 
      /* Report an error and free new_db_file_name. */
875
 
 
876
 
      my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
877
 
      free(new_db_file_name.str);
878
 
 
879
 
      /* The operation failed. */
880
 
 
881
 
      return true;
882
 
    }
 
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);
 
658
 
 
659
    /* The operation failed. */
 
660
 
 
661
    return true;
883
662
  }
884
663
 
885
 
  db_default_cl= get_default_db_collation(new_db_file_name.str);
886
 
 
887
664
  mysql_change_db_impl(session, &new_db_file_name);
888
665
  free(new_db_file_name.str);
889
666
 
890
667
  return false;
891
668
}
892
669
 
893
 
/*
894
 
  Check if there is directory for the database name.
895
 
 
896
 
  SYNOPSIS
897
 
    check_db_dir_existence()
898
 
    db_name   database name
899
 
 
900
 
  RETURN VALUES
901
 
    false   There is directory for the specified database name.
902
 
    true    The directory does not exist.
903
 
*/
904
 
 
905
 
bool check_db_dir_existence(const char *db_name)
906
 
{
907
 
  char db_dir_path[FN_REFLEN];
908
 
  uint32_t db_dir_path_len;
909
 
 
910
 
  db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
911
 
                                        db_name, "", false);
912
 
 
913
 
  if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
914
 
    db_dir_path[db_dir_path_len - 1]= 0;
915
 
 
916
 
  /* Check access. */
917
 
 
918
 
  return access(db_dir_path, F_OK);
919
 
}
920
 
 
921
670
/**
922
671
  @brief Internal implementation: switch current database to a valid one.
923
672