~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

merged with up to date trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
namespace drizzled
58
58
{
59
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);
 
60
static void change_db_impl(Session *session);
 
61
static void change_db_impl(Session *session, SchemaIdentifier &schema_identifier);
65
62
 
66
63
/*
67
64
  Create a database
68
65
 
69
66
  SYNOPSIS
70
 
  mysql_create_db()
 
67
  create_db()
71
68
  session               Thread handler
72
69
  db            Name of database to create
73
70
                Function assumes that this is already validated.
84
81
 
85
82
*/
86
83
 
87
 
bool mysql_create_db(Session *session, const message::Schema &schema_message, const bool is_if_not_exists)
 
84
bool create_db(Session *session, const message::Schema &schema_message, const bool is_if_not_exists)
88
85
{
89
86
  TransactionServices &transaction_services= TransactionServices::singleton();
90
87
  bool error= false;
119
116
    {
120
117
      if (not is_if_not_exists)
121
118
      {
122
 
        my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
 
119
        my_error(ER_DB_CREATE_EXISTS, schema_identifier);
123
120
        error= true;
124
121
      }
125
122
      else
149
146
 
150
147
/* db-name is already validated when we come here */
151
148
 
152
 
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
 
149
bool alter_db(Session *session, const message::Schema &schema_message)
153
150
{
154
151
  TransactionServices &transaction_services= TransactionServices::singleton();
155
152
 
175
172
    SchemaIdentifier schema_idenifier(schema_message.name());
176
173
    if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
177
174
    {
178
 
      my_error(ER_SCHEMA_DOES_NOT_EXIST, MYF(0), schema_message.name().c_str());
 
175
      my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
179
176
      return false;
180
177
    }
181
178
 
189
186
    }
190
187
    else
191
188
    {
192
 
      my_error(ER_ALTER_SCHEMA, MYF(0), schema_message.name().c_str());
 
189
      my_error(ER_ALTER_SCHEMA, schema_idenifier);
193
190
    }
194
191
  }
195
192
  session->startWaitingGlobalReadLock();
202
199
  Drop all tables in a database and the database itself
203
200
 
204
201
  SYNOPSIS
205
 
    mysql_rm_db()
 
202
    rm_db()
206
203
    session                     Thread handle
207
204
    db                  Database name in the case given by user
208
205
                        It's already validated and set to lower case
215
212
    ERROR Error
216
213
*/
217
214
 
218
 
bool mysql_rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
 
215
bool rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
219
216
{
220
 
  long deleted=0;
221
 
  int error= false;
222
 
  TableIdentifier::vector dropped_tables;
223
 
  message::Schema schema_proto;
 
217
  bool error= false;
224
218
 
225
219
  /*
226
220
    Do not drop database if another thread is holding read lock.
236
230
  */
237
231
  if (session->wait_if_global_read_lock(false, true))
238
232
  {
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
 
 
 
233
    return true;
 
234
  }
 
235
 
 
236
  do
253
237
  {
254
238
    boost::mutex::scoped_lock scopedLock(LOCK_create_db);
255
239
 
267
251
      }
268
252
      else
269
253
      {
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
 
 
281
 
      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)
331
 
      {
332
 
        /* These DDL methods and logging protected with LOCK_create_db */
333
 
        transaction_services.rawStatement(session, query);
334
 
      }
335
 
    }
336
 
 
337
 
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
 
  }
 
254
        error= true;
 
255
        my_error(ER_DB_DROP_EXISTS, schema_identifier);
 
256
        break;
 
257
      }
 
258
    }
 
259
    else
 
260
    {
 
261
      error= plugin::StorageEngine::dropSchema(*session, schema_identifier);
 
262
    }
 
263
 
 
264
  } while (0);
 
265
 
 
266
  /*
 
267
    If this database was the client's selected database, we silently
 
268
    change the client's selected database to nothing (to have an empty
 
269
    SELECT DATABASE() in the future). For this we free() session->db and set
 
270
    it to 0.
 
271
  */
 
272
  if (not error and schema_identifier.compare(*session->schema()))
 
273
    change_db_impl(session);
347
274
 
348
275
  session->startWaitingGlobalReadLock();
349
276
 
350
277
  return error;
351
278
}
352
279
 
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
 
 
489
 
  return(error);
490
 
}
491
 
 
492
 
/*
493
 
  Removes files with known extensions plus.
494
 
  session MUST be set when calling this function!
495
 
*/
496
 
 
497
 
static long drop_tables_via_filenames(Session *session,
498
 
                                      SchemaIdentifier &schema_identifier,
499
 
                                      TableIdentifier::vector &dropped_tables)
500
 
{
501
 
  long deleted= 0;
502
 
  TableList *tot_list= NULL, **tot_list_next;
503
 
 
504
 
  tot_list_next= &tot_list;
505
 
 
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
 
}
556
 
 
557
280
/**
558
281
  @brief Change the current database and its attributes unconditionally.
559
282
 
616
339
    @retval true  Error
617
340
*/
618
341
 
619
 
bool mysql_change_db(Session *session, SchemaIdentifier &schema_identifier)
 
342
bool change_db(Session *session, SchemaIdentifier &schema_identifier)
620
343
{
621
344
 
622
 
  if (not plugin::Authorization::isAuthorized(session->getSecurityContext(), schema_identifier))
 
345
  if (not plugin::Authorization::isAuthorized(session->user(), schema_identifier))
623
346
  {
624
347
    /* Error message is set in isAuthorized */
625
348
    return true;
629
352
  {
630
353
    std::string path;
631
354
    schema_identifier.getSQLPath(path);
632
 
    my_error(ER_WRONG_DB_NAME, MYF(0), path.c_str());
 
355
    my_error(ER_WRONG_DB_NAME, schema_identifier);
633
356
 
634
357
    return true;
635
358
  }
636
359
 
637
360
  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
638
361
  {
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());
 
362
    my_error(ER_BAD_DB_ERROR, schema_identifier);
644
363
 
645
364
    /* The operation failed. */
646
365
 
647
366
    return true;
648
367
  }
649
368
 
650
 
  mysql_change_db_impl(session, schema_identifier);
 
369
  change_db_impl(session, schema_identifier);
651
370
 
652
371
  return false;
653
372
}
663
382
  @param new_db_charset Character set of the new database.
664
383
*/
665
384
 
666
 
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier)
 
385
static void change_db_impl(Session *session, SchemaIdentifier &schema_identifier)
667
386
{
668
387
  /* 1. Change current database in Session. */
669
388
 
690
409
  }
691
410
}
692
411
 
693
 
static void mysql_change_db_impl(Session *session)
 
412
static void change_db_impl(Session *session)
694
413
{
695
414
  session->set_db(string());
696
415
}