~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

  • Committer: Jay Pipes
  • Date: 2009-02-21 16:00:06 UTC
  • mto: (907.1.1 trunk-with-temporal)
  • mto: This revision was merged to the branch mainline in revision 908.
  • Revision ID: jpipes@serialcoder-20090221160006-vnk3wt4qbcz62eru
Removes the TIME column type and related time functions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 
16
16
 
17
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>
 
18
#include <drizzled/global.h>
 
19
#include CSTDINT_H
 
20
#include CINTTYPES_H
25
21
#include <string>
26
22
#include <fstream>
27
 
 
28
 
#include <drizzled/message/schema.pb.h>
29
 
#include "drizzled/error.h"
 
23
#include <drizzled/serialize/serialize.h>
 
24
using namespace std;
 
25
#include <drizzled/server_includes.h>
 
26
#include <mysys/mysys_err.h>
 
27
#include <mysys/my_dir.h>
 
28
#include <drizzled/error.h>
30
29
#include <drizzled/gettext.h>
31
 
#include <drizzled/my_hash.h>
32
 
#include "drizzled/internal/m_string.h"
 
30
#include <mysys/hash.h>
33
31
#include <drizzled/session.h>
34
32
#include <drizzled/db.h>
35
33
#include <drizzled/sql_base.h>
36
34
#include <drizzled/lock.h>
37
35
#include <drizzled/errmsg_print.h>
38
 
#include <drizzled/transaction_services.h>
39
 
#include <drizzled/message/schema.pb.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
 
 
47
 
#include "drizzled/internal/my_sys.h"
48
 
 
 
36
#include <drizzled/replicator.h>
 
37
 
 
38
#define MY_DB_OPT_FILE "db.opt"
49
39
#define MAX_DROP_TABLE_Q_LEN      1024
50
40
 
51
 
using namespace std;
52
 
 
53
 
namespace drizzled
54
 
{
55
 
 
56
 
static long mysql_rm_known_files(Session *session,
57
 
                                 SchemaIdentifier &schema_identifier,
58
 
                                 plugin::TableNameList &dropped_tables);
59
 
static void mysql_change_db_impl(Session *session);
60
 
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier);
 
41
const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NULL};
 
42
static TYPELIB deletable_extentions=
 
43
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
 
44
 
 
45
static long mysql_rm_known_files(Session *session, MY_DIR *dirp,
 
46
                                 const char *db, const char *path,
 
47
                                 uint32_t level,
 
48
                                 TableList **dropped_tables);
 
49
 
 
50
static bool rm_dir_w_symlink(const char *org_path, bool send_error);
 
51
static void mysql_change_db_impl(Session *session,
 
52
                                 LEX_STRING *new_db_name,
 
53
                                 const CHARSET_INFO * const new_db_charset);
 
54
 
 
55
 
 
56
/* Database lock hash */
 
57
HASH lock_db_cache;
 
58
pthread_mutex_t LOCK_lock_db;
 
59
bool dbcache_init= false;
 
60
int creating_database= 0;  // how many database locks are made
 
61
 
 
62
 
 
63
/* Structure for database lock */
 
64
typedef struct my_dblock_st
 
65
{
 
66
  char *name;        /* Database name        */
 
67
  uint32_t name_length;  /* Database length name */
 
68
} my_dblock_t;
 
69
 
 
70
 
 
71
/*
 
72
  lock_db key.
 
73
*/
 
74
 
 
75
extern "C" unsigned char* lock_db_get_key(my_dblock_t *, size_t *, bool not_used);
 
76
 
 
77
unsigned char* lock_db_get_key(my_dblock_t *ptr, size_t *length,
 
78
                       bool )
 
79
{
 
80
  *length= ptr->name_length;
 
81
  return (unsigned char*) ptr->name;
 
82
}
 
83
 
 
84
 
 
85
/*
 
86
  Free lock_db hash element.
 
87
*/
 
88
 
 
89
extern "C" void lock_db_free_element(void *ptr);
 
90
 
 
91
void lock_db_free_element(void *ptr)
 
92
{
 
93
  free(ptr);
 
94
}
 
95
 
 
96
 
 
97
/*
 
98
  Delete a database lock entry from hash.
 
99
*/
 
100
 
 
101
void lock_db_delete(const char *name, uint32_t length)
 
102
{
 
103
  my_dblock_t *opt;
 
104
  safe_mutex_assert_owner(&LOCK_lock_db);
 
105
  if ((opt= (my_dblock_t *)hash_search(&lock_db_cache,
 
106
                                       (const unsigned char*) name, length)))
 
107
    hash_delete(&lock_db_cache, (unsigned char*) opt);
 
108
}
 
109
 
 
110
/*
 
111
  Helper function to write a query to binlog used by mysql_rm_db()
 
112
*/
 
113
 
 
114
static inline void write_to_binlog(Session *session, char *query, uint32_t query_length, char *, uint32_t)
 
115
{
 
116
  (void)replicator_statement(session, query, query_length);
 
117
}
 
118
 
 
119
/*
 
120
  Initialize database option hash and locked database hash.
 
121
 
 
122
  SYNOPSIS
 
123
    my_database_names()
 
124
 
 
125
  NOTES
 
126
    Must be called before any other database function is called.
 
127
 
 
128
  RETURN
 
129
    0   ok
 
130
    1   Fatal error
 
131
*/
 
132
 
 
133
bool my_database_names_init(void)
 
134
{
 
135
  bool error= false;
 
136
  if (!dbcache_init)
 
137
  {
 
138
    dbcache_init= true;
 
139
    error= hash_init(&lock_db_cache, lower_case_table_names ?
 
140
                     &my_charset_bin : system_charset_info,
 
141
                     32, 0, 0, (hash_get_key) lock_db_get_key,
 
142
                     lock_db_free_element,0);
 
143
 
 
144
  }
 
145
  return error;
 
146
}
 
147
 
 
148
/**
 
149
  Return default database collation.
 
150
 
 
151
  @param session     Thread context.
 
152
  @param db_name Database name.
 
153
 
 
154
  @return CHARSET_INFO object. The operation always return valid character
 
155
    set, even if the database does not exist.
 
156
*/
 
157
 
 
158
const CHARSET_INFO *get_default_db_collation(Session *session, const char *db_name)
 
159
{
 
160
  HA_CREATE_INFO db_info;
 
161
 
 
162
  if (session->db != NULL && strcmp(db_name, session->db) == 0)
 
163
    return session->db_charset;
 
164
 
 
165
  /*
 
166
    db_info.default_table_charset contains valid character set
 
167
    (collation_server).
 
168
  */
 
169
 
 
170
  load_db_opt_by_name(session, db_name, &db_info);
 
171
 
 
172
  return db_info.default_table_charset;
 
173
}
 
174
 
 
175
/* path is path to database, not schema file */
 
176
static int write_schema_file(Session *session,
 
177
                             const char *path, const char *name,
 
178
                             HA_CREATE_INFO *create)
 
179
{
 
180
  drizzle::Schema db;
 
181
  char schema_file_tmp[FN_REFLEN];
 
182
  string schema_file(path);
 
183
 
 
184
  assert(path);
 
185
  assert(name);
 
186
  assert(create);
 
187
 
 
188
  snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path, FN_LIBCHAR, MY_DB_OPT_FILE);
 
189
 
 
190
  schema_file.append(1, FN_LIBCHAR);
 
191
  schema_file.append(MY_DB_OPT_FILE);
 
192
 
 
193
  int fd= mkstemp(schema_file_tmp);
 
194
 
 
195
  if (fd==-1)
 
196
    return errno;
 
197
 
 
198
  if (!create->default_table_charset)
 
199
    create->default_table_charset= session->variables.collation_server;
 
200
 
 
201
  db.set_name(name);
 
202
  db.set_collation(create->default_table_charset->name);
 
203
 
 
204
  if (!db.SerializeToFileDescriptor(fd))
 
205
  {
 
206
    close(fd);
 
207
    unlink(schema_file_tmp);
 
208
    return -1;
 
209
  }
 
210
 
 
211
  if (rename(schema_file_tmp, schema_file.c_str()) == -1)
 
212
  {
 
213
    close(fd);
 
214
    return errno;
 
215
  }
 
216
 
 
217
  close(fd);
 
218
  return 0;
 
219
}
 
220
 
 
221
int load_db_opt(Session *session, const char *path, HA_CREATE_INFO *create)
 
222
{
 
223
  drizzle::Schema db;
 
224
  string buffer;
 
225
 
 
226
  memset(create, 0, sizeof(*create));
 
227
  create->default_table_charset= session->variables.collation_server;
 
228
 
 
229
  int fd= open(path, O_RDONLY);
 
230
 
 
231
  if (fd == -1)
 
232
    return errno;
 
233
 
 
234
  if (!db.ParseFromFileDescriptor(fd))
 
235
  {
 
236
    close(fd);
 
237
    return -1;
 
238
  }
 
239
  close(fd);
 
240
 
 
241
  buffer= db.collation();
 
242
  if (!(create->default_table_charset= get_charset_by_name(buffer.c_str())))
 
243
  {
 
244
    errmsg_printf(ERRMSG_LVL_ERROR,
 
245
                  _("Error while loading database options: '%s':"),path);
 
246
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
 
247
    create->default_table_charset= default_charset_info;
 
248
    return -1;
 
249
  }
 
250
 
 
251
  return 0;
 
252
}
 
253
 
 
254
int load_db_opt_by_name(Session *session, const char *db_name,
 
255
                        HA_CREATE_INFO *db_create_info)
 
256
{
 
257
  char db_opt_path[FN_REFLEN];
 
258
 
 
259
  /*
 
260
    Pass an empty file name, and the database options file name as extension
 
261
    to avoid table name to file name encoding.
 
262
  */
 
263
  (void) build_table_filename(db_opt_path, sizeof(db_opt_path),
 
264
                              db_name, "", MY_DB_OPT_FILE, 0);
 
265
 
 
266
  return load_db_opt(session, db_opt_path, db_create_info);
 
267
}
 
268
 
61
269
 
62
270
/*
63
271
  Create a database
68
276
  db            Name of database to create
69
277
                Function assumes that this is already validated.
70
278
  create_info   Database create options (like character set)
 
279
  silent        Used by replication when internally creating a database.
 
280
                In this case the entry should not be logged.
71
281
 
72
282
  SIDE-EFFECTS
73
283
   1. Report back to client that command succeeded (my_ok)
74
284
   2. Report errors to client
75
285
   3. Log event to binary log
 
286
   (The 'silent' flags turns off 1 and 3.)
76
287
 
77
288
  RETURN VALUES
78
289
  false ok
80
291
 
81
292
*/
82
293
 
83
 
bool mysql_create_db(Session *session, const message::Schema &schema_message, const bool is_if_not_exists)
 
294
int mysql_create_db(Session *session, char *db, HA_CREATE_INFO *create_info, bool silent)
84
295
{
85
 
  TransactionServices &transaction_services= TransactionServices::singleton();
86
 
  bool error= false;
 
296
  char   path[FN_REFLEN+16];
 
297
  char   tmp_query[FN_REFLEN+16];
 
298
  long result= 1;
 
299
  int error= 0;
 
300
  uint32_t create_options= create_info ? create_info->options : 0;
 
301
  uint32_t path_len;
 
302
 
 
303
  /* do not create 'information_schema' db */
 
304
  if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.c_str()))
 
305
  {
 
306
    my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
 
307
    return(-1);
 
308
  }
87
309
 
88
310
  /*
89
311
    Do not create database if another thread is holding read lock.
90
 
    Wait for global read lock before acquiring LOCK_create_db.
 
312
    Wait for global read lock before acquiring LOCK_drizzleclient_create_db.
91
313
    After wait_if_global_read_lock() we have protection against another
92
 
    global read lock. If we would acquire LOCK_create_db first,
 
314
    global read lock. If we would acquire LOCK_drizzleclient_create_db first,
93
315
    another thread could step in and get the global read lock before we
94
316
    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 LOCK_create_db...
 
317
    (admin a db), it would then go and wait on LOCK_drizzleclient_create_db...
96
318
    Furthermore wait_if_global_read_lock() checks if the current thread
97
319
    has the global read lock and refuses the operation with
98
320
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
99
321
  */
100
322
  if (wait_if_global_read_lock(session, 0, 1))
101
323
  {
102
 
    return false;
103
 
  }
104
 
 
105
 
  assert(schema_message.has_name());
106
 
  assert(schema_message.has_collation());
107
 
 
108
 
  // @todo push this lock down into the engine
109
 
  pthread_mutex_lock(&LOCK_create_db);
110
 
 
111
 
  // Check to see if it exists already.  
112
 
  SchemaIdentifier schema_identifier(schema_message.name());
113
 
  if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
114
 
  {
115
 
    if (not is_if_not_exists)
116
 
    {
117
 
      my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
118
 
      error= true;
 
324
    error= -1;
 
325
    goto exit2;
 
326
  }
 
327
 
 
328
  pthread_mutex_lock(&LOCK_drizzleclient_create_db);
 
329
 
 
330
  /* Check directory */
 
331
  path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
 
332
  path[path_len-1]= 0;                    // Remove last '/' from path
 
333
 
 
334
  if (mkdir(path,0777) == -1)
 
335
  {
 
336
    if (errno == EEXIST)
 
337
    {
 
338
      if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
 
339
      {
 
340
        my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
 
341
        error= -1;
 
342
        goto exit;
 
343
      }
 
344
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
345
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
 
346
      if (!silent)
 
347
        session->my_ok();
 
348
      error= 0;
 
349
      goto exit;
 
350
    }
 
351
 
 
352
    my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
 
353
    error= -1;
 
354
    goto exit;
 
355
  }
 
356
 
 
357
  error= write_schema_file(session, path, db, create_info);
 
358
  if (error && error != EEXIST)
 
359
  {
 
360
    if (rmdir(path) >= 0)
 
361
    {
 
362
      error= -1;
 
363
      goto exit;
 
364
    }
 
365
  }
 
366
 
 
367
  if (!silent)
 
368
  {
 
369
    char *query;
 
370
    uint32_t query_length;
 
371
 
 
372
    if (!session->query)                                // Only in replication
 
373
    {
 
374
      query= tmp_query;
 
375
      query_length= sprintf(tmp_query, "create database `%s`", db);
119
376
    }
120
377
    else
121
378
    {
122
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
123
 
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
124
 
                          schema_message.name().c_str());
125
 
      session->my_ok();
 
379
      query=        session->query;
 
380
      query_length= session->query_length;
126
381
    }
127
 
  }
128
 
  else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it 
129
 
  {
130
 
    my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
131
 
    error= true;
132
 
  }
133
 
  else // Created !
134
 
  {
135
 
    transaction_services.createSchema(session, schema_message);
136
 
    session->my_ok(1);
137
 
  }
138
 
 
139
 
  pthread_mutex_unlock(&LOCK_create_db);
 
382
 
 
383
    (void)replicator_statement(session, query, query_length);
 
384
    session->my_ok(result);
 
385
  }
 
386
 
 
387
exit:
 
388
  pthread_mutex_unlock(&LOCK_drizzleclient_create_db);
140
389
  start_waiting_global_read_lock(session);
141
 
 
142
 
  return error;
 
390
exit2:
 
391
  return(error);
143
392
}
144
393
 
145
394
 
146
395
/* db-name is already validated when we come here */
147
396
 
148
 
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
 
397
bool mysql_alter_db(Session *session, const char *db, HA_CREATE_INFO *create_info)
149
398
{
150
 
  TransactionServices &transaction_services= TransactionServices::singleton();
 
399
  long result=1;
 
400
  int error= 0;
 
401
  char   path[FN_REFLEN+16];
 
402
  uint32_t path_len;
151
403
 
152
404
  /*
153
405
    Do not alter database if another thread is holding read lock.
154
 
    Wait for global read lock before acquiring LOCK_create_db.
 
406
    Wait for global read lock before acquiring LOCK_drizzleclient_create_db.
155
407
    After wait_if_global_read_lock() we have protection against another
156
 
    global read lock. If we would acquire LOCK_create_db first,
 
408
    global read lock. If we would acquire LOCK_drizzleclient_create_db first,
157
409
    another thread could step in and get the global read lock before we
158
410
    reach wait_if_global_read_lock(). If this thread tries the same as we
159
 
    (admin a db), it would then go and wait on LOCK_create_db...
 
411
    (admin a db), it would then go and wait on LOCK_drizzleclient_create_db...
160
412
    Furthermore wait_if_global_read_lock() checks if the current thread
161
413
    has the global read lock and refuses the operation with
162
414
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
163
415
  */
164
 
  if ((wait_if_global_read_lock(session, 0, 1)))
165
 
    return false;
166
 
 
167
 
  pthread_mutex_lock(&LOCK_create_db);
168
 
 
169
 
  SchemaIdentifier schema_idenifier(schema_message.name());
170
 
  if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
171
 
  {
172
 
    my_error(ER_SCHEMA_DOES_NOT_EXIST, MYF(0), schema_message.name().c_str());
173
 
    return false;
174
 
  }
 
416
  if ((error=wait_if_global_read_lock(session,0,1)))
 
417
    goto exit;
 
418
 
 
419
  pthread_mutex_lock(&LOCK_drizzleclient_create_db);
175
420
 
176
421
  /* Change options if current database is being altered. */
177
 
  bool success= plugin::StorageEngine::alterSchema(schema_message);
178
 
 
179
 
  if (success)
180
 
  {
181
 
    transaction_services.rawStatement(session, session->getQueryString());
182
 
    session->my_ok(1);
183
 
  }
184
 
  else
185
 
  {
186
 
    my_error(ER_ALTER_SCHEMA, MYF(0), schema_message.name().c_str());
187
 
  }
188
 
 
189
 
  pthread_mutex_unlock(&LOCK_create_db);
 
422
  path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
 
423
  path[path_len-1]= 0;                    // Remove last '/' from path
 
424
 
 
425
  error= write_schema_file(session, path, db, create_info);
 
426
  if (error && error != EEXIST)
 
427
  {
 
428
    /* TODO: find some witty way of getting back an error message */
 
429
    pthread_mutex_unlock(&LOCK_drizzleclient_create_db);
 
430
    goto exit;
 
431
  }
 
432
 
 
433
  if (session->db && !strcmp(session->db,db))
 
434
  {
 
435
    session->db_charset= create_info->default_table_charset ?
 
436
                     create_info->default_table_charset :
 
437
                     session->variables.collation_server;
 
438
    session->variables.collation_database= session->db_charset;
 
439
  }
 
440
 
 
441
  (void)replicator_statement(session, session->query, session->query_length);
 
442
  session->my_ok(result);
 
443
 
 
444
  pthread_mutex_unlock(&LOCK_drizzleclient_create_db);
190
445
  start_waiting_global_read_lock(session);
191
 
 
192
 
  return success;
 
446
exit:
 
447
  return(error);
193
448
}
194
449
 
195
450
 
210
465
    ERROR Error
211
466
*/
212
467
 
213
 
bool mysql_rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
 
468
bool mysql_rm_db(Session *session,char *db,bool if_exists, bool silent)
214
469
{
215
470
  long deleted=0;
216
471
  int error= false;
217
 
  plugin::TableNameList dropped_tables;
218
 
  message::Schema schema_proto;
 
472
  char  path[FN_REFLEN+16];
 
473
  MY_DIR *dirp;
 
474
  uint32_t length;
 
475
  TableList* dropped_tables= 0;
 
476
 
 
477
  if (db && (strcmp(db, "information_schema") == 0))
 
478
  {
 
479
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
 
480
    return(true);
 
481
  }
219
482
 
220
483
  /*
221
484
    Do not drop database if another thread is holding read lock.
222
 
    Wait for global read lock before acquiring LOCK_create_db.
 
485
    Wait for global read lock before acquiring LOCK_drizzleclient_create_db.
223
486
    After wait_if_global_read_lock() we have protection against another
224
 
    global read lock. If we would acquire LOCK_create_db first,
 
487
    global read lock. If we would acquire LOCK_drizzleclient_create_db first,
225
488
    another thread could step in and get the global read lock before we
226
489
    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 LOCK_create_db...
 
490
    (admin a db), it would then go and wait on LOCK_drizzleclient_create_db...
228
491
    Furthermore wait_if_global_read_lock() checks if the current thread
229
492
    has the global read lock and refuses the operation with
230
493
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
231
494
  */
232
495
  if (wait_if_global_read_lock(session, 0, 1))
233
496
  {
234
 
    return -1;
235
 
  }
236
 
 
237
 
  // Lets delete the temporary tables first outside of locks.  
238
 
  set<string> set_of_names;
239
 
  session->doGetTableNames(schema_identifier, set_of_names);
240
 
 
241
 
  for (set<string>::iterator iter= set_of_names.begin(); iter != set_of_names.end(); iter++)
242
 
  {
243
 
    TableIdentifier identifier(schema_identifier, *iter, message::Table::TEMPORARY);
244
 
    Table *table= session->find_temporary_table(identifier);
245
 
    session->close_temporary_table(table);
246
 
  }
247
 
 
248
 
  pthread_mutex_lock(&LOCK_create_db);
249
 
 
250
 
 
251
 
  /* See if the schema exists */
252
 
  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
253
 
  {
254
 
    if (if_exists)
255
 
    {
256
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
257
 
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
258
 
                          schema_identifier.getSQLPath().c_str());
259
 
    }
260
 
    else
 
497
    error= -1;
 
498
    goto exit2;
 
499
  }
 
500
 
 
501
  pthread_mutex_lock(&LOCK_drizzleclient_create_db);
 
502
 
 
503
  length= build_table_filename(path, sizeof(path), db, "", "", 0);
 
504
  strcpy(path+length, MY_DB_OPT_FILE);         // Append db option file name
 
505
  unlink(path);
 
506
  path[length]= '\0';                           // Remove file name
 
507
 
 
508
  /* See if the directory exists */
 
509
  if (!(dirp= my_dir(path,MYF(MY_DONT_SORT))))
 
510
  {
 
511
    if (!if_exists)
261
512
    {
262
513
      error= -1;
263
 
      my_error(ER_DB_DROP_EXISTS, MYF(0), schema_identifier.getSQLPath().c_str());
 
514
      my_error(ER_DB_DROP_EXISTS, MYF(0), db);
264
515
      goto exit;
265
516
    }
 
517
    else
 
518
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
519
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
266
520
  }
267
521
  else
268
522
  {
269
 
    pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
270
 
    remove_db_from_cache(schema_identifier);
 
523
    pthread_mutex_lock(&LOCK_open);
 
524
    remove_db_from_cache(db);
271
525
    pthread_mutex_unlock(&LOCK_open);
272
526
 
273
527
 
274
528
    error= -1;
275
 
    deleted= mysql_rm_known_files(session, schema_identifier, dropped_tables);
276
 
    if (deleted >= 0)
 
529
    if ((deleted= mysql_rm_known_files(session, dirp, db, path, 0,
 
530
                                       &dropped_tables)) >= 0)
277
531
    {
278
 
      error= 0;
 
532
      ha_drop_database(path);
 
533
      error = 0;
279
534
    }
280
535
  }
281
 
  if (deleted >= 0)
 
536
  if (!silent && deleted>=0)
282
537
  {
283
 
    assert(! session->query.empty());
284
 
 
285
 
    TransactionServices &transaction_services= TransactionServices::singleton();
286
 
    transaction_services.dropSchema(session, schema_identifier.getSchemaName());
 
538
    const char *query;
 
539
    uint32_t query_length;
 
540
    if (!session->query)
 
541
    {
 
542
      /* The client used the old obsolete mysql_drop_db() call */
 
543
      query= path;
 
544
      query_length= sprintf(path, "drop database `%s`", db);
 
545
    }
 
546
    else
 
547
    {
 
548
      query= session->query;
 
549
      query_length= session->query_length;
 
550
    }
 
551
    (void)replicator_statement(session, session->query, session->query_length);
287
552
    session->clear_error();
288
553
    session->server_status|= SERVER_STATUS_DB_DROPPED;
289
554
    session->my_ok((uint32_t) deleted);
292
557
  else
293
558
  {
294
559
    char *query, *query_pos, *query_end, *query_data_start;
 
560
    TableList *tbl;
 
561
    uint32_t db_len;
295
562
 
296
563
    if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
297
564
      goto exit; /* not much else we can do */
298
565
    query_pos= query_data_start= strcpy(query,"drop table ")+11;
299
566
    query_end= query + MAX_DROP_TABLE_Q_LEN;
 
567
    db_len= strlen(db);
300
568
 
301
 
    TransactionServices &transaction_services= TransactionServices::singleton();
302
 
    for (plugin::TableNameList::iterator it= dropped_tables.begin();
303
 
         it != dropped_tables.end();
304
 
         it++)
 
569
    for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
305
570
    {
306
571
      uint32_t tbl_name_len;
307
572
 
308
573
      /* 3 for the quotes and the comma*/
309
 
      tbl_name_len= (*it).length() + 3;
 
574
      tbl_name_len= strlen(tbl->table_name) + 3;
310
575
      if (query_pos + tbl_name_len + 1 >= query_end)
311
576
      {
312
 
        /* These DDL methods and logging protected with LOCK_create_db */
313
 
        transaction_services.rawStatement(session, query);
 
577
        /* These DDL methods and logging protected with LOCK_drizzleclient_create_db */
 
578
        write_to_binlog(session, query, query_pos -1 - query, db, db_len);
314
579
        query_pos= query_data_start;
315
580
      }
316
581
 
317
582
      *query_pos++ = '`';
318
 
      query_pos= strcpy(query_pos, (*it).c_str()) + (tbl_name_len-3);
 
583
      query_pos= strcpy(query_pos,tbl->table_name) + (tbl_name_len-3);
319
584
      *query_pos++ = '`';
320
585
      *query_pos++ = ',';
321
586
    }
322
587
 
323
588
    if (query_pos != query_data_start)
324
589
    {
325
 
      /* These DDL methods and logging protected with LOCK_create_db */
326
 
      transaction_services.rawStatement(session, query);
 
590
      /* These DDL methods and logging protected with LOCK_drizzleclient_create_db */
 
591
      write_to_binlog(session, query, query_pos -1 - query, db, db_len);
327
592
    }
328
593
  }
329
594
 
334
599
    SELECT DATABASE() in the future). For this we free() session->db and set
335
600
    it to 0.
336
601
  */
337
 
  if (schema_identifier.compare(session->db))
338
 
    mysql_change_db_impl(session);
339
 
  pthread_mutex_unlock(&LOCK_create_db);
 
602
  if (session->db && !strcmp(session->db, db))
 
603
    mysql_change_db_impl(session, NULL, session->variables.collation_server);
 
604
  pthread_mutex_unlock(&LOCK_drizzleclient_create_db);
340
605
  start_waiting_global_read_lock(session);
341
 
 
342
 
  return error;
343
 
}
344
 
 
345
 
 
346
 
static int rm_table_part2(Session *session, TableList *tables)
347
 
{
348
 
  TableList *table;
349
 
  String wrong_tables;
350
 
  int error= 0;
351
 
  bool foreign_key_error= false;
352
 
 
353
 
  pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
354
 
 
355
 
  /*
356
 
    If we have the table in the definition cache, we don't have to check the
357
 
    .frm cursor to find if the table is a normal table (not view) and what
358
 
    engine to use.
359
 
  */
360
 
 
361
 
  for (table= tables; table; table= table->next_local)
362
 
  {
363
 
    TableIdentifier identifier(table->db, table->table_name);
364
 
    TableShare *share;
365
 
    table->db_type= NULL;
366
 
    if ((share= TableShare::getShare(identifier)))
367
 
    {
368
 
      table->db_type= share->db_type();
369
 
    }
370
 
  }
371
 
 
372
 
  if (lock_table_names_exclusively(session, tables))
373
 
  {
374
 
    pthread_mutex_unlock(&LOCK_open);
375
 
    return 1;
376
 
  }
377
 
 
378
 
  /* Don't give warnings for not found errors, as we already generate notes */
379
 
  session->no_warnings_for_error= 1;
380
 
 
381
 
  for (table= tables; table; table= table->next_local)
382
 
  {
383
 
    char *db=table->db;
384
 
    plugin::StorageEngine *table_type;
385
 
 
386
 
    error= session->drop_temporary_table(table);
387
 
 
388
 
    switch (error) {
389
 
    case  0:
390
 
      // removed temporary table
391
 
      continue;
392
 
    case -1:
393
 
      error= 1;
394
 
      goto err_with_placeholders;
395
 
    default:
396
 
      // temporary table not found
397
 
      error= 0;
398
 
    }
399
 
 
400
 
    table_type= table->db_type;
401
 
 
402
 
    {
403
 
      Table *locked_table;
404
 
      abort_locked_tables(session, db, table->table_name);
405
 
      remove_table_from_cache(session, db, table->table_name,
406
 
                              RTFC_WAIT_OTHER_THREAD_FLAG |
407
 
                              RTFC_CHECK_KILLED_FLAG);
408
 
      /*
409
 
        If the table was used in lock tables, remember it so that
410
 
        unlock_table_names can free it
411
 
      */
412
 
      if ((locked_table= drop_locked_tables(session, db, table->table_name)))
413
 
        table->table= locked_table;
414
 
 
415
 
      if (session->killed)
416
 
      {
417
 
        error= -1;
418
 
        goto err_with_placeholders;
419
 
      }
420
 
    }
421
 
 
422
 
    TableIdentifier identifier(db, table->table_name);
423
 
    identifier.getPath();
424
 
 
425
 
    if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
426
 
    {
427
 
      // Table was not found on disk and table can't be created from engine
428
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
429
 
                          ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
430
 
                          table->table_name);
431
 
    }
432
 
    else
433
 
    {
434
 
      error= plugin::StorageEngine::dropTable(*session, identifier);
435
 
 
436
 
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
437
 
      {
438
 
        error= 0;
439
 
        session->clear_error();
440
 
      }
441
 
 
442
 
      if (error == HA_ERR_ROW_IS_REFERENCED)
443
 
      {
444
 
        /* the table is referenced by a foreign key constraint */
445
 
        foreign_key_error= true;
446
 
      }
447
 
    }
448
 
 
449
 
    if (error == 0 || (foreign_key_error == false))
450
 
        write_bin_log_drop_table(session, true, db, table->table_name);
451
 
 
452
 
    if (error)
453
 
    {
454
 
      if (wrong_tables.length())
455
 
        wrong_tables.append(',');
456
 
      wrong_tables.append(String(table->table_name,system_charset_info));
457
 
    }
458
 
  }
459
 
  /*
460
 
    It's safe to unlock LOCK_open: we have an exclusive lock
461
 
    on the table name.
462
 
  */
463
 
  pthread_mutex_unlock(&LOCK_open);
464
 
  error= 0;
465
 
  if (wrong_tables.length())
466
 
  {
467
 
    if (not foreign_key_error)
468
 
      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
469
 
                      wrong_tables.c_ptr());
470
 
    else
471
 
    {
472
 
      my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
473
 
    }
474
 
    error= 1;
475
 
  }
476
 
 
477
 
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
478
 
err_with_placeholders:
479
 
  unlock_table_names(tables, NULL);
480
 
  pthread_mutex_unlock(&LOCK_open);
481
 
  session->no_warnings_for_error= 0;
482
 
 
 
606
exit2:
483
607
  return(error);
484
608
}
485
609
 
488
612
  session MUST be set when calling this function!
489
613
*/
490
614
 
491
 
static long mysql_rm_known_files(Session *session,
492
 
                                 SchemaIdentifier &schema_identifier,
493
 
                                 plugin::TableNameList &dropped_tables)
 
615
static long mysql_rm_known_files(Session *session, MY_DIR *dirp, const char *db,
 
616
                                 const char *org_path, uint32_t level,
 
617
                                 TableList **dropped_tables)
494
618
{
495
 
  long deleted= 0;
496
 
  TableList *tot_list= NULL, **tot_list_next;
 
619
  long deleted=0;
 
620
  uint32_t found_other_files=0;
 
621
  char filePath[FN_REFLEN];
 
622
  TableList *tot_list=0, **tot_list_next;
497
623
 
498
624
  tot_list_next= &tot_list;
499
625
 
500
 
  plugin::StorageEngine::getTableNames(*session, schema_identifier, dropped_tables);
501
 
 
502
 
  for (plugin::TableNameList::iterator it= dropped_tables.begin();
503
 
       it != dropped_tables.end();
504
 
       it++)
505
 
  {
506
 
    size_t db_len= schema_identifier.getSchemaName().size();
507
 
 
508
 
    /* Drop the table nicely */
509
 
    TableList *table_list=(TableList*)
510
 
      session->calloc(sizeof(*table_list) +
511
 
                      db_len + 1 +
512
 
                      (*it).length() + 1);
513
 
 
514
 
    if (not table_list)
515
 
      return -1;
516
 
 
517
 
    table_list->db= (char*) (table_list+1);
518
 
    table_list->table_name= strcpy(table_list->db, schema_identifier.getSchemaName().c_str()) + db_len + 1;
519
 
    filename_to_tablename((*it).c_str(), table_list->table_name,
520
 
                          (*it).size() + 1);
521
 
    table_list->alias= table_list->table_name;  // If lower_case_table_names=2
522
 
    table_list->internal_tmp_table= (strncmp((*it).c_str(),
523
 
                                             TMP_FILE_PREFIX,
524
 
                                             strlen(TMP_FILE_PREFIX)) == 0);
525
 
    /* Link into list */
526
 
    (*tot_list_next)= table_list;
527
 
    tot_list_next= &table_list->next_local;
528
 
    deleted++;
529
 
  }
530
 
  if (session->killed)
531
 
    return -1;
532
 
 
533
 
  if (tot_list)
534
 
  {
535
 
    if (rm_table_part2(session, tot_list))
536
 
      return -1;
537
 
  }
538
 
 
539
 
 
540
 
  if (not plugin::StorageEngine::dropSchema(schema_identifier))
541
 
  {
542
 
    my_error(ER_DROP_SCHEMA, MYF(0), schema_identifier.getSQLPath().c_str());
543
 
    return -1;
544
 
  }
545
 
 
546
 
  return deleted;
547
 
}
 
626
  for (uint32_t idx=0 ;
 
627
       idx < (uint32_t) dirp->number_off_files && !session->killed ;
 
628
       idx++)
 
629
  {
 
630
    FILEINFO *file=dirp->dir_entry+idx;
 
631
    char *extension;
 
632
 
 
633
    /* skiping . and .. */
 
634
    if (file->name[0] == '.' && (!file->name[1] ||
 
635
       (file->name[1] == '.' &&  !file->name[2])))
 
636
      continue;
 
637
 
 
638
    if (!(extension= strrchr(file->name, '.')))
 
639
      extension= strchr(file->name, '\0');
 
640
    if (find_type(extension, &deletable_extentions,1+2) <= 0)
 
641
    {
 
642
      /*
 
643
        ass ass ass.
 
644
 
 
645
        strange checking for magic extensions that are then deleted if
 
646
        not reg_ext (i.e. .frm).
 
647
 
 
648
        and (previously) we'd err out on drop database if files not matching
 
649
        engine ha_known_exts() or deletable_extensions were present.
 
650
 
 
651
        presumably this was to avoid deleting other user data... except if that
 
652
        data happened to be in files ending in .BAK, .opt or .TMD. *fun*
 
653
       */
 
654
      find_type(extension, ha_known_exts(),1+2);
 
655
      continue;
 
656
    }
 
657
    /* just for safety we use files_charset_info */
 
658
    if (db && !my_strcasecmp(files_charset_info,
 
659
                             extension, reg_ext))
 
660
    {
 
661
      uint32_t db_len= strlen(db);
 
662
 
 
663
      /* Drop the table nicely */
 
664
      *extension= 0;                    // Remove extension
 
665
      TableList *table_list=(TableList*)
 
666
                              session->calloc(sizeof(*table_list) +
 
667
                                          db_len + 1 +
 
668
                                          MYSQL50_TABLE_NAME_PREFIX_LENGTH +
 
669
                                          strlen(file->name) + 1);
 
670
 
 
671
      if (!table_list)
 
672
        goto err;
 
673
      table_list->db= (char*) (table_list+1);
 
674
      table_list->table_name= strcpy(table_list->db, db) + db_len + 1;
 
675
      filename_to_tablename(file->name, table_list->table_name,
 
676
                            MYSQL50_TABLE_NAME_PREFIX_LENGTH +
 
677
                            strlen(file->name) + 1);
 
678
      table_list->alias= table_list->table_name;        // If lower_case_table_names=2
 
679
      table_list->internal_tmp_table= is_prefix(file->name, TMP_FILE_PREFIX);
 
680
      /* Link into list */
 
681
      (*tot_list_next)= table_list;
 
682
      tot_list_next= &table_list->next_local;
 
683
      deleted++;
 
684
    }
 
685
    else
 
686
    {
 
687
      sprintf(filePath, "%s/%s", org_path, file->name);
 
688
      if (my_delete_with_symlink(filePath,MYF(MY_WME)))
 
689
      {
 
690
        goto err;
 
691
      }
 
692
    }
 
693
  }
 
694
  if (session->killed ||
 
695
      (tot_list && mysql_rm_table_part2(session, tot_list, 1, 0, 1)))
 
696
    goto err;
 
697
 
 
698
  my_dirend(dirp);
 
699
 
 
700
  if (dropped_tables)
 
701
    *dropped_tables= tot_list;
 
702
 
 
703
  /*
 
704
    If the directory is a symbolic link, remove the link first, then
 
705
    remove the directory the symbolic link pointed at
 
706
  */
 
707
  if (found_other_files)
 
708
  {
 
709
    my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, EEXIST);
 
710
    return(-1);
 
711
  }
 
712
  else
 
713
  {
 
714
    /* Don't give errors if we can't delete 'RAID' directory */
 
715
    if (rm_dir_w_symlink(org_path, level == 0))
 
716
      return(-1);
 
717
  }
 
718
 
 
719
  return(deleted);
 
720
 
 
721
err:
 
722
  my_dirend(dirp);
 
723
  return(-1);
 
724
}
 
725
 
 
726
 
 
727
/*
 
728
  Remove directory with symlink
 
729
 
 
730
  SYNOPSIS
 
731
    rm_dir_w_symlink()
 
732
    org_path    path of derictory
 
733
    send_error  send errors
 
734
  RETURN
 
735
    0 OK
 
736
    1 ERROR
 
737
*/
 
738
 
 
739
static bool rm_dir_w_symlink(const char *org_path, bool send_error)
 
740
{
 
741
  char tmp_path[FN_REFLEN], *pos;
 
742
  char *path= tmp_path;
 
743
  unpack_filename(tmp_path, org_path);
 
744
#ifdef HAVE_READLINK
 
745
  int error;
 
746
  char tmp2_path[FN_REFLEN];
 
747
 
 
748
  /* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */
 
749
  pos= strchr(path, '\0');
 
750
  if (pos > path && pos[-1] == FN_LIBCHAR)
 
751
    *--pos=0;
 
752
 
 
753
  if ((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0)
 
754
    return(1);
 
755
  if (!error)
 
756
  {
 
757
    if (my_delete(path, MYF(send_error ? MY_WME : 0)))
 
758
    {
 
759
      return(send_error);
 
760
    }
 
761
    /* Delete directory symbolic link pointed at */
 
762
    path= tmp2_path;
 
763
  }
 
764
#endif
 
765
  /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
 
766
  pos= strchr(path, '\0');
 
767
 
 
768
  if (pos > path && pos[-1] == FN_LIBCHAR)
 
769
    *--pos=0;
 
770
  if (rmdir(path) < 0 && send_error)
 
771
  {
 
772
    my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
 
773
    return(1);
 
774
  }
 
775
  return(0);
 
776
}
 
777
 
 
778
 
 
779
/**
 
780
  @brief Internal implementation: switch current database to a valid one.
 
781
 
 
782
  @param session            Thread context.
 
783
  @param new_db_name    Name of the database to switch to. The function will
 
784
                        take ownership of the name (the caller must not free
 
785
                        the allocated memory). If the name is NULL, we're
 
786
                        going to switch to NULL db.
 
787
  @param new_db_charset Character set of the new database.
 
788
*/
 
789
 
 
790
static void mysql_change_db_impl(Session *session,
 
791
                                 LEX_STRING *new_db_name,
 
792
                                 const CHARSET_INFO * const new_db_charset)
 
793
{
 
794
  /* 1. Change current database in Session. */
 
795
 
 
796
  if (new_db_name == NULL)
 
797
  {
 
798
    /*
 
799
      Session::set_db() does all the job -- it frees previous database name and
 
800
      sets the new one.
 
801
    */
 
802
 
 
803
    session->set_db(NULL, 0);
 
804
  }
 
805
  else if (my_strcasecmp(system_charset_info, new_db_name->str,
 
806
                         INFORMATION_SCHEMA_NAME.c_str()) == 0)
 
807
  {
 
808
    /*
 
809
      Here we must use Session::set_db(), because we want to copy
 
810
      INFORMATION_SCHEMA_NAME constant.
 
811
    */
 
812
 
 
813
    session->set_db(INFORMATION_SCHEMA_NAME.c_str(),
 
814
                    INFORMATION_SCHEMA_NAME.length());
 
815
  }
 
816
  else
 
817
  {
 
818
    /*
 
819
      Here we already have a copy of database name to be used in Session. So,
 
820
      we just call Session::reset_db(). Since Session::reset_db() does not releases
 
821
      the previous database name, we should do it explicitly.
 
822
    */
 
823
 
 
824
    if (session->db)
 
825
      free(session->db);
 
826
 
 
827
    session->reset_db(new_db_name->str, new_db_name->length);
 
828
  }
 
829
 
 
830
  /* 3. Update db-charset environment variables. */
 
831
 
 
832
  session->db_charset= new_db_charset;
 
833
  session->variables.collation_database= new_db_charset;
 
834
}
 
835
 
 
836
 
 
837
 
 
838
/**
 
839
  Backup the current database name before switch.
 
840
 
 
841
  @param[in]      session             thread handle
 
842
  @param[in, out] saved_db_name   IN: "str" points to a buffer where to store
 
843
                                  the old database name, "length" contains the
 
844
                                  buffer size
 
845
                                  OUT: if the current (default) database is
 
846
                                  not NULL, its name is copied to the
 
847
                                  buffer pointed at by "str"
 
848
                                  and "length" is updated accordingly.
 
849
                                  Otherwise "str" is set to NULL and
 
850
                                  "length" is set to 0.
 
851
*/
 
852
 
 
853
static void backup_current_db_name(Session *session,
 
854
                                   LEX_STRING *saved_db_name)
 
855
{
 
856
  if (!session->db)
 
857
  {
 
858
    /* No current (default) database selected. */
 
859
 
 
860
    saved_db_name->str= NULL;
 
861
    saved_db_name->length= 0;
 
862
  }
 
863
  else
 
864
  {
 
865
    strncpy(saved_db_name->str, session->db, saved_db_name->length - 1);
 
866
    saved_db_name->length= session->db_length;
 
867
  }
 
868
}
 
869
 
 
870
 
 
871
/**
 
872
  Return true if db1_name is equal to db2_name, false otherwise.
 
873
 
 
874
  The function allows to compare database names according to the MySQL
 
875
  rules. The database names db1 and db2 are equal if:
 
876
     - db1 is NULL and db2 is NULL;
 
877
     or
 
878
     - db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
 
879
       db2 in system character set (UTF8).
 
880
*/
 
881
 
 
882
static inline bool
 
883
cmp_db_names(const char *db1_name,
 
884
             const char *db2_name)
 
885
{
 
886
  return
 
887
         /* db1 is NULL and db2 is NULL */
 
888
         (!db1_name && !db2_name) ||
 
889
 
 
890
         /* db1 is not-NULL, db2 is not-NULL, db1 == db2. */
 
891
         (db1_name && db2_name && my_strcasecmp(system_charset_info, db1_name, db2_name) == 0);
 
892
}
 
893
 
548
894
 
549
895
/**
550
896
  @brief Change the current database and its attributes unconditionally.
608
954
    @retval true  Error
609
955
*/
610
956
 
611
 
bool mysql_change_db(Session *session, SchemaIdentifier &schema_identifier)
 
957
bool mysql_change_db(Session *session, const LEX_STRING *new_db_name, bool force_switch)
612
958
{
613
 
 
614
 
  if (not plugin::Authorization::isAuthorized(session->getSecurityContext(), schema_identifier))
615
 
  {
616
 
    /* Error message is set in isAuthorized */
617
 
    return true;
618
 
  }
619
 
 
620
 
  if (not check_db_name(schema_identifier))
621
 
  {
622
 
    my_error(ER_WRONG_DB_NAME, MYF(0), schema_identifier.getSQLPath().c_str());
623
 
 
624
 
    return true;
625
 
  }
626
 
 
627
 
  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
628
 
  {
629
 
    /* Report an error and free new_db_file_name. */
630
 
 
631
 
    my_error(ER_BAD_DB_ERROR, MYF(0), schema_identifier.getSQLPath().c_str());
632
 
 
633
 
    /* The operation failed. */
634
 
 
635
 
    return true;
636
 
  }
637
 
 
638
 
  mysql_change_db_impl(session, schema_identifier);
639
 
 
640
 
  return false;
 
959
  LEX_STRING new_db_file_name;
 
960
  const CHARSET_INFO *db_default_cl;
 
961
 
 
962
  if (new_db_name == NULL ||
 
963
      new_db_name->length == 0)
 
964
  {
 
965
    if (force_switch)
 
966
    {
 
967
      /*
 
968
        This can happen only if we're switching the current database back
 
969
        after loading stored program. The thing is that loading of stored
 
970
        program can happen when there is no current database.
 
971
 
 
972
        TODO: actually, new_db_name and new_db_name->str seem to be always
 
973
        non-NULL. In case of stored program, new_db_name->str == "" and
 
974
        new_db_name->length == 0.
 
975
      */
 
976
 
 
977
      mysql_change_db_impl(session, NULL, session->variables.collation_server);
 
978
 
 
979
      return(false);
 
980
    }
 
981
    else
 
982
    {
 
983
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
 
984
 
 
985
      return(true);
 
986
    }
 
987
  }
 
988
 
 
989
  if (my_strcasecmp(system_charset_info, new_db_name->str,
 
990
                    INFORMATION_SCHEMA_NAME.c_str()) == 0)
 
991
  {
 
992
    /* Switch the current database to INFORMATION_SCHEMA. */
 
993
    /* const_cast<> is safe here: mysql_change_db_impl does a copy */
 
994
    LEX_STRING is_name= { const_cast<char *>(INFORMATION_SCHEMA_NAME.c_str()),
 
995
                          INFORMATION_SCHEMA_NAME.length() };
 
996
    mysql_change_db_impl(session, &is_name, system_charset_info);
 
997
 
 
998
    return(false);
 
999
  }
 
1000
 
 
1001
  /*
 
1002
    Now we need to make a copy because check_db_name requires a
 
1003
    non-constant argument. Actually, it takes database file name.
 
1004
 
 
1005
    TODO: fix check_db_name().
 
1006
  */
 
1007
 
 
1008
  new_db_file_name.length= new_db_name->length;
 
1009
  new_db_file_name.str= (char *)malloc(new_db_name->length + 1);
 
1010
  if (new_db_file_name.str == NULL)
 
1011
    return(true);                             /* the error is set */
 
1012
  memcpy(new_db_file_name.str, new_db_name->str, new_db_name->length);
 
1013
  new_db_file_name.str[new_db_name->length]= 0;
 
1014
 
 
1015
 
 
1016
  /*
 
1017
    NOTE: if check_db_name() fails, we should throw an error in any case,
 
1018
    even if we are called from sp_head::execute().
 
1019
 
 
1020
    It's next to impossible however to get this error when we are called
 
1021
    from sp_head::execute(). But let's switch the current database to NULL
 
1022
    in this case to be sure.
 
1023
  */
 
1024
 
 
1025
  if (check_db_name(&new_db_file_name))
 
1026
  {
 
1027
    my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
 
1028
    free(new_db_file_name.str);
 
1029
 
 
1030
    if (force_switch)
 
1031
      mysql_change_db_impl(session, NULL, session->variables.collation_server);
 
1032
 
 
1033
    return(true);
 
1034
  }
 
1035
 
 
1036
  if (check_db_dir_existence(new_db_file_name.str))
 
1037
  {
 
1038
    if (force_switch)
 
1039
    {
 
1040
      /* Throw a warning and free new_db_file_name. */
 
1041
 
 
1042
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
1043
                          ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
 
1044
                          new_db_file_name.str);
 
1045
 
 
1046
      free(new_db_file_name.str);
 
1047
 
 
1048
      /* Change db to NULL. */
 
1049
 
 
1050
      mysql_change_db_impl(session, NULL, session->variables.collation_server);
 
1051
 
 
1052
      /* The operation succeed. */
 
1053
 
 
1054
      return(false);
 
1055
    }
 
1056
    else
 
1057
    {
 
1058
      /* Report an error and free new_db_file_name. */
 
1059
 
 
1060
      my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
 
1061
      free(new_db_file_name.str);
 
1062
 
 
1063
      /* The operation failed. */
 
1064
 
 
1065
      return(true);
 
1066
    }
 
1067
  }
 
1068
 
 
1069
  /*
 
1070
    NOTE: in mysql_change_db_impl() new_db_file_name is assigned to Session
 
1071
    attributes and will be freed in Session::~Session().
 
1072
  */
 
1073
 
 
1074
  db_default_cl= get_default_db_collation(session, new_db_file_name.str);
 
1075
 
 
1076
  mysql_change_db_impl(session, &new_db_file_name, db_default_cl);
 
1077
 
 
1078
  return(false);
641
1079
}
642
1080
 
 
1081
 
643
1082
/**
644
 
  @brief Internal implementation: switch current database to a valid one.
645
 
 
646
 
  @param session            Thread context.
647
 
  @param new_db_name    Name of the database to switch to. The function will
648
 
                        take ownership of the name (the caller must not free
649
 
                        the allocated memory). If the name is NULL, we're
650
 
                        going to switch to NULL db.
651
 
  @param new_db_charset Character set of the new database.
652
 
*/
653
 
 
654
 
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier)
655
 
{
656
 
  /* 1. Change current database in Session. */
657
 
 
658
 
#if 0
659
 
  if (new_db_name == NULL)
660
 
  {
661
 
    /*
662
 
      Session::set_db() does all the job -- it frees previous database name and
663
 
      sets the new one.
664
 
    */
665
 
 
666
 
    session->set_db(NULL, 0);
667
 
  }
668
 
  else
669
 
#endif
670
 
  {
671
 
    /*
672
 
      Here we already have a copy of database name to be used in Session. So,
673
 
      we just call Session::reset_db(). Since Session::reset_db() does not releases
674
 
      the previous database name, we should do it explicitly.
675
 
    */
676
 
 
677
 
    session->set_db(schema_identifier.getLower());
678
 
  }
679
 
}
680
 
 
681
 
static void mysql_change_db_impl(Session *session)
682
 
{
683
 
  session->set_db(string());
684
 
}
685
 
 
686
 
} /* namespace drizzled */
 
1083
  Change the current database and its attributes if needed.
 
1084
 
 
1085
  @param          session             thread handle
 
1086
  @param          new_db_name     database name
 
1087
  @param[in, out] saved_db_name   IN: "str" points to a buffer where to store
 
1088
                                  the old database name, "length" contains the
 
1089
                                  buffer size
 
1090
                                  OUT: if the current (default) database is
 
1091
                                  not NULL, its name is copied to the
 
1092
                                  buffer pointed at by "str"
 
1093
                                  and "length" is updated accordingly.
 
1094
                                  Otherwise "str" is set to NULL and
 
1095
                                  "length" is set to 0.
 
1096
  @param          force_switch    @see mysql_change_db()
 
1097
  @param[out]     cur_db_changed  out-flag to indicate whether the current
 
1098
                                  database has been changed (valid only if
 
1099
                                  the function suceeded)
 
1100
*/
 
1101
 
 
1102
bool mysql_opt_change_db(Session *session,
 
1103
                         const LEX_STRING *new_db_name,
 
1104
                         LEX_STRING *saved_db_name,
 
1105
                         bool force_switch,
 
1106
                         bool *cur_db_changed)
 
1107
{
 
1108
  *cur_db_changed= !cmp_db_names(session->db, new_db_name->str);
 
1109
 
 
1110
  if (!*cur_db_changed)
 
1111
    return false;
 
1112
 
 
1113
  backup_current_db_name(session, saved_db_name);
 
1114
 
 
1115
  return mysql_change_db(session, new_db_name, force_switch);
 
1116
}
 
1117
 
 
1118
 
 
1119
/*
 
1120
  Check if there is directory for the database name.
 
1121
 
 
1122
  SYNOPSIS
 
1123
    check_db_dir_existence()
 
1124
    db_name   database name
 
1125
 
 
1126
  RETURN VALUES
 
1127
    false   There is directory for the specified database name.
 
1128
    true    The directory does not exist.
 
1129
*/
 
1130
 
 
1131
bool check_db_dir_existence(const char *db_name)
 
1132
{
 
1133
  char db_dir_path[FN_REFLEN];
 
1134
  uint32_t db_dir_path_len;
 
1135
 
 
1136
  db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
 
1137
                                        db_name, "", "", 0);
 
1138
 
 
1139
  if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
 
1140
    db_dir_path[db_dir_path_len - 1]= 0;
 
1141
 
 
1142
  /* Check access. */
 
1143
 
 
1144
  return my_access(db_dir_path, F_OK);
 
1145
}