~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

  • Committer: Jay Pipes
  • Date: 2008-12-18 15:55:03 UTC
  • mto: This revision was merged to the branch mainline in revision 717.
  • Revision ID: jpipes@serialcoder-20081218155503-u45ygyunrdyyvquq
Fix for Bug#308457.  Gave UTF8 enclosure and escape character on LOAD DATA INFILE and changed the error message to be more descriptive

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
 
 
 
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 "log.h"
28
29
#include <drizzled/error.h>
29
30
#include <drizzled/gettext.h>
30
 
#include <drizzled/my_hash.h>
31
 
#include <drizzled/internal/m_string.h>
 
31
#include <mysys/hash.h>
32
32
#include <drizzled/session.h>
33
 
#include <drizzled/schema.h>
 
33
#include <drizzled/db.h>
34
34
#include <drizzled/sql_base.h>
35
35
#include <drizzled/lock.h>
36
 
#include <drizzled/errmsg_print.h>
37
 
#include <drizzled/transaction_services.h>
38
 
#include <drizzled/message/schema.pb.h>
39
 
#include <drizzled/sql_table.h>
40
 
#include <drizzled/plugin/storage_engine.h>
41
 
#include <drizzled/plugin/authorization.h>
42
 
#include <drizzled/global_charset_info.h>
43
 
#include <drizzled/pthread_globals.h>
44
 
#include <drizzled/charset.h>
45
 
#include <drizzled/internal/my_sys.h>
46
 
 
47
 
#include <boost/thread/mutex.hpp>
48
36
 
49
37
#define MAX_DROP_TABLE_Q_LEN      1024
50
38
 
51
 
using namespace std;
52
 
 
53
 
namespace drizzled
54
 
{
55
 
 
56
 
namespace schema
57
 
{
58
 
 
59
 
static void change_db_impl(Session &session);
60
 
static void change_db_impl(Session &session, identifier::Schema &schema_identifier);
 
39
const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NULL};
 
40
static TYPELIB deletable_extentions=
 
41
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
 
42
 
 
43
static long mysql_rm_known_files(Session *session, MY_DIR *dirp,
 
44
                                 const char *db, const char *path,
 
45
                                 uint32_t level,
 
46
                                 TableList **dropped_tables);
 
47
 
 
48
static bool rm_dir_w_symlink(const char *org_path, bool send_error);
 
49
static void mysql_change_db_impl(Session *session,
 
50
                                 LEX_STRING *new_db_name,
 
51
                                 const CHARSET_INFO * const new_db_charset);
 
52
 
 
53
 
 
54
/* Database lock hash */
 
55
HASH lock_db_cache;
 
56
pthread_mutex_t LOCK_lock_db;
 
57
int creating_database= 0;  // how many database locks are made
 
58
 
 
59
 
 
60
/* Structure for database lock */
 
61
typedef struct my_dblock_st
 
62
{
 
63
  char *name;        /* Database name        */
 
64
  uint32_t name_length;  /* Database length name */
 
65
} my_dblock_t;
 
66
 
 
67
 
 
68
/*
 
69
  lock_db key.
 
70
*/
 
71
 
 
72
extern "C" unsigned char* lock_db_get_key(my_dblock_t *, size_t *, bool not_used);
 
73
 
 
74
unsigned char* lock_db_get_key(my_dblock_t *ptr, size_t *length,
 
75
                       bool not_used __attribute__((unused)))
 
76
{
 
77
  *length= ptr->name_length;
 
78
  return (unsigned char*) ptr->name;
 
79
}
 
80
 
 
81
 
 
82
/*
 
83
  Free lock_db hash element.
 
84
*/
 
85
 
 
86
extern "C" void lock_db_free_element(void *ptr);
 
87
 
 
88
void lock_db_free_element(void *ptr)
 
89
{
 
90
  free(ptr);
 
91
}
 
92
 
 
93
 
 
94
/*
 
95
  Delete a database lock entry from hash.
 
96
*/
 
97
 
 
98
void lock_db_delete(const char *name, uint32_t length)
 
99
{
 
100
  my_dblock_t *opt;
 
101
  safe_mutex_assert_owner(&LOCK_lock_db);
 
102
  if ((opt= (my_dblock_t *)hash_search(&lock_db_cache,
 
103
                                       (const unsigned char*) name, length)))
 
104
    hash_delete(&lock_db_cache, (unsigned char*) opt);
 
105
}
 
106
 
 
107
 
 
108
/* Database options hash */
 
109
static HASH dboptions;
 
110
static bool dboptions_init= 0;
 
111
static pthread_rwlock_t LOCK_dboptions;
 
112
 
 
113
/* Structure for database options */
 
114
typedef struct my_dbopt_st
 
115
{
 
116
  char *name;                   /* Database name                  */
 
117
  uint32_t name_length;         /* Database length name           */
 
118
  const CHARSET_INFO *charset;  /* Database default character set */
 
119
} my_dbopt_t;
 
120
 
 
121
 
 
122
/*
 
123
  Function we use in the creation of our hash to get key.
 
124
*/
 
125
 
 
126
extern "C" unsigned char* dboptions_get_key(my_dbopt_t *opt, size_t *length,
 
127
                                    bool not_used);
 
128
 
 
129
unsigned char* dboptions_get_key(my_dbopt_t *opt, size_t *length,
 
130
                         bool not_used __attribute__((unused)))
 
131
{
 
132
  *length= opt->name_length;
 
133
  return (unsigned char*) opt->name;
 
134
}
 
135
 
 
136
 
 
137
/*
 
138
  Helper function to write a query to binlog used by mysql_rm_db()
 
139
*/
 
140
 
 
141
static inline void write_to_binlog(Session *session, char *query, uint32_t q_len,
 
142
                                   char *db, uint32_t db_len)
 
143
{
 
144
  Query_log_event qinfo(session, query, q_len, 0, 0);
 
145
  qinfo.error_code= 0;
 
146
  qinfo.db= db;
 
147
  qinfo.db_len= db_len;
 
148
  drizzle_bin_log.write(&qinfo);
 
149
}
 
150
 
 
151
 
 
152
/*
 
153
  Function to free dboptions hash element
 
154
*/
 
155
 
 
156
extern "C" void free_dbopt(void *dbopt);
 
157
 
 
158
void free_dbopt(void *dbopt)
 
159
{
 
160
  free((unsigned char*) dbopt);
 
161
}
 
162
 
 
163
 
 
164
/*
 
165
  Initialize database option hash and locked database hash.
 
166
 
 
167
  SYNOPSIS
 
168
    my_database_names()
 
169
 
 
170
  NOTES
 
171
    Must be called before any other database function is called.
 
172
 
 
173
  RETURN
 
174
    0   ok
 
175
    1   Fatal error
 
176
*/
 
177
 
 
178
bool my_database_names_init(void)
 
179
{
 
180
  bool error= false;
 
181
  (void) pthread_rwlock_init(&LOCK_dboptions, NULL);
 
182
  if (!dboptions_init)
 
183
  {
 
184
    dboptions_init= 1;
 
185
    error= hash_init(&dboptions, lower_case_table_names ?
 
186
                     &my_charset_bin : system_charset_info,
 
187
                     32, 0, 0, (hash_get_key) dboptions_get_key,
 
188
                     free_dbopt,0) ||
 
189
           hash_init(&lock_db_cache, lower_case_table_names ?
 
190
                     &my_charset_bin : system_charset_info,
 
191
                     32, 0, 0, (hash_get_key) lock_db_get_key,
 
192
                     lock_db_free_element,0);
 
193
 
 
194
  }
 
195
  return error;
 
196
}
 
197
 
 
198
 
 
199
 
 
200
/*
 
201
  Free database option hash and locked databases hash.
 
202
*/
 
203
 
 
204
void my_database_names_free(void)
 
205
{
 
206
  if (dboptions_init)
 
207
  {
 
208
    dboptions_init= 0;
 
209
    hash_free(&dboptions);
 
210
    (void) pthread_rwlock_destroy(&LOCK_dboptions);
 
211
    hash_free(&lock_db_cache);
 
212
  }
 
213
}
 
214
 
 
215
 
 
216
/*
 
217
  Cleanup cached options
 
218
*/
 
219
 
 
220
void my_dbopt_cleanup(void)
 
221
{
 
222
  pthread_rwlock_wrlock(&LOCK_dboptions);
 
223
  hash_free(&dboptions);
 
224
  hash_init(&dboptions, lower_case_table_names ?
 
225
            &my_charset_bin : system_charset_info,
 
226
            32, 0, 0, (hash_get_key) dboptions_get_key,
 
227
            free_dbopt,0);
 
228
  pthread_rwlock_unlock(&LOCK_dboptions);
 
229
}
 
230
 
 
231
 
 
232
/*
 
233
  Find database options in the hash.
 
234
 
 
235
  DESCRIPTION
 
236
    Search a database options in the hash, usings its path.
 
237
    Fills "create" on success.
 
238
 
 
239
  RETURN VALUES
 
240
    0 on success.
 
241
    1 on error.
 
242
*/
 
243
 
 
244
static bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
 
245
{
 
246
  my_dbopt_t *opt;
 
247
  uint32_t length;
 
248
  bool error= true;
 
249
 
 
250
  length= (uint) strlen(dbname);
 
251
 
 
252
  pthread_rwlock_rdlock(&LOCK_dboptions);
 
253
  if ((opt= (my_dbopt_t*) hash_search(&dboptions, (unsigned char*) dbname, length)))
 
254
  {
 
255
    create->default_table_charset= opt->charset;
 
256
    error= true;
 
257
  }
 
258
  pthread_rwlock_unlock(&LOCK_dboptions);
 
259
  return error;
 
260
}
 
261
 
 
262
 
 
263
/*
 
264
  Writes database options into the hash.
 
265
 
 
266
  DESCRIPTION
 
267
    Inserts database options into the hash, or updates
 
268
    options if they are already in the hash.
 
269
 
 
270
  RETURN VALUES
 
271
    0 on success.
 
272
    1 on error.
 
273
*/
 
274
 
 
275
static bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
 
276
{
 
277
  my_dbopt_t *opt;
 
278
  uint32_t length;
 
279
  bool error= false;
 
280
 
 
281
  length= (uint) strlen(dbname);
 
282
 
 
283
  pthread_rwlock_wrlock(&LOCK_dboptions);
 
284
  if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (unsigned char*) dbname, length)))
 
285
  {
 
286
    /* Options are not in the hash, insert them */
 
287
    char *tmp_name;
 
288
    if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
 
289
                         &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
 
290
                         NULL))
 
291
    {
 
292
      error= true;
 
293
      goto end;
 
294
    }
 
295
 
 
296
    opt->name= tmp_name;
 
297
    strcpy(opt->name, dbname);
 
298
    opt->name_length= length;
 
299
 
 
300
    if ((error= my_hash_insert(&dboptions, (unsigned char*) opt)))
 
301
    {
 
302
      free(opt);
 
303
      goto end;
 
304
    }
 
305
  }
 
306
 
 
307
  /* Update / write options in hash */
 
308
  opt->charset= create->default_table_charset;
 
309
 
 
310
end:
 
311
  pthread_rwlock_unlock(&LOCK_dboptions);
 
312
  return(error);
 
313
}
 
314
 
 
315
 
 
316
/*
 
317
  Deletes database options from the hash.
 
318
*/
 
319
 
 
320
void del_dbopt(const char *path)
 
321
{
 
322
  my_dbopt_t *opt;
 
323
  pthread_rwlock_wrlock(&LOCK_dboptions);
 
324
  if ((opt= (my_dbopt_t *)hash_search(&dboptions, (const unsigned char*) path,
 
325
                                      strlen(path))))
 
326
    hash_delete(&dboptions, (unsigned char*) opt);
 
327
  pthread_rwlock_unlock(&LOCK_dboptions);
 
328
}
 
329
 
 
330
 
 
331
/*
 
332
  Create database options file:
 
333
 
 
334
  DESCRIPTION
 
335
    Currently database default charset is only stored there.
 
336
 
 
337
  RETURN VALUES
 
338
  0     ok
 
339
  1     Could not create file or write to it.  Error sent through my_error()
 
340
*/
 
341
 
 
342
static bool write_db_opt(Session *session, const char *path, const char *name, HA_CREATE_INFO *create)
 
343
{
 
344
  bool error= true;
 
345
  drizzle::Schema db;
 
346
 
 
347
  assert(name);
 
348
 
 
349
  if (!create->default_table_charset)
 
350
    create->default_table_charset= session->variables.collation_server;
 
351
 
 
352
  if (put_dbopt(path, create))
 
353
    return 1;
 
354
 
 
355
  db.set_name(name);
 
356
  db.set_characterset(create->default_table_charset->csname);
 
357
  db.set_collation(create->default_table_charset->name);
 
358
 
 
359
  fstream output(path, ios::out | ios::trunc | ios::binary);
 
360
  if (!db.SerializeToOstream(&output))
 
361
    error= false;
 
362
 
 
363
  return error;
 
364
}
 
365
 
 
366
 
 
367
/*
 
368
  Load database options file
 
369
 
 
370
  load_db_opt()
 
371
  path          Path for option file
 
372
  create        Where to store the read options
 
373
 
 
374
  DESCRIPTION
 
375
 
 
376
  RETURN VALUES
 
377
  0     File found
 
378
  1     No database file or could not open it
 
379
 
 
380
*/
 
381
 
 
382
bool load_db_opt(Session *session, const char *path, HA_CREATE_INFO *create)
 
383
{
 
384
  bool error=1;
 
385
  drizzle::Schema db;
 
386
  string buffer;
 
387
 
 
388
  memset(create, 0, sizeof(*create));
 
389
  create->default_table_charset= session->variables.collation_server;
 
390
 
 
391
  /* Check if options for this database are already in the hash */
 
392
  if (!get_dbopt(path, create))
 
393
    return(0);
 
394
 
 
395
  fstream input(path, ios::in | ios::binary);
 
396
  if (!input)
 
397
    goto err1;
 
398
  else if (!db.ParseFromIstream(&input))
 
399
    goto err1;
 
400
 
 
401
  buffer= db.characterset();
 
402
  if (!(create->default_table_charset= get_charset_by_csname(buffer.c_str(), MY_CS_PRIMARY, MYF(0))))
 
403
  {
 
404
    sql_print_error(_("Error while loading database options: '%s':"),path);
 
405
    sql_print_error(ER(ER_UNKNOWN_COLLATION), buffer.c_str());
 
406
    create->default_table_charset= default_charset_info;
 
407
  }
 
408
 
 
409
  buffer= db.collation();
 
410
  if (!(create->default_table_charset= get_charset_by_name(buffer.c_str(), MYF(0))))
 
411
  {
 
412
    sql_print_error(_("Error while loading database options: '%s':"),path);
 
413
    sql_print_error(ER(ER_UNKNOWN_COLLATION), buffer.c_str());
 
414
    create->default_table_charset= default_charset_info;
 
415
  }
 
416
 
 
417
  /*
 
418
    Put the loaded value into the hash.
 
419
    Note that another thread could've added the same
 
420
    entry to the hash after we called get_dbopt(),
 
421
    but it's not an error, as put_dbopt() takes this
 
422
    possibility into account.
 
423
  */
 
424
  error= put_dbopt(path, create);
 
425
 
 
426
err1:
 
427
  return(error);
 
428
}
 
429
 
 
430
 
 
431
/*
 
432
  Retrieve database options by name. Load database options file or fetch from
 
433
  cache.
 
434
 
 
435
  SYNOPSIS
 
436
    load_db_opt_by_name()
 
437
    db_name         Database name
 
438
    db_create_info  Where to store the database options
 
439
 
 
440
  DESCRIPTION
 
441
    load_db_opt_by_name() is a shortcut for load_db_opt().
 
442
 
 
443
  NOTE
 
444
    Although load_db_opt_by_name() (and load_db_opt()) returns status of
 
445
    the operation, it is useless usually and should be ignored. The problem
 
446
    is that there are 1) system databases ("mysql") and 2) virtual
 
447
    databases ("information_schema"), which do not contain options file.
 
448
    So, load_db_opt[_by_name]() returns false for these databases, but this
 
449
    is not an error.
 
450
 
 
451
    load_db_opt[_by_name]() clears db_create_info structure in any case, so
 
452
    even on failure it contains valid data. So, common use case is just
 
453
    call load_db_opt[_by_name]() without checking return value and use
 
454
    db_create_info right after that.
 
455
 
 
456
  RETURN VALUES (read NOTE!)
 
457
    false   Success
 
458
    true    Failed to retrieve options
 
459
*/
 
460
 
 
461
bool load_db_opt_by_name(Session *session, const char *db_name,
 
462
                         HA_CREATE_INFO *db_create_info)
 
463
{
 
464
  char db_opt_path[FN_REFLEN];
 
465
 
 
466
  /*
 
467
    Pass an empty file name, and the database options file name as extension
 
468
    to avoid table name to file name encoding.
 
469
  */
 
470
  (void) build_table_filename(db_opt_path, sizeof(db_opt_path),
 
471
                              db_name, "", MY_DB_OPT_FILE, 0);
 
472
 
 
473
  return load_db_opt(session, db_opt_path, db_create_info);
 
474
}
 
475
 
 
476
 
 
477
/**
 
478
  Return default database collation.
 
479
 
 
480
  @param session     Thread context.
 
481
  @param db_name Database name.
 
482
 
 
483
  @return CHARSET_INFO object. The operation always return valid character
 
484
    set, even if the database does not exist.
 
485
*/
 
486
 
 
487
const CHARSET_INFO *get_default_db_collation(Session *session, const char *db_name)
 
488
{
 
489
  HA_CREATE_INFO db_info;
 
490
 
 
491
  if (session->db != NULL && strcmp(db_name, session->db) == 0)
 
492
    return session->db_charset;
 
493
 
 
494
  load_db_opt_by_name(session, db_name, &db_info);
 
495
 
 
496
  /*
 
497
    NOTE: even if load_db_opt_by_name() fails,
 
498
    db_info.default_table_charset contains valid character set
 
499
    (collation_server). We should not fail if load_db_opt_by_name() fails,
 
500
    because it is valid case. If a database has been created just by
 
501
    "mkdir", it does not contain db.opt file, but it is valid database.
 
502
  */
 
503
 
 
504
  return db_info.default_table_charset;
 
505
}
 
506
 
61
507
 
62
508
/*
63
509
  Create a database
64
510
 
65
511
  SYNOPSIS
66
 
  create_db()
 
512
  mysql_create_db()
67
513
  session               Thread handler
68
514
  db            Name of database to create
69
515
                Function assumes that this is already validated.
70
516
  create_info   Database create options (like character set)
 
517
  silent        Used by replication when internally creating a database.
 
518
                In this case the entry should not be logged.
71
519
 
72
520
  SIDE-EFFECTS
73
521
   1. Report back to client that command succeeded (my_ok)
74
522
   2. Report errors to client
75
523
   3. Log event to binary log
 
524
   (The 'silent' flags turns off 1 and 3.)
76
525
 
77
526
  RETURN VALUES
78
527
  false ok
80
529
 
81
530
*/
82
531
 
83
 
bool create(Session &session, const message::Schema &schema_message, const bool is_if_not_exists)
 
532
int mysql_create_db(Session *session, char *db, HA_CREATE_INFO *create_info, bool silent)
84
533
{
85
 
  TransactionServices &transaction_services= TransactionServices::singleton();
86
 
  bool error= false;
 
534
  char   path[FN_REFLEN+16];
 
535
  char   tmp_query[FN_REFLEN+16];
 
536
  long result= 1;
 
537
  int error= 0;
 
538
  struct stat stat_info;
 
539
  uint32_t create_options= create_info ? create_info->options : 0;
 
540
  uint32_t path_len;
 
541
 
 
542
  /* do not create 'information_schema' db */
 
543
  if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.c_str()))
 
544
  {
 
545
    my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
 
546
    return(-1);
 
547
  }
87
548
 
88
549
  /*
89
550
    Do not create database if another thread is holding read lock.
90
 
    Wait for global read lock before acquiring session->catalog()->schemaLock().
 
551
    Wait for global read lock before acquiring LOCK_drizzle_create_db.
91
552
    After wait_if_global_read_lock() we have protection against another
92
 
    global read lock. If we would acquire session->catalog()->schemaLock() first,
 
553
    global read lock. If we would acquire LOCK_drizzle_create_db first,
93
554
    another thread could step in and get the global read lock before we
94
555
    reach wait_if_global_read_lock(). If this thread tries the same as we
95
 
    (admin a db), it would then go and wait on session->catalog()->schemaLock()...
 
556
    (admin a db), it would then go and wait on LOCK_drizzle_create_db...
96
557
    Furthermore wait_if_global_read_lock() checks if the current thread
97
558
    has the global read lock and refuses the operation with
98
559
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
99
560
  */
100
 
  if (session.wait_if_global_read_lock(false, true))
101
 
  {
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
 
  {
110
 
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
111
 
 
112
 
    // Check to see if it exists already.  
113
 
    identifier::Schema schema_identifier(schema_message.name());
114
 
    if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
115
 
    {
116
 
      if (not is_if_not_exists)
117
 
      {
118
 
        my_error(ER_DB_CREATE_EXISTS, schema_identifier);
119
 
        error= true;
120
 
      }
121
 
      else
122
 
      {
123
 
        push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
124
 
                            ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
125
 
                            schema_message.name().c_str());
126
 
        session.my_ok();
127
 
      }
128
 
    }
129
 
    else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it 
130
 
    {
131
 
      my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
132
 
      error= true;
133
 
    }
134
 
    else // Created !
135
 
    {
136
 
      transaction_services.createSchema(session, schema_message);
137
 
      session.my_ok(1);
138
 
    }
139
 
  }
140
 
  session.startWaitingGlobalReadLock();
141
 
 
142
 
  return error;
 
561
  if (wait_if_global_read_lock(session, 0, 1))
 
562
  {
 
563
    error= -1;
 
564
    goto exit2;
 
565
  }
 
566
 
 
567
  pthread_mutex_lock(&LOCK_drizzle_create_db);
 
568
 
 
569
  /* Check directory */
 
570
  path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
 
571
  path[path_len-1]= 0;                    // Remove last '/' from path
 
572
 
 
573
  if (!stat(path,&stat_info))
 
574
  {
 
575
    if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
 
576
    {
 
577
      my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
 
578
      error= -1;
 
579
      goto exit;
 
580
    }
 
581
    push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
582
                        ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
 
583
    if (!silent)
 
584
      my_ok(session);
 
585
    error= 0;
 
586
    goto exit;
 
587
  }
 
588
  else
 
589
  {
 
590
    if (errno != ENOENT)
 
591
    {
 
592
      my_error(EE_STAT, MYF(0), path, errno);
 
593
      goto exit;
 
594
    }
 
595
    if (my_mkdir(path,0777,MYF(0)) < 0)
 
596
    {
 
597
      my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
 
598
      error= -1;
 
599
      goto exit;
 
600
    }
 
601
  }
 
602
 
 
603
  path[path_len-1]= FN_LIBCHAR;
 
604
  strncpy(path+path_len, MY_DB_OPT_FILE, sizeof(path)-path_len-1);
 
605
  if (write_db_opt(session, path, db, create_info))
 
606
  {
 
607
    /*
 
608
      Could not create options file.
 
609
      Restore things to beginning.
 
610
    */
 
611
    path[path_len]= 0;
 
612
    if (rmdir(path) >= 0)
 
613
    {
 
614
      error= -1;
 
615
      goto exit;
 
616
    }
 
617
    /*
 
618
      We come here when we managed to create the database, but not the option
 
619
      file.  In this case it's best to just continue as if nothing has
 
620
      happened.  (This is a very unlikely senario)
 
621
    */
 
622
  }
 
623
 
 
624
  if (!silent)
 
625
  {
 
626
    char *query;
 
627
    uint32_t query_length;
 
628
 
 
629
    if (!session->query)                                // Only in replication
 
630
    {
 
631
      query= tmp_query;
 
632
      query_length= sprintf(tmp_query, "create database `%s`", db);
 
633
    }
 
634
    else
 
635
    {
 
636
      query=        session->query;
 
637
      query_length= session->query_length;
 
638
    }
 
639
 
 
640
    if (drizzle_bin_log.is_open())
 
641
    {
 
642
      Query_log_event qinfo(session, query, query_length, 0,
 
643
                            /* suppress_use */ true);
 
644
 
 
645
      /*
 
646
        Write should use the database being created as the "current
 
647
        database" and not the threads current database, which is the
 
648
        default. If we do not change the "current database" to the
 
649
        database being created, the CREATE statement will not be
 
650
        replicated when using --binlog-do-db to select databases to be
 
651
        replicated.
 
652
 
 
653
        An example (--binlog-do-db=sisyfos):
 
654
 
 
655
          CREATE DATABASE bob;        # Not replicated
 
656
          USE bob;                    # 'bob' is the current database
 
657
          CREATE DATABASE sisyfos;    # Not replicated since 'bob' is
 
658
                                      # current database.
 
659
          USE sisyfos;                # Will give error on slave since
 
660
                                      # database does not exist.
 
661
      */
 
662
      qinfo.db     = db;
 
663
      qinfo.db_len = strlen(db);
 
664
 
 
665
      /* These DDL methods and logging protected with LOCK_drizzle_create_db */
 
666
      drizzle_bin_log.write(&qinfo);
 
667
    }
 
668
    my_ok(session, result);
 
669
  }
 
670
 
 
671
exit:
 
672
  pthread_mutex_unlock(&LOCK_drizzle_create_db);
 
673
  start_waiting_global_read_lock(session);
 
674
exit2:
 
675
  return(error);
143
676
}
144
677
 
145
678
 
146
679
/* db-name is already validated when we come here */
147
680
 
148
 
bool alter(Session &session,
149
 
           const message::Schema &schema_message,
150
 
           const message::Schema &original_schema)
 
681
bool mysql_alter_db(Session *session, const char *db, HA_CREATE_INFO *create_info)
151
682
{
152
 
  TransactionServices &transaction_services= TransactionServices::singleton();
 
683
  char path[FN_REFLEN+16];
 
684
  long result=1;
 
685
  int error= false;
153
686
 
154
687
  /*
155
688
    Do not alter database if another thread is holding read lock.
156
 
    Wait for global read lock before acquiring session->catalog()->schemaLock().
 
689
    Wait for global read lock before acquiring LOCK_drizzle_create_db.
157
690
    After wait_if_global_read_lock() we have protection against another
158
 
    global read lock. If we would acquire session->catalog()->schemaLock() first,
 
691
    global read lock. If we would acquire LOCK_drizzle_create_db first,
159
692
    another thread could step in and get the global read lock before we
160
693
    reach wait_if_global_read_lock(). If this thread tries the same as we
161
 
    (admin a db), it would then go and wait on session->catalog()->schemaLock()...
 
694
    (admin a db), it would then go and wait on LOCK_drizzle_create_db...
162
695
    Furthermore wait_if_global_read_lock() checks if the current thread
163
696
    has the global read lock and refuses the operation with
164
697
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
165
698
  */
166
 
  if ((session.wait_if_global_read_lock(false, true)))
167
 
    return false;
168
 
 
169
 
  bool success;
170
 
  {
171
 
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
172
 
 
173
 
    identifier::Schema schema_idenifier(schema_message.name());
174
 
    if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
175
 
    {
176
 
      my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
177
 
      return false;
178
 
    }
179
 
 
180
 
    /* Change options if current database is being altered. */
181
 
    success= plugin::StorageEngine::alterSchema(schema_message);
182
 
 
183
 
    if (success)
184
 
    {
185
 
      transaction_services.alterSchema(session, original_schema, schema_message);
186
 
      session.my_ok(1);
187
 
    }
188
 
    else
189
 
    {
190
 
      my_error(ER_ALTER_SCHEMA, schema_idenifier);
191
 
    }
192
 
  }
193
 
  session.startWaitingGlobalReadLock();
194
 
 
195
 
  return success;
 
699
  if ((error=wait_if_global_read_lock(session,0,1)))
 
700
    goto exit2;
 
701
 
 
702
  pthread_mutex_lock(&LOCK_drizzle_create_db);
 
703
 
 
704
  /*
 
705
     Recreate db options file: /dbpath/.db.opt
 
706
     We pass MY_DB_OPT_FILE as "extension" to avoid
 
707
     "table name to file name" encoding.
 
708
  */
 
709
  build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE, 0);
 
710
  if ((error=write_db_opt(session, path, db, create_info)))
 
711
    goto exit;
 
712
 
 
713
  /* Change options if current database is being altered. */
 
714
 
 
715
  if (session->db && !strcmp(session->db,db))
 
716
  {
 
717
    session->db_charset= create_info->default_table_charset ?
 
718
                     create_info->default_table_charset :
 
719
                     session->variables.collation_server;
 
720
    session->variables.collation_database= session->db_charset;
 
721
  }
 
722
 
 
723
  if (drizzle_bin_log.is_open())
 
724
  {
 
725
    Query_log_event qinfo(session, session->query, session->query_length, 0,
 
726
                          /* suppress_use */ true);
 
727
 
 
728
    /*
 
729
      Write should use the database being created as the "current
 
730
      database" and not the threads current database, which is the
 
731
      default.
 
732
    */
 
733
    qinfo.db     = db;
 
734
    qinfo.db_len = strlen(db);
 
735
 
 
736
    session->clear_error();
 
737
    /* These DDL methods and logging protected with LOCK_drizzle_create_db */
 
738
    drizzle_bin_log.write(&qinfo);
 
739
  }
 
740
  my_ok(session, result);
 
741
 
 
742
exit:
 
743
  pthread_mutex_unlock(&LOCK_drizzle_create_db);
 
744
  start_waiting_global_read_lock(session);
 
745
exit2:
 
746
  return(error);
196
747
}
197
748
 
198
749
 
200
751
  Drop all tables in a database and the database itself
201
752
 
202
753
  SYNOPSIS
203
 
    rm_db()
 
754
    mysql_rm_db()
204
755
    session                     Thread handle
205
756
    db                  Database name in the case given by user
206
757
                        It's already validated and set to lower case
213
764
    ERROR Error
214
765
*/
215
766
 
216
 
bool drop(Session &session, identifier::Schema &schema_identifier, const bool if_exists)
 
767
bool mysql_rm_db(Session *session,char *db,bool if_exists, bool silent)
217
768
{
218
 
  bool error= false;
 
769
  long deleted=0;
 
770
  int error= false;
 
771
  char  path[FN_REFLEN+16];
 
772
  MY_DIR *dirp;
 
773
  uint32_t length;
 
774
  TableList* dropped_tables= 0;
 
775
 
 
776
  if (db && (strcmp(db, "information_schema") == 0))
 
777
  {
 
778
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
 
779
    return(true);
 
780
  }
219
781
 
220
782
  /*
221
783
    Do not drop database if another thread is holding read lock.
222
 
    Wait for global read lock before acquiring session->catalog()->schemaLock().
 
784
    Wait for global read lock before acquiring LOCK_drizzle_create_db.
223
785
    After wait_if_global_read_lock() we have protection against another
224
 
    global read lock. If we would acquire session->catalog()->schemaLock() first,
 
786
    global read lock. If we would acquire LOCK_drizzle_create_db first,
225
787
    another thread could step in and get the global read lock before we
226
788
    reach wait_if_global_read_lock(). If this thread tries the same as we
227
 
    (admin a db), it would then go and wait on session->catalog()->schemaLock()...
 
789
    (admin a db), it would then go and wait on LOCK_drizzle_create_db...
228
790
    Furthermore wait_if_global_read_lock() checks if the current thread
229
791
    has the global read lock and refuses the operation with
230
792
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
231
793
  */
232
 
  if (session.wait_if_global_read_lock(false, true))
233
 
  {
234
 
    return true;
235
 
  }
236
 
 
237
 
  do
238
 
  {
239
 
    boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
240
 
    message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier);
241
 
 
242
 
    /* See if the schema exists */
243
 
    if (not message)
244
 
    {
245
 
      if (if_exists)
246
 
      {
247
 
        std::string path;
248
 
        schema_identifier.getSQLPath(path);
249
 
 
250
 
        push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
251
 
                            ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
252
 
                            path.c_str());
253
 
      }
254
 
      else
255
 
      {
256
 
        error= true;
257
 
        my_error(ER_DB_DROP_EXISTS, schema_identifier);
258
 
        break;
259
 
      }
260
 
    }
261
 
    else
262
 
    {
263
 
      error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
264
 
    }
265
 
 
266
 
  } while (0);
267
 
 
 
794
  if (wait_if_global_read_lock(session, 0, 1))
 
795
  {
 
796
    error= -1;
 
797
    goto exit2;
 
798
  }
 
799
 
 
800
  pthread_mutex_lock(&LOCK_drizzle_create_db);
 
801
 
 
802
  length= build_table_filename(path, sizeof(path), db, "", "", 0);
 
803
  strcpy(path+length, MY_DB_OPT_FILE);          // Append db option file name
 
804
  del_dbopt(path);                              // Remove dboption hash entry
 
805
  path[length]= '\0';                           // Remove file name
 
806
 
 
807
  /* See if the directory exists */
 
808
  if (!(dirp= my_dir(path,MYF(MY_DONT_SORT))))
 
809
  {
 
810
    if (!if_exists)
 
811
    {
 
812
      error= -1;
 
813
      my_error(ER_DB_DROP_EXISTS, MYF(0), db);
 
814
      goto exit;
 
815
    }
 
816
    else
 
817
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
818
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
 
819
  }
 
820
  else
 
821
  {
 
822
    pthread_mutex_lock(&LOCK_open);
 
823
    remove_db_from_cache(db);
 
824
    pthread_mutex_unlock(&LOCK_open);
 
825
 
 
826
 
 
827
    error= -1;
 
828
    if ((deleted= mysql_rm_known_files(session, dirp, db, path, 0,
 
829
                                       &dropped_tables)) >= 0)
 
830
    {
 
831
      ha_drop_database(path);
 
832
      error = 0;
 
833
    }
 
834
  }
 
835
  if (!silent && deleted>=0)
 
836
  {
 
837
    const char *query;
 
838
    uint32_t query_length;
 
839
    if (!session->query)
 
840
    {
 
841
      /* The client used the old obsolete mysql_drop_db() call */
 
842
      query= path;
 
843
      query_length= sprintf(path, "drop database `%s`", db);
 
844
    }
 
845
    else
 
846
    {
 
847
      query= session->query;
 
848
      query_length= session->query_length;
 
849
    }
 
850
    if (drizzle_bin_log.is_open())
 
851
    {
 
852
      Query_log_event qinfo(session, query, query_length, 0,
 
853
                            /* suppress_use */ true);
 
854
      /*
 
855
        Write should use the database being created as the "current
 
856
        database" and not the threads current database, which is the
 
857
        default.
 
858
      */
 
859
      qinfo.db     = db;
 
860
      qinfo.db_len = strlen(db);
 
861
 
 
862
      session->clear_error();
 
863
      /* These DDL methods and logging protected with LOCK_drizzle_create_db */
 
864
      drizzle_bin_log.write(&qinfo);
 
865
    }
 
866
    session->clear_error();
 
867
    session->server_status|= SERVER_STATUS_DB_DROPPED;
 
868
    my_ok(session, (uint32_t) deleted);
 
869
    session->server_status&= ~SERVER_STATUS_DB_DROPPED;
 
870
  }
 
871
  else if (drizzle_bin_log.is_open())
 
872
  {
 
873
    char *query, *query_pos, *query_end, *query_data_start;
 
874
    TableList *tbl;
 
875
    uint32_t db_len;
 
876
 
 
877
    if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
 
878
      goto exit; /* not much else we can do */
 
879
    query_pos= query_data_start= strcpy(query,"drop table ")+11;
 
880
    query_end= query + MAX_DROP_TABLE_Q_LEN;
 
881
    db_len= strlen(db);
 
882
 
 
883
    for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
 
884
    {
 
885
      uint32_t tbl_name_len;
 
886
 
 
887
      /* 3 for the quotes and the comma*/
 
888
      tbl_name_len= strlen(tbl->table_name) + 3;
 
889
      if (query_pos + tbl_name_len + 1 >= query_end)
 
890
      {
 
891
        /* These DDL methods and logging protected with LOCK_drizzle_create_db */
 
892
        write_to_binlog(session, query, query_pos -1 - query, db, db_len);
 
893
        query_pos= query_data_start;
 
894
      }
 
895
 
 
896
      *query_pos++ = '`';
 
897
      query_pos= strcpy(query_pos,tbl->table_name) + (tbl_name_len-3);
 
898
      *query_pos++ = '`';
 
899
      *query_pos++ = ',';
 
900
    }
 
901
 
 
902
    if (query_pos != query_data_start)
 
903
    {
 
904
      /* These DDL methods and logging protected with LOCK_drizzle_create_db */
 
905
      write_to_binlog(session, query, query_pos -1 - query, db, db_len);
 
906
    }
 
907
  }
 
908
 
 
909
exit:
268
910
  /*
269
911
    If this database was the client's selected database, we silently
270
912
    change the client's selected database to nothing (to have an empty
271
913
    SELECT DATABASE() in the future). For this we free() session->db and set
272
914
    it to 0.
273
915
  */
274
 
  if (not error and schema_identifier.compare(*session.schema()))
275
 
    change_db_impl(session);
276
 
 
277
 
  session.startWaitingGlobalReadLock();
278
 
 
279
 
  return error;
280
 
}
 
916
  if (session->db && !strcmp(session->db, db))
 
917
    mysql_change_db_impl(session, NULL, session->variables.collation_server);
 
918
  pthread_mutex_unlock(&LOCK_drizzle_create_db);
 
919
  start_waiting_global_read_lock(session);
 
920
exit2:
 
921
  return(error);
 
922
}
 
923
 
 
924
/*
 
925
  Removes files with known extensions plus.
 
926
  session MUST be set when calling this function!
 
927
*/
 
928
 
 
929
static long mysql_rm_known_files(Session *session, MY_DIR *dirp, const char *db,
 
930
                                 const char *org_path, uint32_t level,
 
931
                                 TableList **dropped_tables)
 
932
{
 
933
  long deleted=0;
 
934
  uint32_t found_other_files=0;
 
935
  char filePath[FN_REFLEN];
 
936
  TableList *tot_list=0, **tot_list_next;
 
937
 
 
938
  tot_list_next= &tot_list;
 
939
 
 
940
  for (uint32_t idx=0 ;
 
941
       idx < (uint) dirp->number_off_files && !session->killed ;
 
942
       idx++)
 
943
  {
 
944
    FILEINFO *file=dirp->dir_entry+idx;
 
945
    char *extension;
 
946
 
 
947
    /* skiping . and .. */
 
948
    if (file->name[0] == '.' && (!file->name[1] ||
 
949
       (file->name[1] == '.' &&  !file->name[2])))
 
950
      continue;
 
951
 
 
952
    if (!(extension= strrchr(file->name, '.')))
 
953
      extension= strchr(file->name, '\0');
 
954
    if (find_type(extension, &deletable_extentions,1+2) <= 0)
 
955
    {
 
956
      /*
 
957
        ass ass ass.
 
958
 
 
959
        strange checking for magic extensions that are then deleted if
 
960
        not reg_ext (i.e. .frm).
 
961
 
 
962
        and (previously) we'd err out on drop database if files not matching
 
963
        engine ha_known_exts() or deletable_extensions were present.
 
964
 
 
965
        presumably this was to avoid deleting other user data... except if that
 
966
        data happened to be in files ending in .BAK, .opt or .TMD. *fun*
 
967
       */
 
968
      find_type(extension, ha_known_exts(),1+2);
 
969
      continue;
 
970
    }
 
971
    /* just for safety we use files_charset_info */
 
972
    if (db && !my_strcasecmp(files_charset_info,
 
973
                             extension, reg_ext))
 
974
    {
 
975
      uint32_t db_len= strlen(db);
 
976
 
 
977
      /* Drop the table nicely */
 
978
      *extension= 0;                    // Remove extension
 
979
      TableList *table_list=(TableList*)
 
980
                              session->calloc(sizeof(*table_list) +
 
981
                                          db_len + 1 +
 
982
                                          MYSQL50_TABLE_NAME_PREFIX_LENGTH +
 
983
                                          strlen(file->name) + 1);
 
984
 
 
985
      if (!table_list)
 
986
        goto err;
 
987
      table_list->db= (char*) (table_list+1);
 
988
      table_list->table_name= strcpy(table_list->db, db) + db_len + 1;
 
989
      filename_to_tablename(file->name, table_list->table_name,
 
990
                            MYSQL50_TABLE_NAME_PREFIX_LENGTH +
 
991
                            strlen(file->name) + 1);
 
992
      table_list->alias= table_list->table_name;        // If lower_case_table_names=2
 
993
      table_list->internal_tmp_table= is_prefix(file->name, TMP_FILE_PREFIX);
 
994
      /* Link into list */
 
995
      (*tot_list_next)= table_list;
 
996
      tot_list_next= &table_list->next_local;
 
997
      deleted++;
 
998
    }
 
999
    else
 
1000
    {
 
1001
      sprintf(filePath, "%s/%s", org_path, file->name);
 
1002
      if (my_delete_with_symlink(filePath,MYF(MY_WME)))
 
1003
      {
 
1004
        goto err;
 
1005
      }
 
1006
    }
 
1007
  }
 
1008
  if (session->killed ||
 
1009
      (tot_list && mysql_rm_table_part2(session, tot_list, 1, 0, 1)))
 
1010
    goto err;
 
1011
 
 
1012
  my_dirend(dirp);
 
1013
 
 
1014
  if (dropped_tables)
 
1015
    *dropped_tables= tot_list;
 
1016
 
 
1017
  /*
 
1018
    If the directory is a symbolic link, remove the link first, then
 
1019
    remove the directory the symbolic link pointed at
 
1020
  */
 
1021
  if (found_other_files)
 
1022
  {
 
1023
    my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, EEXIST);
 
1024
    return(-1);
 
1025
  }
 
1026
  else
 
1027
  {
 
1028
    /* Don't give errors if we can't delete 'RAID' directory */
 
1029
    if (rm_dir_w_symlink(org_path, level == 0))
 
1030
      return(-1);
 
1031
  }
 
1032
 
 
1033
  return(deleted);
 
1034
 
 
1035
err:
 
1036
  my_dirend(dirp);
 
1037
  return(-1);
 
1038
}
 
1039
 
 
1040
 
 
1041
/*
 
1042
  Remove directory with symlink
 
1043
 
 
1044
  SYNOPSIS
 
1045
    rm_dir_w_symlink()
 
1046
    org_path    path of derictory
 
1047
    send_error  send errors
 
1048
  RETURN
 
1049
    0 OK
 
1050
    1 ERROR
 
1051
*/
 
1052
 
 
1053
static bool rm_dir_w_symlink(const char *org_path, bool send_error)
 
1054
{
 
1055
  char tmp_path[FN_REFLEN], *pos;
 
1056
  char *path= tmp_path;
 
1057
  unpack_filename(tmp_path, org_path);
 
1058
#ifdef HAVE_READLINK
 
1059
  int error;
 
1060
  char tmp2_path[FN_REFLEN];
 
1061
 
 
1062
  /* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */
 
1063
  pos= strchr(path, '\0');
 
1064
  if (pos > path && pos[-1] == FN_LIBCHAR)
 
1065
    *--pos=0;
 
1066
 
 
1067
  if ((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0)
 
1068
    return(1);
 
1069
  if (!error)
 
1070
  {
 
1071
    if (my_delete(path, MYF(send_error ? MY_WME : 0)))
 
1072
    {
 
1073
      return(send_error);
 
1074
    }
 
1075
    /* Delete directory symbolic link pointed at */
 
1076
    path= tmp2_path;
 
1077
  }
 
1078
#endif
 
1079
  /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
 
1080
  pos= strchr(path, '\0');
 
1081
 
 
1082
  if (pos > path && pos[-1] == FN_LIBCHAR)
 
1083
    *--pos=0;
 
1084
  if (rmdir(path) < 0 && send_error)
 
1085
  {
 
1086
    my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
 
1087
    return(1);
 
1088
  }
 
1089
  return(0);
 
1090
}
 
1091
 
 
1092
 
 
1093
/**
 
1094
  @brief Internal implementation: switch current database to a valid one.
 
1095
 
 
1096
  @param session            Thread context.
 
1097
  @param new_db_name    Name of the database to switch to. The function will
 
1098
                        take ownership of the name (the caller must not free
 
1099
                        the allocated memory). If the name is NULL, we're
 
1100
                        going to switch to NULL db.
 
1101
  @param new_db_charset Character set of the new database.
 
1102
*/
 
1103
 
 
1104
static void mysql_change_db_impl(Session *session,
 
1105
                                 LEX_STRING *new_db_name,
 
1106
                                 const CHARSET_INFO * const new_db_charset)
 
1107
{
 
1108
  /* 1. Change current database in Session. */
 
1109
 
 
1110
  if (new_db_name == NULL)
 
1111
  {
 
1112
    /*
 
1113
      Session::set_db() does all the job -- it frees previous database name and
 
1114
      sets the new one.
 
1115
    */
 
1116
 
 
1117
    session->set_db(NULL, 0);
 
1118
  }
 
1119
  else if (my_strcasecmp(system_charset_info, new_db_name->str,
 
1120
                         INFORMATION_SCHEMA_NAME.c_str()) == 0)
 
1121
  {
 
1122
    /*
 
1123
      Here we must use Session::set_db(), because we want to copy
 
1124
      INFORMATION_SCHEMA_NAME constant.
 
1125
    */
 
1126
 
 
1127
    session->set_db(INFORMATION_SCHEMA_NAME.c_str(),
 
1128
                    INFORMATION_SCHEMA_NAME.length());
 
1129
  }
 
1130
  else
 
1131
  {
 
1132
    /*
 
1133
      Here we already have a copy of database name to be used in Session. So,
 
1134
      we just call Session::reset_db(). Since Session::reset_db() does not releases
 
1135
      the previous database name, we should do it explicitly.
 
1136
    */
 
1137
 
 
1138
    if (session->db)
 
1139
      free(session->db);
 
1140
 
 
1141
    session->reset_db(new_db_name->str, new_db_name->length);
 
1142
  }
 
1143
 
 
1144
  /* 3. Update db-charset environment variables. */
 
1145
 
 
1146
  session->db_charset= new_db_charset;
 
1147
  session->variables.collation_database= new_db_charset;
 
1148
}
 
1149
 
 
1150
 
 
1151
 
 
1152
/**
 
1153
  Backup the current database name before switch.
 
1154
 
 
1155
  @param[in]      session             thread handle
 
1156
  @param[in, out] saved_db_name   IN: "str" points to a buffer where to store
 
1157
                                  the old database name, "length" contains the
 
1158
                                  buffer size
 
1159
                                  OUT: if the current (default) database is
 
1160
                                  not NULL, its name is copied to the
 
1161
                                  buffer pointed at by "str"
 
1162
                                  and "length" is updated accordingly.
 
1163
                                  Otherwise "str" is set to NULL and
 
1164
                                  "length" is set to 0.
 
1165
*/
 
1166
 
 
1167
static void backup_current_db_name(Session *session,
 
1168
                                   LEX_STRING *saved_db_name)
 
1169
{
 
1170
  if (!session->db)
 
1171
  {
 
1172
    /* No current (default) database selected. */
 
1173
 
 
1174
    saved_db_name->str= NULL;
 
1175
    saved_db_name->length= 0;
 
1176
  }
 
1177
  else
 
1178
  {
 
1179
    strncpy(saved_db_name->str, session->db, saved_db_name->length - 1);
 
1180
    saved_db_name->length= session->db_length;
 
1181
  }
 
1182
}
 
1183
 
 
1184
 
 
1185
/**
 
1186
  Return true if db1_name is equal to db2_name, false otherwise.
 
1187
 
 
1188
  The function allows to compare database names according to the MySQL
 
1189
  rules. The database names db1 and db2 are equal if:
 
1190
     - db1 is NULL and db2 is NULL;
 
1191
     or
 
1192
     - db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
 
1193
       db2 in system character set (UTF8).
 
1194
*/
 
1195
 
 
1196
static inline bool
 
1197
cmp_db_names(const char *db1_name,
 
1198
             const char *db2_name)
 
1199
{
 
1200
  return
 
1201
         /* db1 is NULL and db2 is NULL */
 
1202
         (!db1_name && !db2_name) ||
 
1203
 
 
1204
         /* db1 is not-NULL, db2 is not-NULL, db1 == db2. */
 
1205
         (db1_name && db2_name && my_strcasecmp(system_charset_info, db1_name, db2_name) == 0);
 
1206
}
 
1207
 
281
1208
 
282
1209
/**
283
1210
  @brief Change the current database and its attributes unconditionally.
341
1268
    @retval true  Error
342
1269
*/
343
1270
 
344
 
bool change(Session &session, identifier::Schema &schema_identifier)
 
1271
bool mysql_change_db(Session *session, const LEX_STRING *new_db_name, bool force_switch)
345
1272
{
346
 
 
347
 
  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
348
 
  {
349
 
    /* Error message is set in isAuthorized */
350
 
    return true;
351
 
  }
352
 
 
353
 
  if (not check(session, schema_identifier))
354
 
  {
355
 
    my_error(ER_WRONG_DB_NAME, schema_identifier);
356
 
 
357
 
    return true;
358
 
  }
359
 
 
360
 
  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
361
 
  {
362
 
    my_error(ER_BAD_DB_ERROR, schema_identifier);
363
 
 
364
 
    /* The operation failed. */
365
 
 
366
 
    return true;
367
 
  }
368
 
 
369
 
  change_db_impl(session, schema_identifier);
370
 
 
371
 
  return false;
 
1273
  LEX_STRING new_db_file_name;
 
1274
  const CHARSET_INFO *db_default_cl;
 
1275
 
 
1276
  if (new_db_name == NULL ||
 
1277
      new_db_name->length == 0)
 
1278
  {
 
1279
    if (force_switch)
 
1280
    {
 
1281
      /*
 
1282
        This can happen only if we're switching the current database back
 
1283
        after loading stored program. The thing is that loading of stored
 
1284
        program can happen when there is no current database.
 
1285
 
 
1286
        TODO: actually, new_db_name and new_db_name->str seem to be always
 
1287
        non-NULL. In case of stored program, new_db_name->str == "" and
 
1288
        new_db_name->length == 0.
 
1289
      */
 
1290
 
 
1291
      mysql_change_db_impl(session, NULL, session->variables.collation_server);
 
1292
 
 
1293
      return(false);
 
1294
    }
 
1295
    else
 
1296
    {
 
1297
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
 
1298
 
 
1299
      return(true);
 
1300
    }
 
1301
  }
 
1302
 
 
1303
  if (my_strcasecmp(system_charset_info, new_db_name->str,
 
1304
                    INFORMATION_SCHEMA_NAME.c_str()) == 0)
 
1305
  {
 
1306
    /* Switch the current database to INFORMATION_SCHEMA. */
 
1307
    /* const_cast<> is safe here: mysql_change_db_impl does a copy */
 
1308
    LEX_STRING is_name= { const_cast<char *>(INFORMATION_SCHEMA_NAME.c_str()),
 
1309
                          INFORMATION_SCHEMA_NAME.length() };
 
1310
    mysql_change_db_impl(session, &is_name, system_charset_info);
 
1311
 
 
1312
    return(false);
 
1313
  }
 
1314
 
 
1315
  /*
 
1316
    Now we need to make a copy because check_db_name requires a
 
1317
    non-constant argument. Actually, it takes database file name.
 
1318
 
 
1319
    TODO: fix check_db_name().
 
1320
  */
 
1321
 
 
1322
  new_db_file_name.length= new_db_name->length;
 
1323
  new_db_file_name.str= (char *)malloc(new_db_name->length + 1);
 
1324
  if (new_db_file_name.str == NULL)
 
1325
    return(true);                             /* the error is set */
 
1326
  memcpy(new_db_file_name.str, new_db_name->str, new_db_name->length);
 
1327
  new_db_file_name.str[new_db_name->length]= 0;
 
1328
 
 
1329
 
 
1330
  /*
 
1331
    NOTE: if check_db_name() fails, we should throw an error in any case,
 
1332
    even if we are called from sp_head::execute().
 
1333
 
 
1334
    It's next to impossible however to get this error when we are called
 
1335
    from sp_head::execute(). But let's switch the current database to NULL
 
1336
    in this case to be sure.
 
1337
  */
 
1338
 
 
1339
  if (check_db_name(&new_db_file_name))
 
1340
  {
 
1341
    my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
 
1342
    free(new_db_file_name.str);
 
1343
 
 
1344
    if (force_switch)
 
1345
      mysql_change_db_impl(session, NULL, session->variables.collation_server);
 
1346
 
 
1347
    return(true);
 
1348
  }
 
1349
 
 
1350
  if (check_db_dir_existence(new_db_file_name.str))
 
1351
  {
 
1352
    if (force_switch)
 
1353
    {
 
1354
      /* Throw a warning and free new_db_file_name. */
 
1355
 
 
1356
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
1357
                          ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
 
1358
                          new_db_file_name.str);
 
1359
 
 
1360
      free(new_db_file_name.str);
 
1361
 
 
1362
      /* Change db to NULL. */
 
1363
 
 
1364
      mysql_change_db_impl(session, NULL, session->variables.collation_server);
 
1365
 
 
1366
      /* The operation succeed. */
 
1367
 
 
1368
      return(false);
 
1369
    }
 
1370
    else
 
1371
    {
 
1372
      /* Report an error and free new_db_file_name. */
 
1373
 
 
1374
      my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
 
1375
      free(new_db_file_name.str);
 
1376
 
 
1377
      /* The operation failed. */
 
1378
 
 
1379
      return(true);
 
1380
    }
 
1381
  }
 
1382
 
 
1383
  /*
 
1384
    NOTE: in mysql_change_db_impl() new_db_file_name is assigned to Session
 
1385
    attributes and will be freed in Session::~Session().
 
1386
  */
 
1387
 
 
1388
  db_default_cl= get_default_db_collation(session, new_db_file_name.str);
 
1389
 
 
1390
  mysql_change_db_impl(session, &new_db_file_name, db_default_cl);
 
1391
 
 
1392
  return(false);
372
1393
}
373
1394
 
 
1395
 
374
1396
/**
375
 
  @brief Internal implementation: switch current database to a valid one.
 
1397
  Change the current database and its attributes if needed.
376
1398
 
377
 
  @param session            Thread context.
378
 
  @param new_db_name    Name of the database to switch to. The function will
379
 
                        take ownership of the name (the caller must not free
380
 
                        the allocated memory). If the name is NULL, we're
381
 
                        going to switch to NULL db.
382
 
  @param new_db_charset Character set of the new database.
 
1399
  @param          session             thread handle
 
1400
  @param          new_db_name     database name
 
1401
  @param[in, out] saved_db_name   IN: "str" points to a buffer where to store
 
1402
                                  the old database name, "length" contains the
 
1403
                                  buffer size
 
1404
                                  OUT: if the current (default) database is
 
1405
                                  not NULL, its name is copied to the
 
1406
                                  buffer pointed at by "str"
 
1407
                                  and "length" is updated accordingly.
 
1408
                                  Otherwise "str" is set to NULL and
 
1409
                                  "length" is set to 0.
 
1410
  @param          force_switch    @see mysql_change_db()
 
1411
  @param[out]     cur_db_changed  out-flag to indicate whether the current
 
1412
                                  database has been changed (valid only if
 
1413
                                  the function suceeded)
383
1414
*/
384
1415
 
385
 
static void change_db_impl(Session &session, identifier::Schema &schema_identifier)
386
 
{
387
 
  /* 1. Change current database in Session. */
388
 
 
389
 
#if 0
390
 
  if (new_db_name == NULL)
391
 
  {
392
 
    /*
393
 
      Session::set_db() does all the job -- it frees previous database name and
394
 
      sets the new one.
395
 
    */
396
 
 
397
 
    session->set_db(NULL, 0);
398
 
  }
399
 
  else
400
 
#endif
401
 
  {
402
 
    /*
403
 
      Here we already have a copy of database name to be used in Session. So,
404
 
      we just call Session::reset_db(). Since Session::reset_db() does not releases
405
 
      the previous database name, we should do it explicitly.
406
 
    */
407
 
 
408
 
    session.set_db(schema_identifier.getSchemaName());
409
 
  }
410
 
}
411
 
 
412
 
static void change_db_impl(Session &session)
413
 
{
414
 
  session.set_db(string());
415
 
}
 
1416
bool mysql_opt_change_db(Session *session,
 
1417
                         const LEX_STRING *new_db_name,
 
1418
                         LEX_STRING *saved_db_name,
 
1419
                         bool force_switch,
 
1420
                         bool *cur_db_changed)
 
1421
{
 
1422
  *cur_db_changed= !cmp_db_names(session->db, new_db_name->str);
 
1423
 
 
1424
  if (!*cur_db_changed)
 
1425
    return false;
 
1426
 
 
1427
  backup_current_db_name(session, saved_db_name);
 
1428
 
 
1429
  return mysql_change_db(session, new_db_name, force_switch);
 
1430
}
 
1431
 
416
1432
 
417
1433
/*
418
 
  Check if database name is valid
419
 
 
420
 
  SYNPOSIS
421
 
    check()
422
 
    org_name            Name of database and length
423
 
 
424
 
  RETURN
425
 
    false error
426
 
    true ok
 
1434
  Check if there is directory for the database name.
 
1435
 
 
1436
  SYNOPSIS
 
1437
    check_db_dir_existence()
 
1438
    db_name   database name
 
1439
 
 
1440
  RETURN VALUES
 
1441
    false   There is directory for the specified database name.
 
1442
    true    The directory does not exist.
427
1443
*/
428
1444
 
429
 
bool check(Session &session, identifier::Schema &schema_identifier)
 
1445
bool check_db_dir_existence(const char *db_name)
430
1446
{
431
 
  if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
432
 
  {
433
 
    return false;
434
 
  }
435
 
 
436
 
  return schema_identifier.isValid();
 
1447
  char db_dir_path[FN_REFLEN];
 
1448
  uint32_t db_dir_path_len;
 
1449
 
 
1450
  db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
 
1451
                                        db_name, "", "", 0);
 
1452
 
 
1453
  if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
 
1454
    db_dir_path[db_dir_path_len - 1]= 0;
 
1455
 
 
1456
  /* Check access. */
 
1457
 
 
1458
  return my_access(db_dir_path, F_OK);
437
1459
}
438
 
 
439
 
} /* namespace schema */
440
 
 
441
 
} /* namespace drizzled */