~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

  • Committer: lbieber
  • Date: 2010-01-21 18:21:39 UTC
  • mto: This revision was merged to the branch mainline in revision 1277.
  • Revision ID: lbieber@orisndriz08-20100121182139-h549us3gsysyyl0e
clean up japanese tests, remove tests that no longer apply.  In test-run.pl change mysql_version_id to drizzle_version_id

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 */
26
26
#include <fstream>
27
27
 
28
28
#include <drizzled/message/schema.pb.h>
29
 
#include "drizzled/error.h"
 
29
#include "drizzled/my_error.h"
 
30
#include <drizzled/error.h>
30
31
#include <drizzled/gettext.h>
31
32
#include <drizzled/my_hash.h>
32
33
#include "drizzled/internal/m_string.h"
35
36
#include <drizzled/sql_base.h>
36
37
#include <drizzled/lock.h>
37
38
#include <drizzled/errmsg_print.h>
38
 
#include <drizzled/transaction_services.h>
 
39
#include <drizzled/replication_services.h>
39
40
#include <drizzled/message/schema.pb.h>
40
41
#include "drizzled/sql_table.h"
41
 
#include "drizzled/plugin/storage_engine.h"
42
 
#include "drizzled/plugin/authorization.h"
 
42
#include "drizzled/plugin/info_schema_table.h"
43
43
#include "drizzled/global_charset_info.h"
44
44
#include "drizzled/pthread_globals.h"
45
45
#include "drizzled/charset.h"
46
46
 
47
 
#include <boost/thread/mutex.hpp>
48
 
 
49
 
boost::mutex LOCK_create_db;
50
 
 
51
47
#include "drizzled/internal/my_sys.h"
52
48
 
 
49
using namespace std;
 
50
using namespace drizzled;
 
51
 
 
52
#define MY_DB_OPT_FILE "db.opt"
53
53
#define MAX_DROP_TABLE_Q_LEN      1024
54
54
 
55
 
using namespace std;
56
 
 
57
 
namespace drizzled
58
 
{
59
 
 
60
 
static long drop_tables_via_filenames(Session *session,
61
 
                                 SchemaIdentifier &schema_identifier,
62
 
                                 TableIdentifier::vector &dropped_tables);
63
 
static void mysql_change_db_impl(Session *session);
64
 
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier);
 
55
const string del_exts[]= {".dfe", ".blk", ".arz", ".BAK", ".TMD", ".opt"};
 
56
static set<string> deletable_extentions(del_exts, &del_exts[sizeof(del_exts)/sizeof(del_exts[0])]);
 
57
 
 
58
 
 
59
static long mysql_rm_known_files(Session *session, CachedDirectory &dirp,
 
60
                                 const string &db, const char *path,
 
61
                                 TableList **dropped_tables);
 
62
 
 
63
/**
 
64
  Return default database collation.
 
65
 
 
66
  @param session     Thread context.
 
67
  @param db_name Database name.
 
68
 
 
69
  @return CHARSET_INFO object. The operation always return valid character
 
70
    set, even if the database does not exist.
 
71
*/
 
72
 
 
73
const CHARSET_INFO *get_default_db_collation(const char *db_name)
 
74
{
 
75
  message::Schema db;
 
76
 
 
77
  get_database_metadata(db_name, &db);
 
78
 
 
79
  /* If for some reason the db.opt file lacks a collation,
 
80
     we just return the default */
 
81
 
 
82
  if (db.has_collation())
 
83
  {
 
84
    const string buffer= db.collation();
 
85
    const CHARSET_INFO* cs= get_charset_by_name(buffer.c_str());
 
86
 
 
87
    if (!cs)
 
88
    {
 
89
      errmsg_printf(ERRMSG_LVL_ERROR,
 
90
                    _("Error while loading database options: '%s':"),db_name);
 
91
      errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
 
92
 
 
93
      return default_charset_info;
 
94
    }
 
95
 
 
96
    return cs;
 
97
  }
 
98
 
 
99
  return default_charset_info;
 
100
}
 
101
 
 
102
/* path is path to database, not schema file */
 
103
static int write_schema_file(const DatabasePathName &path, const message::Schema &db)
 
104
{
 
105
  char schema_file_tmp[FN_REFLEN];
 
106
  string schema_file(path.to_string());
 
107
 
 
108
  snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path.to_string().c_str(), FN_LIBCHAR, MY_DB_OPT_FILE);
 
109
 
 
110
  schema_file.append(1, FN_LIBCHAR);
 
111
  schema_file.append(MY_DB_OPT_FILE);
 
112
 
 
113
  int fd= mkstemp(schema_file_tmp);
 
114
 
 
115
  if (fd==-1)
 
116
    return errno;
 
117
 
 
118
 
 
119
  if (!db.SerializeToFileDescriptor(fd))
 
120
  {
 
121
    close(fd);
 
122
    unlink(schema_file_tmp);
 
123
    return -1;
 
124
  }
 
125
 
 
126
  if (rename(schema_file_tmp, schema_file.c_str()) == -1)
 
127
  {
 
128
    close(fd);
 
129
    return errno;
 
130
  }
 
131
 
 
132
  close(fd);
 
133
  return 0;
 
134
}
 
135
 
 
136
int get_database_metadata(const char *dbname, message::Schema *db)
 
137
{
 
138
  char db_opt_path[FN_REFLEN];
 
139
  size_t length;
 
140
 
 
141
  /*
 
142
    Pass an empty file name, and the database options file name as extension
 
143
    to avoid table name to file name encoding.
 
144
  */
 
145
  length= build_table_filename(db_opt_path, sizeof(db_opt_path),
 
146
                              dbname, "", false);
 
147
  strcpy(db_opt_path + length, MY_DB_OPT_FILE);
 
148
 
 
149
  int fd= open(db_opt_path, O_RDONLY);
 
150
 
 
151
  if (fd == -1)
 
152
    return errno;
 
153
 
 
154
  if (!db->ParseFromFileDescriptor(fd))
 
155
  {
 
156
    close(fd);
 
157
    return -1;
 
158
  }
 
159
  close(fd);
 
160
 
 
161
  return 0;
 
162
}
65
163
 
66
164
/*
67
165
  Create a database
84
182
 
85
183
*/
86
184
 
87
 
bool mysql_create_db(Session *session, const message::Schema &schema_message, const bool is_if_not_exists)
 
185
bool mysql_create_db(Session *session, const NormalisedDatabaseName &database_name, message::Schema *schema_message, bool is_if_not_exists)
88
186
{
89
 
  TransactionServices &transaction_services= TransactionServices::singleton();
 
187
  ReplicationServices &replication_services= ReplicationServices::singleton();
 
188
  long result= 1;
 
189
  int error_erno;
90
190
  bool error= false;
 
191
  DatabasePathName database_path(database_name);
 
192
 
 
193
  /* do not create 'information_schema' db */
 
194
  if (!my_strcasecmp(system_charset_info, database_name.to_string().c_str(), INFORMATION_SCHEMA_NAME.c_str()))
 
195
  {
 
196
    my_error(ER_DB_CREATE_EXISTS, MYF(0), database_name.to_string().c_str());
 
197
    return(-1);
 
198
  }
 
199
 
 
200
  assert(database_name.isValid());
 
201
  schema_message->set_name(database_name.to_string());
91
202
 
92
203
  /*
93
204
    Do not create database if another thread is holding read lock.
101
212
    has the global read lock and refuses the operation with
102
213
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
103
214
  */
104
 
  if (session->wait_if_global_read_lock(false, true))
 
215
  if (wait_if_global_read_lock(session, 0, 1))
105
216
  {
106
 
    return false;
 
217
    error= true;
 
218
    goto exit2;
107
219
  }
108
220
 
109
 
  assert(schema_message.has_name());
110
 
  assert(schema_message.has_collation());
 
221
  pthread_mutex_lock(&LOCK_create_db);
111
222
 
112
 
  // @todo push this lock down into the engine
 
223
  if (mkdir(database_path.to_string().c_str(),0777) == -1)
113
224
  {
114
 
    boost::mutex::scoped_lock scopedLock(LOCK_create_db);
115
 
 
116
 
    // Check to see if it exists already.  
117
 
    SchemaIdentifier schema_identifier(schema_message.name());
118
 
    if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
 
225
    if (errno == EEXIST)
119
226
    {
120
 
      if (not is_if_not_exists)
121
 
      {
122
 
        my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
123
 
        error= true;
124
 
      }
125
 
      else
126
 
      {
127
 
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
128
 
                            ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
129
 
                            schema_message.name().c_str());
130
 
        session->my_ok();
131
 
      }
 
227
      if (! is_if_not_exists)
 
228
      {
 
229
        my_error(ER_DB_CREATE_EXISTS, MYF(0), database_name.to_string().c_str());
 
230
        error= true;
 
231
        goto exit;
 
232
      }
 
233
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
234
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
 
235
                          database_name.to_string().c_str());
 
236
      session->my_ok();
 
237
      error= false;
 
238
      goto exit;
132
239
    }
133
 
    else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it 
 
240
 
 
241
    my_error(ER_CANT_CREATE_DB, MYF(0), database_name.to_string().c_str(), errno);
 
242
    error= true;
 
243
    goto exit;
 
244
  }
 
245
 
 
246
  error_erno= write_schema_file(database_path, *schema_message);
 
247
  if (error_erno && error_erno != EEXIST)
 
248
  {
 
249
    if (rmdir(database_path.to_string().c_str()) >= 0)
134
250
    {
135
 
      my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
136
251
      error= true;
137
 
    }
138
 
    else // Created !
139
 
    {
140
 
      transaction_services.createSchema(session, schema_message);
141
 
      session->my_ok(1);
 
252
      goto exit;
142
253
    }
143
254
  }
144
 
  session->startWaitingGlobalReadLock();
145
 
 
 
255
  else if (error_erno)
 
256
    error= true;
 
257
 
 
258
  replication_services.rawStatement(session, session->query, session->query_length);
 
259
  session->my_ok(result);
 
260
 
 
261
exit:
 
262
  pthread_mutex_unlock(&LOCK_create_db);
 
263
  start_waiting_global_read_lock(session);
 
264
exit2:
146
265
  return error;
147
266
}
148
267
 
149
268
 
150
269
/* db-name is already validated when we come here */
151
270
 
152
 
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
 
271
bool mysql_alter_db(Session *session, const NormalisedDatabaseName &database_name, message::Schema *schema_message)
153
272
{
154
 
  TransactionServices &transaction_services= TransactionServices::singleton();
 
273
  ReplicationServices &replication_services= ReplicationServices::singleton();
 
274
  long result=1;
 
275
  int error= 0;
 
276
  DatabasePathName database_path(database_name);
155
277
 
156
278
  /*
157
279
    Do not alter database if another thread is holding read lock.
165
287
    has the global read lock and refuses the operation with
166
288
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
167
289
  */
168
 
  if ((session->wait_if_global_read_lock(false, true)))
169
 
    return false;
170
 
 
171
 
  bool success;
 
290
  if ((error=wait_if_global_read_lock(session,0,1)))
 
291
    goto exit;
 
292
 
 
293
  assert(schema_message);
 
294
  assert(database_name.isValid());
 
295
 
 
296
  schema_message->set_name(database_name.to_string());
 
297
 
 
298
  pthread_mutex_lock(&LOCK_create_db);
 
299
 
 
300
  error= write_schema_file(database_path, *schema_message);
 
301
  if (error && error != EEXIST)
172
302
  {
173
 
    boost::mutex::scoped_lock scopedLock(LOCK_create_db);
174
 
 
175
 
    SchemaIdentifier schema_idenifier(schema_message.name());
176
 
    if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
177
 
    {
178
 
      my_error(ER_SCHEMA_DOES_NOT_EXIST, MYF(0), schema_message.name().c_str());
179
 
      return false;
180
 
    }
181
 
 
182
 
    /* Change options if current database is being altered. */
183
 
    success= plugin::StorageEngine::alterSchema(schema_message);
184
 
 
185
 
    if (success)
186
 
    {
187
 
      transaction_services.rawStatement(session, *session->getQueryString());
188
 
      session->my_ok(1);
189
 
    }
190
 
    else
191
 
    {
192
 
      my_error(ER_ALTER_SCHEMA, MYF(0), schema_message.name().c_str());
193
 
    }
 
303
    /* TODO: find some witty way of getting back an error message */
 
304
    pthread_mutex_unlock(&LOCK_create_db);
 
305
    goto exit;
194
306
  }
195
 
  session->startWaitingGlobalReadLock();
196
 
 
197
 
  return success;
 
307
 
 
308
  replication_services.rawStatement(session, session->getQueryString(), session->getQueryLength());
 
309
  session->my_ok(result);
 
310
 
 
311
  pthread_mutex_unlock(&LOCK_create_db);
 
312
  start_waiting_global_read_lock(session);
 
313
exit:
 
314
  return error ? true : false;
198
315
}
199
316
 
200
317
 
215
332
    ERROR Error
216
333
*/
217
334
 
218
 
bool mysql_rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
 
335
bool mysql_rm_db(Session *session, const NormalisedDatabaseName &database_name, bool if_exists)
219
336
{
220
337
  long deleted=0;
221
338
  int error= false;
222
 
  TableIdentifier::vector dropped_tables;
223
 
  message::Schema schema_proto;
 
339
  char  path[FN_REFLEN+16];
 
340
  uint32_t length;
 
341
  TableList *dropped_tables= NULL;
 
342
 
 
343
  if (database_name.to_string().compare(INFORMATION_SCHEMA_NAME) == 0)
 
344
  {
 
345
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
 
346
    return true;
 
347
  }
224
348
 
225
349
  /*
226
350
    Do not drop database if another thread is holding read lock.
234
358
    has the global read lock and refuses the operation with
235
359
    ER_CANT_UPDATE_WITH_READLOCK if applicable.
236
360
  */
237
 
  if (session->wait_if_global_read_lock(false, true))
 
361
  if (wait_if_global_read_lock(session, 0, 1))
238
362
  {
239
363
    return -1;
240
364
  }
241
365
 
242
 
  // Lets delete the temporary tables first outside of locks.  
243
 
  set<string> set_of_names;
244
 
  session->doGetTableNames(schema_identifier, set_of_names);
245
 
 
246
 
  for (set<string>::iterator iter= set_of_names.begin(); iter != set_of_names.end(); iter++)
247
 
  {
248
 
    TableIdentifier identifier(schema_identifier, *iter, message::Table::TEMPORARY);
249
 
    Table *table= session->find_temporary_table(identifier);
250
 
    session->close_temporary_table(table);
251
 
  }
252
 
 
253
 
  {
254
 
    boost::mutex::scoped_lock scopedLock(LOCK_create_db);
255
 
 
256
 
    /* See if the schema exists */
257
 
    if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
258
 
    {
259
 
      std::string path;
260
 
      schema_identifier.getSQLPath(path);
261
 
 
262
 
      if (if_exists)
263
 
      {
264
 
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
265
 
                            ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
266
 
                            path.c_str());
267
 
      }
268
 
      else
269
 
      {
270
 
        error= -1;
271
 
        my_error(ER_DB_DROP_EXISTS, MYF(0), path.c_str());
272
 
        goto exit;
273
 
      }
274
 
    }
275
 
    else
276
 
    {
277
 
      /* After deleting database, remove all cache entries related to schema */
278
 
      table::Cache::singleton().removeSchema(schema_identifier);
279
 
 
280
 
 
 
366
  pthread_mutex_lock(&LOCK_create_db);
 
367
 
 
368
  length= build_table_filename(path, sizeof(path),
 
369
                               database_name.to_string().c_str(), "", false);
 
370
  strcpy(path+length, MY_DB_OPT_FILE);         // Append db option file name
 
371
  unlink(path);
 
372
  path[length]= '\0';                           // Remove file name
 
373
 
 
374
  /* See if the directory exists */
 
375
  CachedDirectory dirp(path);
 
376
  if (dirp.fail())
 
377
  {
 
378
    if (!if_exists)
 
379
    {
281
380
      error= -1;
282
 
      deleted= drop_tables_via_filenames(session, schema_identifier, dropped_tables);
283
 
      if (deleted >= 0)
284
 
      {
285
 
        error= 0;
286
 
      }
 
381
      my_error(ER_DB_DROP_EXISTS, MYF(0), database_name.to_string().c_str());
 
382
      goto exit;
287
383
    }
 
384
    else
 
385
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
386
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
 
387
                          database_name.to_string().c_str());
 
388
  }
 
389
  else
 
390
  {
 
391
    pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
 
392
    remove_db_from_cache(database_name.to_string().c_str());
 
393
    pthread_mutex_unlock(&LOCK_open);
 
394
 
 
395
 
 
396
    error= -1;
 
397
    deleted= mysql_rm_known_files(session, dirp,
 
398
                                  database_name.to_string(),
 
399
                                  path, &dropped_tables);
288
400
    if (deleted >= 0)
289
401
    {
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;
 
402
      plugin::StorageEngine::dropDatabase(path);
 
403
      error = 0;
298
404
    }
299
 
    else
 
405
  }
 
406
  if (deleted >= 0)
 
407
  {
 
408
    const char *query;
 
409
    uint32_t query_length;
 
410
 
 
411
    assert(session->query);
 
412
 
 
413
    query= session->query;
 
414
    query_length= session->query_length;
 
415
 
 
416
    ReplicationServices &replication_services= ReplicationServices::singleton();
 
417
    replication_services.rawStatement(session, session->getQueryString(), session->getQueryLength());
 
418
    session->clear_error();
 
419
    session->server_status|= SERVER_STATUS_DB_DROPPED;
 
420
    session->my_ok((uint32_t) deleted);
 
421
    session->server_status&= ~SERVER_STATUS_DB_DROPPED;
 
422
  }
 
423
  else
 
424
  {
 
425
    char *query, *query_pos, *query_end, *query_data_start;
 
426
    TableList *tbl;
 
427
    uint32_t db_len;
 
428
 
 
429
    if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
 
430
      goto exit; /* not much else we can do */
 
431
    query_pos= query_data_start= strcpy(query,"drop table ")+11;
 
432
    query_end= query + MAX_DROP_TABLE_Q_LEN;
 
433
    db_len= database_name.to_string().length();
 
434
 
 
435
    ReplicationServices &replication_services= ReplicationServices::singleton();
 
436
    for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
300
437
    {
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)
 
438
      uint32_t tbl_name_len;
 
439
 
 
440
      /* 3 for the quotes and the comma*/
 
441
      tbl_name_len= strlen(tbl->table_name) + 3;
 
442
      if (query_pos + tbl_name_len + 1 >= query_end)
331
443
      {
332
444
        /* These DDL methods and logging protected with LOCK_create_db */
333
 
        transaction_services.rawStatement(session, query);
 
445
        replication_services.rawStatement(session, query, (size_t) (query_pos -1 - query));
 
446
        query_pos= query_data_start;
334
447
      }
335
 
    }
 
448
 
 
449
      *query_pos++ = '`';
 
450
      query_pos= strcpy(query_pos,tbl->table_name) + (tbl_name_len-3);
 
451
      *query_pos++ = '`';
 
452
      *query_pos++ = ',';
 
453
    }
 
454
 
 
455
    if (query_pos != query_data_start)
 
456
    {
 
457
      /* These DDL methods and logging protected with LOCK_create_db */
 
458
      replication_services.rawStatement(session, query, (size_t) (query_pos -1 - query));
 
459
    }
 
460
  }
336
461
 
337
462
exit:
338
 
    /*
339
 
      If this database was the client's selected database, we silently
340
 
      change the client's selected database to nothing (to have an empty
341
 
      SELECT DATABASE() in the future). For this we free() session->db and set
342
 
      it to 0.
343
 
    */
344
 
    if (schema_identifier.compare(*session->schema()))
345
 
      mysql_change_db_impl(session);
346
 
  }
347
 
 
348
 
  session->startWaitingGlobalReadLock();
349
 
 
 
463
  /*
 
464
    If this database was the client's selected database, we silently
 
465
    change the client's selected database to nothing (to have an empty
 
466
    SELECT DATABASE() in the future). For this we free() session->db and set
 
467
    it to 0.
 
468
  */
 
469
  if (! session->db.empty() && session->db.compare(database_name.to_string()) == 0)
 
470
    session->clear_db();
 
471
  pthread_mutex_unlock(&LOCK_create_db);
 
472
  start_waiting_global_read_lock(session);
350
473
  return error;
351
474
}
352
475
 
353
476
 
354
477
static int rm_table_part2(Session *session, TableList *tables)
355
478
{
356
 
  TransactionServices &transaction_services= TransactionServices::singleton();
357
 
 
358
479
  TableList *table;
359
480
  String wrong_tables;
360
481
  int error= 0;
361
482
  bool foreign_key_error= false;
362
483
 
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
 
 
 
484
  pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
 
485
 
 
486
  /*
 
487
    If we have the table in the definition cache, we don't have to check the
 
488
    .frm cursor to find if the table is a normal table (not view) and what
 
489
    engine to use.
 
490
  */
 
491
 
 
492
  for (table= tables; table; table= table->next_local)
 
493
  {
 
494
    TableShare *share;
 
495
    table->db_type= NULL;
 
496
    if ((share= TableShare::getShare(table->db, table->table_name)))
 
497
      table->db_type= share->db_type();
 
498
  }
 
499
 
 
500
  if (lock_table_names_exclusively(session, tables))
 
501
  {
 
502
    pthread_mutex_unlock(&LOCK_open);
 
503
    return 1;
 
504
  }
 
505
 
 
506
  /* Don't give warnings for not found errors, as we already generate notes */
 
507
  session->no_warnings_for_error= 1;
 
508
 
 
509
  for (table= tables; table; table= table->next_local)
 
510
  {
 
511
    char *db=table->db;
 
512
    plugin::StorageEngine *table_type;
 
513
 
 
514
    error= session->drop_temporary_table(table);
 
515
 
 
516
    switch (error) {
 
517
    case  0:
 
518
      // removed temporary table
 
519
      continue;
 
520
    case -1:
 
521
      error= 1;
 
522
      goto err_with_placeholders;
 
523
    default:
 
524
      // temporary table not found
 
525
      error= 0;
 
526
    }
 
527
 
 
528
    table_type= table->db_type;
 
529
 
 
530
    {
 
531
      Table *locked_table;
 
532
      abort_locked_tables(session, db, table->table_name);
 
533
      remove_table_from_cache(session, db, table->table_name,
 
534
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
535
                              RTFC_CHECK_KILLED_FLAG);
 
536
      /*
 
537
        If the table was used in lock tables, remember it so that
 
538
        unlock_table_names can free it
 
539
      */
 
540
      if ((locked_table= drop_locked_tables(session, db, table->table_name)))
 
541
        table->table= locked_table;
 
542
 
 
543
      if (session->killed)
 
544
      {
 
545
        error= -1;
 
546
        goto err_with_placeholders;
 
547
      }
 
548
    }
 
549
 
 
550
    TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? INTERNAL_TMP_TABLE : NO_TMP_TABLE);
 
551
 
 
552
    if ((table_type == NULL
 
553
          && (plugin::StorageEngine::getTableDefinition(*session,
 
554
                                                        identifier) != EEXIST)))
 
555
    {
 
556
      // Table was not found on disk and table can't be created from engine
 
557
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
558
                          ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 
559
                          table->table_name);
 
560
    }
 
561
    else
 
562
    {
 
563
      error= plugin::StorageEngine::dropTable(*session,
 
564
                                              identifier,
 
565
                                              false);
 
566
 
 
567
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
 
568
      {
 
569
        error= 0;
 
570
        session->clear_error();
 
571
      }
 
572
 
 
573
      if (error == HA_ERR_ROW_IS_REFERENCED)
 
574
      {
 
575
        /* the table is referenced by a foreign key constraint */
 
576
        foreign_key_error= true;
 
577
      }
 
578
    }
 
579
 
 
580
    if (error == 0 || (foreign_key_error == false))
 
581
        write_bin_log_drop_table(session, true, db, table->table_name);
 
582
 
 
583
    if (error)
 
584
    {
 
585
      if (wrong_tables.length())
 
586
        wrong_tables.append(',');
 
587
      wrong_tables.append(String(table->table_name,system_charset_info));
 
588
    }
 
589
  }
 
590
  /*
 
591
    It's safe to unlock LOCK_open: we have an exclusive lock
 
592
    on the table name.
 
593
  */
 
594
  pthread_mutex_unlock(&LOCK_open);
470
595
  error= 0;
471
596
  if (wrong_tables.length())
472
597
  {
473
 
    if (not foreign_key_error)
 
598
    if (!foreign_key_error)
474
599
      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
475
600
                      wrong_tables.c_ptr());
476
601
    else
480
605
    error= 1;
481
606
  }
482
607
 
483
 
  {
484
 
    boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* final bit in rm table lock */
485
 
    tables->unlock_table_names();
486
 
  }
 
608
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
 
609
err_with_placeholders:
 
610
  unlock_table_names(tables, NULL);
 
611
  pthread_mutex_unlock(&LOCK_open);
487
612
  session->no_warnings_for_error= 0;
488
613
 
489
614
  return(error);
494
619
  session MUST be set when calling this function!
495
620
*/
496
621
 
497
 
static long drop_tables_via_filenames(Session *session,
498
 
                                      SchemaIdentifier &schema_identifier,
499
 
                                      TableIdentifier::vector &dropped_tables)
 
622
static long mysql_rm_known_files(Session *session, CachedDirectory &dirp,
 
623
                                 const string &db,
 
624
                                 const char *org_path,
 
625
                                 TableList **dropped_tables)
500
626
{
 
627
 
 
628
 
501
629
  long deleted= 0;
 
630
  char filePath[FN_REFLEN];
502
631
  TableList *tot_list= NULL, **tot_list_next;
503
632
 
504
633
  tot_list_next= &tot_list;
505
634
 
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++)
 
635
  for (CachedDirectory::Entries::const_iterator iter= dirp.getEntries().begin();
 
636
       iter != dirp.getEntries().end() && !session->killed;
 
637
       ++iter)
511
638
  {
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++;
 
639
    string filename((*iter)->filename);
 
640
 
 
641
    /* skiping . and .. */
 
642
    if (filename[0] == '.' && (!filename[1] ||
 
643
       (filename[1] == '.' &&  !filename[2])))
 
644
      continue;
 
645
 
 
646
    string extension("");
 
647
    size_t ext_pos= filename.rfind('.');
 
648
    if (ext_pos != string::npos)
 
649
    {
 
650
      extension= filename.substr(ext_pos);
 
651
    }
 
652
    if (deletable_extentions.find(extension) == deletable_extentions.end())
 
653
    {
 
654
      /*
 
655
        ass ass ass.
 
656
 
 
657
        strange checking for magic extensions that are then deleted if
 
658
        not reg_ext (i.e. .frm).
 
659
 
 
660
        and (previously) we'd err out on drop database if files not matching
 
661
        engine ha_known_exts() or deletable_extensions were present.
 
662
 
 
663
        presumably this was to avoid deleting other user data... except if that
 
664
        data happened to be in files ending in .BAK, .opt or .TMD. *fun*
 
665
       */
 
666
      continue;
 
667
    }
 
668
    /* just for safety we use files_charset_info */
 
669
    if (!my_strcasecmp(files_charset_info, extension.c_str(), ".dfe"))
 
670
    {
 
671
      size_t db_len= db.size();
 
672
 
 
673
      /* Drop the table nicely */
 
674
      filename.erase(ext_pos);
 
675
      TableList *table_list=(TableList*)
 
676
                             session->calloc(sizeof(*table_list) +
 
677
                                             db_len + 1 +
 
678
                                             filename.size() + 1);
 
679
 
 
680
      if (!table_list)
 
681
        return -1;
 
682
      table_list->db= (char*) (table_list+1);
 
683
      table_list->table_name= strcpy(table_list->db, db.c_str()) + db_len + 1;
 
684
      filename_to_tablename(filename.c_str(), table_list->table_name,
 
685
                            filename.size() + 1);
 
686
      table_list->alias= table_list->table_name;  // If lower_case_table_names=2
 
687
      table_list->internal_tmp_table= (strncmp(filename.c_str(),
 
688
                                               TMP_FILE_PREFIX,
 
689
                                               strlen(TMP_FILE_PREFIX)) == 0);
 
690
      /* Link into list */
 
691
      (*tot_list_next)= table_list;
 
692
      tot_list_next= &table_list->next_local;
 
693
      deleted++;
 
694
    }
 
695
    else
 
696
    {
 
697
      sprintf(filePath, "%s/%s", org_path, filename.c_str());
 
698
      if (my_delete_with_symlink(filePath,MYF(MY_WME)))
 
699
      {
 
700
        return -1;
 
701
      }
 
702
    }
534
703
  }
535
 
  if (session->getKilled())
 
704
  if (session->killed)
536
705
    return -1;
537
706
 
538
707
  if (tot_list)
541
710
      return -1;
542
711
  }
543
712
 
 
713
  if (dropped_tables)
 
714
    *dropped_tables= tot_list;
544
715
 
545
 
  if (not plugin::StorageEngine::dropSchema(schema_identifier))
 
716
  if (rmdir(org_path))
546
717
  {
547
 
    std::string path;
548
 
    schema_identifier.getSQLPath(path);
549
 
    my_error(ER_DROP_SCHEMA, MYF(0), path.c_str());
550
 
 
 
718
    my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, errno);
551
719
    return -1;
552
720
  }
553
721
 
616
784
    @retval true  Error
617
785
*/
618
786
 
619
 
bool mysql_change_db(Session *session, SchemaIdentifier &schema_identifier)
 
787
bool mysql_change_db(Session *session, const NormalisedDatabaseName &normalised_database_name, bool force_switch)
620
788
{
621
 
 
622
 
  if (not plugin::Authorization::isAuthorized(session->getSecurityContext(), schema_identifier))
623
 
  {
624
 
    /* Error message is set in isAuthorized */
625
 
    return true;
626
 
  }
627
 
 
628
 
  if (not check_db_name(session, schema_identifier))
629
 
  {
630
 
    std::string path;
631
 
    schema_identifier.getSQLPath(path);
632
 
    my_error(ER_WRONG_DB_NAME, MYF(0), path.c_str());
633
 
 
634
 
    return true;
635
 
  }
636
 
 
637
 
  if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
638
 
  {
639
 
    /* Report an error and free new_db_file_name. */
640
 
    std::string path;
641
 
    schema_identifier.getSQLPath(path);
642
 
 
643
 
    my_error(ER_BAD_DB_ERROR, MYF(0), path.c_str());
644
 
 
645
 
    /* The operation failed. */
646
 
 
647
 
    return true;
648
 
  }
649
 
 
650
 
  mysql_change_db_impl(session, schema_identifier);
 
789
  const CHARSET_INFO *db_default_cl;
 
790
 
 
791
  if (my_strcasecmp(system_charset_info, normalised_database_name.to_string().c_str(),
 
792
                    INFORMATION_SCHEMA_NAME.c_str()) == 0)
 
793
  {
 
794
    NonNormalisedDatabaseName non_normalised_i_s(INFORMATION_SCHEMA_NAME);
 
795
    NormalisedDatabaseName is_name(non_normalised_i_s);
 
796
 
 
797
    session->set_db(is_name);
 
798
    return false;
 
799
  }
 
800
 
 
801
  /*
 
802
    NOTE: if check_db_name() fails, we should throw an error in any case,
 
803
    even if we are called from sp_head::execute().
 
804
 
 
805
    It's next to impossible however to get this error when we are called
 
806
    from sp_head::execute(). But let's switch the current database to NULL
 
807
    in this case to be sure.
 
808
  */
 
809
  if (! normalised_database_name.isValid())
 
810
  {
 
811
    my_error(ER_WRONG_DB_NAME, MYF(0),
 
812
             normalised_database_name.to_string().c_str());
 
813
 
 
814
    if (force_switch)
 
815
      session->clear_db();
 
816
 
 
817
    return true;
 
818
  }
 
819
 
 
820
  DatabasePathName database_path(normalised_database_name);
 
821
 
 
822
  if (! database_path.exists())
 
823
  {
 
824
    if (force_switch)
 
825
    {
 
826
      /* Throw a warning and free new_db_file_name. */
 
827
 
 
828
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
829
                          ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
 
830
                          normalised_database_name.to_string().c_str());
 
831
 
 
832
      /* Change db to NULL. */
 
833
 
 
834
      session->clear_db();
 
835
 
 
836
      /* The operation succeed. */
 
837
 
 
838
      return false;
 
839
    }
 
840
    else
 
841
    {
 
842
      /* Report an error and free new_db_file_name. */
 
843
 
 
844
      my_error(ER_BAD_DB_ERROR, MYF(0),
 
845
               normalised_database_name.to_string().c_str());
 
846
 
 
847
      /* The operation failed. */
 
848
 
 
849
      return true;
 
850
    }
 
851
  }
 
852
 
 
853
  db_default_cl= get_default_db_collation(normalised_database_name.to_string().c_str());
 
854
 
 
855
  session->set_db(normalised_database_name);
651
856
 
652
857
  return false;
653
858
}
654
859
 
655
 
/**
656
 
  @brief Internal implementation: switch current database to a valid one.
657
 
 
658
 
  @param session            Thread context.
659
 
  @param new_db_name    Name of the database to switch to. The function will
660
 
                        take ownership of the name (the caller must not free
661
 
                        the allocated memory). If the name is NULL, we're
662
 
                        going to switch to NULL db.
663
 
  @param new_db_charset Character set of the new database.
664
 
*/
665
 
 
666
 
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier)
667
 
{
668
 
  /* 1. Change current database in Session. */
669
 
 
670
 
#if 0
671
 
  if (new_db_name == NULL)
672
 
  {
673
 
    /*
674
 
      Session::set_db() does all the job -- it frees previous database name and
675
 
      sets the new one.
676
 
    */
677
 
 
678
 
    session->set_db(NULL, 0);
679
 
  }
680
 
  else
681
 
#endif
682
 
  {
683
 
    /*
684
 
      Here we already have a copy of database name to be used in Session. So,
685
 
      we just call Session::reset_db(). Since Session::reset_db() does not releases
686
 
      the previous database name, we should do it explicitly.
687
 
    */
688
 
 
689
 
    session->set_db(schema_identifier.getSchemaName());
690
 
  }
691
 
}
692
 
 
693
 
static void mysql_change_db_impl(Session *session)
694
 
{
695
 
  session->set_db(string());
696
 
}
697
 
 
698
 
} /* namespace drizzled */
 
860
NormalisedDatabaseName::NormalisedDatabaseName(const NonNormalisedDatabaseName &dbname)
 
861
{
 
862
  const std::string &non_norm_string= dbname.to_string();
 
863
  database_name= (char*)malloc(non_norm_string.size()+1);
 
864
 
 
865
  assert(database_name); /* FIXME: should throw exception */
 
866
 
 
867
  strncpy(database_name, non_norm_string.c_str(), non_norm_string.size()+1);
 
868
 
 
869
  my_casedn_str(files_charset_info, database_name);
 
870
}
 
871
 
 
872
NormalisedDatabaseName::~NormalisedDatabaseName()
 
873
{
 
874
  free(database_name);
 
875
}
 
876
 
 
877
bool NormalisedDatabaseName::isValid() const
 
878
{
 
879
  LEX_STRING db_lexstring;
 
880
 
 
881
  db_lexstring.str= database_name;
 
882
  db_lexstring.length= strlen(database_name);
 
883
 
 
884
  if (db_lexstring.length == 0
 
885
      || db_lexstring.length > NAME_LEN
 
886
      || database_name[db_lexstring.length - 1] == ' ')
 
887
    return false;
 
888
 
 
889
  return (! check_identifier_name(&db_lexstring));
 
890
}
 
891
 
 
892
DatabasePathName::DatabasePathName(const NormalisedDatabaseName &database_name)
 
893
{
 
894
  char db_dir_path[FN_REFLEN];
 
895
  uint32_t db_dir_path_len;
 
896
 
 
897
  db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
 
898
                                        database_name.to_string().c_str(),
 
899
                                        "", false);
 
900
 
 
901
  if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
 
902
    db_dir_path[db_dir_path_len - 1]= 0;
 
903
 
 
904
  database_path.assign(db_dir_path);
 
905
}
 
906
 
 
907
bool DatabasePathName::exists() const
 
908
{
 
909
  /* TODO: handle EIO and other fun errors */
 
910
  return access(database_path.c_str(), F_OK) == 0;
 
911
}