~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

  • Committer: Brian Aker
  • Date: 2009-05-23 17:13:03 UTC
  • mfrom: (1034.1.8 merge)
  • Revision ID: brian@gaz-20090523171303-d28xhutqic0xe2b4
Merge Brian

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