~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

  • Committer: Brian Aker
  • Date: 2009-02-02 18:19:36 UTC
  • mfrom: (820.1.14 nofrm)
  • Revision ID: brian@tangent.org-20090202181936-l03a2jb3vpndr1k3
Merge from Stewart.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
#include <drizzled/errmsg_print.h>
36
36
#include <drizzled/replicator.h>
37
37
 
 
38
#define MY_DB_OPT_FILE "db.opt"
38
39
#define MAX_DROP_TABLE_Q_LEN      1024
39
40
 
40
41
const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NULL};
55
56
/* Database lock hash */
56
57
HASH lock_db_cache;
57
58
pthread_mutex_t LOCK_lock_db;
 
59
bool dbcache_init= false;
58
60
int creating_database= 0;  // how many database locks are made
59
61
 
60
62
 
105
107
    hash_delete(&lock_db_cache, (unsigned char*) opt);
106
108
}
107
109
 
108
 
 
109
 
/* Database options hash */
110
 
static HASH dboptions;
111
 
static bool dboptions_init= 0;
112
 
static pthread_rwlock_t LOCK_dboptions;
113
 
 
114
 
/* Structure for database options */
115
 
typedef struct my_dbopt_st
116
 
{
117
 
  char *name;                   /* Database name                  */
118
 
  uint32_t name_length;         /* Database length name           */
119
 
  const CHARSET_INFO *charset;  /* Database default character set */
120
 
} my_dbopt_t;
121
 
 
122
 
 
123
 
/*
124
 
  Function we use in the creation of our hash to get key.
125
 
*/
126
 
 
127
 
extern "C" unsigned char* dboptions_get_key(my_dbopt_t *opt, size_t *length,
128
 
                                    bool not_used);
129
 
 
130
 
unsigned char* dboptions_get_key(my_dbopt_t *opt, size_t *length,
131
 
                         bool )
132
 
{
133
 
  *length= opt->name_length;
134
 
  return (unsigned char*) opt->name;
135
 
}
136
 
 
137
 
 
138
110
/*
139
111
  Helper function to write a query to binlog used by mysql_rm_db()
140
112
*/
144
116
  (void)replicator_statement(session, query, query_length);
145
117
}
146
118
 
147
 
 
148
 
/*
149
 
  Function to free dboptions hash element
150
 
*/
151
 
 
152
 
extern "C" void free_dbopt(void *dbopt);
153
 
 
154
 
void free_dbopt(void *dbopt)
155
 
{
156
 
  free((unsigned char*) dbopt);
157
 
}
158
 
 
159
 
 
160
119
/*
161
120
  Initialize database option hash and locked database hash.
162
121
 
174
133
bool my_database_names_init(void)
175
134
{
176
135
  bool error= false;
177
 
  (void) pthread_rwlock_init(&LOCK_dboptions, NULL);
178
 
  if (!dboptions_init)
 
136
  if (!dbcache_init)
179
137
  {
180
 
    dboptions_init= 1;
181
 
    error= hash_init(&dboptions, lower_case_table_names ?
182
 
                     &my_charset_bin : system_charset_info,
183
 
                     32, 0, 0, (hash_get_key) dboptions_get_key,
184
 
                     free_dbopt,0) ||
185
 
           hash_init(&lock_db_cache, lower_case_table_names ?
 
138
    dbcache_init= true;
 
139
    error= hash_init(&lock_db_cache, lower_case_table_names ?
186
140
                     &my_charset_bin : system_charset_info,
187
141
                     32, 0, 0, (hash_get_key) lock_db_get_key,
188
142
                     lock_db_free_element,0);
191
145
  return error;
192
146
}
193
147
 
194
 
 
195
 
 
196
 
/*
197
 
  Free database option hash and locked databases hash.
198
 
*/
199
 
 
200
 
void my_database_names_free(void)
201
 
{
202
 
  if (dboptions_init)
203
 
  {
204
 
    dboptions_init= 0;
205
 
    hash_free(&dboptions);
206
 
    (void) pthread_rwlock_destroy(&LOCK_dboptions);
207
 
    hash_free(&lock_db_cache);
208
 
  }
209
 
}
210
 
 
211
 
 
212
 
/*
213
 
  Cleanup cached options
214
 
*/
215
 
 
216
 
void my_dbopt_cleanup(void)
217
 
{
218
 
  pthread_rwlock_wrlock(&LOCK_dboptions);
219
 
  hash_free(&dboptions);
220
 
  hash_init(&dboptions, lower_case_table_names ?
221
 
            &my_charset_bin : system_charset_info,
222
 
            32, 0, 0, (hash_get_key) dboptions_get_key,
223
 
            free_dbopt,0);
224
 
  pthread_rwlock_unlock(&LOCK_dboptions);
225
 
}
226
 
 
227
 
 
228
 
/*
229
 
  Find database options in the hash.
230
 
 
231
 
  DESCRIPTION
232
 
    Search a database options in the hash, usings its path.
233
 
    Fills "create" on success.
234
 
 
235
 
  RETURN VALUES
236
 
    0 on success.
237
 
    1 on error.
238
 
*/
239
 
 
240
 
static bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
241
 
{
242
 
  my_dbopt_t *opt;
243
 
  uint32_t length;
244
 
  bool error= true;
245
 
 
246
 
  length= (uint) strlen(dbname);
247
 
 
248
 
  pthread_rwlock_rdlock(&LOCK_dboptions);
249
 
  if ((opt= (my_dbopt_t*) hash_search(&dboptions, (unsigned char*) dbname, length)))
250
 
  {
251
 
    create->default_table_charset= opt->charset;
252
 
    error= true;
253
 
  }
254
 
  pthread_rwlock_unlock(&LOCK_dboptions);
255
 
  return error;
256
 
}
257
 
 
258
 
 
259
 
/*
260
 
  Writes database options into the hash.
261
 
 
262
 
  DESCRIPTION
263
 
    Inserts database options into the hash, or updates
264
 
    options if they are already in the hash.
265
 
 
266
 
  RETURN VALUES
267
 
    0 on success.
268
 
    1 on error.
269
 
*/
270
 
 
271
 
static bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
272
 
{
273
 
  my_dbopt_t *opt;
274
 
  uint32_t length;
275
 
  bool error= false;
276
 
 
277
 
  length= (uint) strlen(dbname);
278
 
 
279
 
  pthread_rwlock_wrlock(&LOCK_dboptions);
280
 
  if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (unsigned char*) dbname, length)))
281
 
  {
282
 
    /* Options are not in the hash, insert them */
283
 
    char *tmp_name;
284
 
    if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
285
 
                         &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
286
 
                         NULL))
287
 
    {
288
 
      error= true;
289
 
      goto end;
290
 
    }
291
 
 
292
 
    opt->name= tmp_name;
293
 
    strcpy(opt->name, dbname);
294
 
    opt->name_length= length;
295
 
 
296
 
    if ((error= my_hash_insert(&dboptions, (unsigned char*) opt)))
297
 
    {
298
 
      free(opt);
299
 
      goto end;
300
 
    }
301
 
  }
302
 
 
303
 
  /* Update / write options in hash */
304
 
  opt->charset= create->default_table_charset;
305
 
 
306
 
end:
307
 
  pthread_rwlock_unlock(&LOCK_dboptions);
308
 
  return(error);
309
 
}
310
 
 
311
 
 
312
 
/*
313
 
  Deletes database options from the hash.
314
 
*/
315
 
 
316
 
void del_dbopt(const char *path)
317
 
{
318
 
  my_dbopt_t *opt;
319
 
  pthread_rwlock_wrlock(&LOCK_dboptions);
320
 
  if ((opt= (my_dbopt_t *)hash_search(&dboptions, (const unsigned char*) path,
321
 
                                      strlen(path))))
322
 
    hash_delete(&dboptions, (unsigned char*) opt);
323
 
  pthread_rwlock_unlock(&LOCK_dboptions);
324
 
}
325
 
 
326
 
 
327
 
/*
328
 
  Create database options file:
329
 
 
330
 
  DESCRIPTION
331
 
    Currently database default charset is only stored there.
332
 
 
333
 
  RETURN VALUES
334
 
  0     ok
335
 
  1     Could not create file or write to it.  Error sent through my_error()
336
 
*/
337
 
 
338
 
static bool write_db_opt(Session *session, const char *path, const char *name, HA_CREATE_INFO *create)
339
 
{
340
 
  bool error= true;
 
148
/**
 
149
  Return default database collation.
 
150
 
 
151
  @param session     Thread context.
 
152
  @param db_name Database name.
 
153
 
 
154
  @return CHARSET_INFO object. The operation always return valid character
 
155
    set, even if the database does not exist.
 
156
*/
 
157
 
 
158
const CHARSET_INFO *get_default_db_collation(Session *session, const char *db_name)
 
159
{
 
160
  HA_CREATE_INFO db_info;
 
161
 
 
162
  if (session->db != NULL && strcmp(db_name, session->db) == 0)
 
163
    return session->db_charset;
 
164
 
 
165
  /*
 
166
    db_info.default_table_charset contains valid character set
 
167
    (collation_server).
 
168
  */
 
169
 
 
170
  load_db_opt_by_name(session, db_name, &db_info);
 
171
 
 
172
  return db_info.default_table_charset;
 
173
}
 
174
 
 
175
/* path is path to database, not schema file */
 
176
static int write_schema_file(Session *session,
 
177
                             const char *path, const char *name,
 
178
                             HA_CREATE_INFO *create)
 
179
{
341
180
  drizzle::Schema db;
 
181
  char schema_file_tmp[FN_REFLEN];
 
182
  string schema_file(path);
342
183
 
 
184
  assert(path);
343
185
  assert(name);
 
186
  assert(create);
 
187
 
 
188
  snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path, FN_LIBCHAR, MY_DB_OPT_FILE);
 
189
 
 
190
  schema_file.append(1, FN_LIBCHAR);
 
191
  schema_file.append(MY_DB_OPT_FILE);
 
192
 
 
193
  int fd= mkstemp(schema_file_tmp);
 
194
 
 
195
  if (fd==-1)
 
196
    return errno;
344
197
 
345
198
  if (!create->default_table_charset)
346
199
    create->default_table_charset= session->variables.collation_server;
347
200
 
348
 
  if (put_dbopt(path, create))
349
 
    return 1;
350
 
 
351
201
  db.set_name(name);
352
 
  db.set_characterset(create->default_table_charset->csname);
353
202
  db.set_collation(create->default_table_charset->name);
354
203
 
355
 
  fstream output(path, ios::out | ios::trunc | ios::binary);
356
 
  if (!db.SerializeToOstream(&output))
357
 
    error= false;
358
 
 
359
 
  return error;
 
204
  if (!db.SerializeToFileDescriptor(fd))
 
205
  {
 
206
    close(fd);
 
207
    unlink(schema_file_tmp);
 
208
    return -1;
 
209
  }
 
210
 
 
211
  if (rename(schema_file_tmp, schema_file.c_str()) == -1)
 
212
  {
 
213
    close(fd);
 
214
    return errno;
 
215
  }
 
216
 
 
217
  close(fd);
 
218
  return 0;
360
219
}
361
220
 
362
 
 
363
 
/*
364
 
  Load database options file
365
 
 
366
 
  load_db_opt()
367
 
  path          Path for option file
368
 
  create        Where to store the read options
369
 
 
370
 
  DESCRIPTION
371
 
 
372
 
  RETURN VALUES
373
 
  0     File found
374
 
  1     No database file or could not open it
375
 
 
376
 
*/
377
 
 
378
 
bool load_db_opt(Session *session, const char *path, HA_CREATE_INFO *create)
 
221
int load_db_opt(Session *session, const char *path, HA_CREATE_INFO *create)
379
222
{
380
 
  bool error=1;
381
223
  drizzle::Schema db;
382
224
  string buffer;
383
225
 
384
226
  memset(create, 0, sizeof(*create));
385
227
  create->default_table_charset= session->variables.collation_server;
386
228
 
387
 
  /* Check if options for this database are already in the hash */
388
 
  if (!get_dbopt(path, create))
389
 
    return(0);
390
 
 
391
 
  fstream input(path, ios::in | ios::binary);
392
 
  if (!input)
393
 
    goto err1;
394
 
  else if (!db.ParseFromIstream(&input))
395
 
    goto err1;
396
 
 
397
 
  buffer= db.characterset();
398
 
  if (!(create->default_table_charset= get_charset_by_csname(buffer.c_str(), MY_CS_PRIMARY, MYF(0))))
 
229
  int fd= open(path, O_RDONLY);
 
230
 
 
231
  if (fd == -1)
 
232
    return errno;
 
233
 
 
234
  if (!db.ParseFromFileDescriptor(fd))
399
235
  {
400
 
    errmsg_printf(ERRMSG_LVL_ERROR, _("Error while loading database options: '%s':"),path);
401
 
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
402
 
    create->default_table_charset= default_charset_info;
 
236
    close(fd);
 
237
    return -1;
403
238
  }
 
239
  close(fd);
404
240
 
405
241
  buffer= db.collation();
406
 
  if (!(create->default_table_charset= get_charset_by_name(buffer.c_str(), MYF(0))))
 
242
  if (!(create->default_table_charset= get_charset_by_name(buffer.c_str(),
 
243
                                                           MYF(0))))
407
244
  {
408
 
    errmsg_printf(ERRMSG_LVL_ERROR, _("Error while loading database options: '%s':"),path);
 
245
    errmsg_printf(ERRMSG_LVL_ERROR,
 
246
                  _("Error while loading database options: '%s':"),path);
409
247
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
410
248
    create->default_table_charset= default_charset_info;
 
249
    return -1;
411
250
  }
412
251
 
413
 
  /*
414
 
    Put the loaded value into the hash.
415
 
    Note that another thread could've added the same
416
 
    entry to the hash after we called get_dbopt(),
417
 
    but it's not an error, as put_dbopt() takes this
418
 
    possibility into account.
419
 
  */
420
 
  error= put_dbopt(path, create);
421
 
 
422
 
err1:
423
 
  return(error);
 
252
  return 0;
424
253
}
425
254
 
426
 
 
427
 
/*
428
 
  Retrieve database options by name. Load database options file or fetch from
429
 
  cache.
430
 
 
431
 
  SYNOPSIS
432
 
    load_db_opt_by_name()
433
 
    db_name         Database name
434
 
    db_create_info  Where to store the database options
435
 
 
436
 
  DESCRIPTION
437
 
    load_db_opt_by_name() is a shortcut for load_db_opt().
438
 
 
439
 
  NOTE
440
 
    Although load_db_opt_by_name() (and load_db_opt()) returns status of
441
 
    the operation, it is useless usually and should be ignored. The problem
442
 
    is that there are 1) system databases ("mysql") and 2) virtual
443
 
    databases ("information_schema"), which do not contain options file.
444
 
    So, load_db_opt[_by_name]() returns false for these databases, but this
445
 
    is not an error.
446
 
 
447
 
    load_db_opt[_by_name]() clears db_create_info structure in any case, so
448
 
    even on failure it contains valid data. So, common use case is just
449
 
    call load_db_opt[_by_name]() without checking return value and use
450
 
    db_create_info right after that.
451
 
 
452
 
  RETURN VALUES (read NOTE!)
453
 
    false   Success
454
 
    true    Failed to retrieve options
455
 
*/
456
 
 
457
 
bool load_db_opt_by_name(Session *session, const char *db_name,
458
 
                         HA_CREATE_INFO *db_create_info)
 
255
int load_db_opt_by_name(Session *session, const char *db_name,
 
256
                        HA_CREATE_INFO *db_create_info)
459
257
{
460
258
  char db_opt_path[FN_REFLEN];
461
259
 
470
268
}
471
269
 
472
270
 
473
 
/**
474
 
  Return default database collation.
475
 
 
476
 
  @param session     Thread context.
477
 
  @param db_name Database name.
478
 
 
479
 
  @return CHARSET_INFO object. The operation always return valid character
480
 
    set, even if the database does not exist.
481
 
*/
482
 
 
483
 
const CHARSET_INFO *get_default_db_collation(Session *session, const char *db_name)
484
 
{
485
 
  HA_CREATE_INFO db_info;
486
 
 
487
 
  if (session->db != NULL && strcmp(db_name, session->db) == 0)
488
 
    return session->db_charset;
489
 
 
490
 
  load_db_opt_by_name(session, db_name, &db_info);
491
 
 
492
 
  /*
493
 
    NOTE: even if load_db_opt_by_name() fails,
494
 
    db_info.default_table_charset contains valid character set
495
 
    (collation_server). We should not fail if load_db_opt_by_name() fails,
496
 
    because it is valid case. If a database has been created just by
497
 
    "mkdir", it does not contain db.opt file, but it is valid database.
498
 
  */
499
 
 
500
 
  return db_info.default_table_charset;
501
 
}
502
 
 
503
 
 
504
271
/*
505
272
  Create a database
506
273
 
531
298
  char   tmp_query[FN_REFLEN+16];
532
299
  long result= 1;
533
300
  int error= 0;
534
 
  struct stat stat_info;
535
301
  uint32_t create_options= create_info ? create_info->options : 0;
536
302
  uint32_t path_len;
537
303
 
566
332
  path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
567
333
  path[path_len-1]= 0;                    // Remove last '/' from path
568
334
 
569
 
  if (!stat(path,&stat_info))
 
335
  if (mkdir(path,0777) == -1)
570
336
  {
571
 
    if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
 
337
    if (errno == EEXIST)
572
338
    {
573
 
      my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
574
 
      error= -1;
 
339
      if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
 
340
      {
 
341
        my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
 
342
        error= -1;
 
343
        goto exit;
 
344
      }
 
345
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
346
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
 
347
      if (!silent)
 
348
        my_ok(session);
 
349
      error= 0;
575
350
      goto exit;
576
351
    }
577
 
    push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
578
 
                        ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
579
 
    if (!silent)
580
 
      my_ok(session);
581
 
    error= 0;
 
352
 
 
353
    my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
 
354
    error= -1;
582
355
    goto exit;
583
356
  }
584
 
  else
585
 
  {
586
 
    if (errno != ENOENT)
587
 
    {
588
 
      my_error(EE_STAT, MYF(0), path, errno);
589
 
      goto exit;
590
 
    }
591
 
    if (mkdir(path,0777) < 0)
592
 
    {
593
 
      my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
594
 
      error= -1;
595
 
      goto exit;
596
 
    }
597
 
  }
598
357
 
599
 
  path[path_len-1]= FN_LIBCHAR;
600
 
  strncpy(path+path_len, MY_DB_OPT_FILE, sizeof(path)-path_len-1);
601
 
  if (write_db_opt(session, path, db, create_info))
 
358
  error= write_schema_file(session, path, db, create_info);
 
359
  if (error && error != EEXIST)
602
360
  {
603
 
    /*
604
 
      Could not create options file.
605
 
      Restore things to beginning.
606
 
    */
607
 
    path[path_len]= 0;
608
361
    if (rmdir(path) >= 0)
609
362
    {
610
363
      error= -1;
611
364
      goto exit;
612
365
    }
613
 
    /*
614
 
      We come here when we managed to create the database, but not the option
615
 
      file.  In this case it's best to just continue as if nothing has
616
 
      happened.  (This is a very unlikely senario)
617
 
    */
618
366
  }
619
367
 
620
368
  if (!silent)
649
397
 
650
398
bool mysql_alter_db(Session *session, const char *db, HA_CREATE_INFO *create_info)
651
399
{
652
 
  char path[FN_REFLEN+16];
653
400
  long result=1;
654
 
  int error= false;
 
401
  int error= 0;
 
402
  char   path[FN_REFLEN+16];
 
403
  uint32_t path_len;
655
404
 
656
405
  /*
657
406
    Do not alter database if another thread is holding read lock.
666
415
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
667
416
  */
668
417
  if ((error=wait_if_global_read_lock(session,0,1)))
669
 
    goto exit2;
 
418
    goto exit;
670
419
 
671
420
  pthread_mutex_lock(&LOCK_drizzle_create_db);
672
421
 
673
 
  /*
674
 
     Recreate db options file: /dbpath/.db.opt
675
 
     We pass MY_DB_OPT_FILE as "extension" to avoid
676
 
     "table name to file name" encoding.
677
 
  */
678
 
  build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE, 0);
679
 
  if ((error=write_db_opt(session, path, db, create_info)))
680
 
    goto exit;
681
 
 
682
422
  /* Change options if current database is being altered. */
 
423
  path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
 
424
  path[path_len-1]= 0;                    // Remove last '/' from path
 
425
 
 
426
  error= write_schema_file(session, path, db, create_info);
 
427
  if (error && error != EEXIST)
 
428
  {
 
429
    /* TODO: find some witty way of getting back an error message */
 
430
    pthread_mutex_unlock(&LOCK_drizzle_create_db);
 
431
    goto exit;
 
432
  }
683
433
 
684
434
  if (session->db && !strcmp(session->db,db))
685
435
  {
692
442
  (void)replicator_statement(session, session->query, session->query_length);
693
443
  my_ok(session, result);
694
444
 
695
 
exit:
696
445
  pthread_mutex_unlock(&LOCK_drizzle_create_db);
697
446
  start_waiting_global_read_lock(session);
698
 
exit2:
 
447
exit:
699
448
  return(error);
700
449
}
701
450
 
753
502
  pthread_mutex_lock(&LOCK_drizzle_create_db);
754
503
 
755
504
  length= build_table_filename(path, sizeof(path), db, "", "", 0);
756
 
  strcpy(path+length, MY_DB_OPT_FILE);          // Append db option file name
757
 
  del_dbopt(path);                              // Remove dboption hash entry
 
505
  strcpy(path+length, MY_DB_OPT_FILE);         // Append db option file name
 
506
  unlink(path);
758
507
  path[length]= '\0';                           // Remove file name
759
508
 
760
509
  /* See if the directory exists */