~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

  • Committer: Brian Aker
  • Date: 2011-01-03 18:49:27 UTC
  • mfrom: (2041.3.12 session-fix)
  • Revision ID: brian@tangent.org-20110103184927-2oso3g5g7g1gwb5m
Refactor drop schema so that it can be used for removing tables under
catalogs.

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
60
static void change_db_impl(Session *session);
64
61
static void change_db_impl(Session *session, SchemaIdentifier &schema_identifier);
65
62
 
217
214
 
218
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;
 
254
        error= true;
271
255
        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
 
      error= -1;
281
 
      deleted= drop_tables_via_filenames(session, schema_identifier, dropped_tables);
282
 
      if (deleted >= 0)
283
 
      {
284
 
        error= 0;
285
 
        
286
 
        /* We've already verified that the schema does exist, so safe to log it */
287
 
        TransactionServices &transaction_services= TransactionServices::singleton();
288
 
        transaction_services.dropSchema(session, schema_identifier.getSchemaName());
289
 
      }
290
 
    }
291
 
    if (deleted >= 0)
292
 
    {
293
 
      session->clear_error();
294
 
      session->server_status|= SERVER_STATUS_DB_DROPPED;
295
 
      session->my_ok((uint32_t) deleted);
296
 
      session->server_status&= ~SERVER_STATUS_DB_DROPPED;
297
 
    }
298
 
    else
299
 
    {
300
 
      char *query, *query_pos, *query_end, *query_data_start;
301
 
 
302
 
      if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
303
 
        goto exit; /* not much else we can do */
304
 
      query_pos= query_data_start= strcpy(query,"drop table ")+11;
305
 
      query_end= query + MAX_DROP_TABLE_Q_LEN;
306
 
 
307
 
      TransactionServices &transaction_services= TransactionServices::singleton();
308
 
      for (TableIdentifier::vector::iterator it= dropped_tables.begin();
309
 
           it != dropped_tables.end();
310
 
           it++)
311
 
      {
312
 
        uint32_t tbl_name_len;
313
 
 
314
 
        /* 3 for the quotes and the comma*/
315
 
        tbl_name_len= (*it).getTableName().length() + 3;
316
 
        if (query_pos + tbl_name_len + 1 >= query_end)
317
 
        {
318
 
          /* These DDL methods and logging protected with LOCK_create_db */
319
 
          transaction_services.rawStatement(session, query);
320
 
          query_pos= query_data_start;
321
 
        }
322
 
 
323
 
        *query_pos++ = '`';
324
 
        query_pos= strcpy(query_pos, (*it).getTableName().c_str()) + (tbl_name_len-3);
325
 
        *query_pos++ = '`';
326
 
        *query_pos++ = ',';
327
 
      }
328
 
 
329
 
      if (query_pos != query_data_start)
330
 
      {
331
 
        /* These DDL methods and logging protected with LOCK_create_db */
332
 
        transaction_services.rawStatement(session, query);
333
 
      }
334
 
    }
335
 
 
336
 
exit:
337
 
    /*
338
 
      If this database was the client's selected database, we silently
339
 
      change the client's selected database to nothing (to have an empty
340
 
      SELECT DATABASE() in the future). For this we free() session->db and set
341
 
      it to 0.
342
 
    */
343
 
    if (schema_identifier.compare(*session->schema()))
344
 
      change_db_impl(session);
345
 
  }
 
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);
346
274
 
347
275
  session->startWaitingGlobalReadLock();
348
276
 
349
277
  return error;
350
278
}
351
279
 
352
 
 
353
 
static int rm_table_part2(Session *session, TableList *tables)
354
 
{
355
 
  TransactionServices &transaction_services= TransactionServices::singleton();
356
 
 
357
 
  TableList *table;
358
 
  String wrong_tables;
359
 
  int error= 0;
360
 
  bool foreign_key_error= false;
361
 
 
362
 
  {
363
 
    table::Cache::singleton().mutex().lock(); /* Part 2 of rm a table */
364
 
 
365
 
    if (session->lock_table_names_exclusively(tables))
366
 
    {
367
 
      table::Cache::singleton().mutex().unlock();
368
 
      return 1;
369
 
    }
370
 
 
371
 
    /* Don't give warnings for not found errors, as we already generate notes */
372
 
    session->no_warnings_for_error= 1;
373
 
 
374
 
    for (table= tables; table; table= table->next_local)
375
 
    {
376
 
      const char *db=table->getSchemaName();
377
 
      TableIdentifier identifier(table->getSchemaName(), table->getTableName());
378
 
 
379
 
      plugin::StorageEngine *table_type;
380
 
 
381
 
      error= session->drop_temporary_table(identifier);
382
 
 
383
 
      switch (error) {
384
 
      case  0:
385
 
        // removed temporary table
386
 
        continue;
387
 
      case -1:
388
 
        error= 1;
389
 
        tables->unlock_table_names();
390
 
        table::Cache::singleton().mutex().unlock();
391
 
        session->no_warnings_for_error= 0;
392
 
 
393
 
        return(error);
394
 
      default:
395
 
        // temporary table not found
396
 
        error= 0;
397
 
      }
398
 
 
399
 
      table_type= table->getDbType();
400
 
 
401
 
      {
402
 
        Table *locked_table;
403
 
        abort_locked_tables(session, identifier);
404
 
        table::Cache::singleton().removeTable(session, identifier,
405
 
                                              RTFC_WAIT_OTHER_THREAD_FLAG |
406
 
                                              RTFC_CHECK_KILLED_FLAG);
407
 
        /*
408
 
          If the table was used in lock tables, remember it so that
409
 
          unlock_table_names can free it
410
 
        */
411
 
        if ((locked_table= drop_locked_tables(session, identifier)))
412
 
          table->table= locked_table;
413
 
 
414
 
        if (session->getKilled())
415
 
        {
416
 
          error= -1;
417
 
          tables->unlock_table_names();
418
 
          table::Cache::singleton().mutex().unlock();
419
 
          session->no_warnings_for_error= 0;
420
 
 
421
 
          return(error);
422
 
        }
423
 
      }
424
 
      identifier.getPath();
425
 
 
426
 
      if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
427
 
      {
428
 
        // Table was not found on disk and table can't be created from engine
429
 
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
430
 
                            ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
431
 
                            table->getTableName());
432
 
      }
433
 
      else
434
 
      {
435
 
        error= plugin::StorageEngine::dropTable(*session, identifier);
436
 
 
437
 
        /* Generate transaction event ONLY when we successfully drop */ 
438
 
        if (error == 0)
439
 
        {
440
 
          transaction_services.dropTable(session, string(db), string(table->getTableName()));
441
 
        }
442
 
 
443
 
        if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
444
 
        {
445
 
          error= 0;
446
 
          session->clear_error();
447
 
        }
448
 
 
449
 
        if (error == HA_ERR_ROW_IS_REFERENCED)
450
 
        {
451
 
          /* the table is referenced by a foreign key constraint */
452
 
          foreign_key_error= true;
453
 
        }
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