~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/db.cc

Big merge.

Show diffs side-by-side

added added

removed removed

Lines of Context:
49
49
                                 const char *db, const char *path,
50
50
                                 TableList **dropped_tables);
51
51
 
52
 
static void mysql_change_db_impl(Session *session, LEX_STRING *new_db_name);
53
 
            
54
 
 
55
52
/**
56
53
  Return default database collation.
57
54
 
92
89
}
93
90
 
94
91
/* path is path to database, not schema file */
95
 
static int write_schema_file(Session *session,
96
 
                             const char *path, const char *name,
97
 
                             HA_CREATE_INFO *create)
 
92
static int write_schema_file(const DatabasePathName &path, const message::Schema &db)
98
93
{
99
 
  message::Schema db;
100
94
  char schema_file_tmp[FN_REFLEN];
101
 
  string schema_file(path);
102
 
 
103
 
  assert(path);
104
 
  assert(name);
105
 
  assert(create);
106
 
 
107
 
  snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path, FN_LIBCHAR, MY_DB_OPT_FILE);
 
95
  string schema_file(path.to_string());
 
96
 
 
97
  snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path.to_string().c_str(), FN_LIBCHAR, MY_DB_OPT_FILE);
108
98
 
109
99
  schema_file.append(1, FN_LIBCHAR);
110
100
  schema_file.append(MY_DB_OPT_FILE);
114
104
  if (fd==-1)
115
105
    return errno;
116
106
 
117
 
  if (!create->default_table_charset)
118
 
    create->default_table_charset= session->variables.collation_server;
119
 
 
120
 
  db.set_name(name);
121
 
  db.set_collation(create->default_table_charset->name);
122
107
 
123
108
  if (!db.SerializeToFileDescriptor(fd))
124
109
  {
186
171
 
187
172
*/
188
173
 
189
 
bool mysql_create_db(Session *session, const char *db, HA_CREATE_INFO *create_info, bool is_if_not_exists)
 
174
bool mysql_create_db(Session *session, const NormalisedDatabaseName &database_name, message::Schema *schema_message, bool is_if_not_exists)
190
175
{
191
176
  ReplicationServices &replication_services= ReplicationServices::singleton();
192
 
  char   path[FN_REFLEN+16];
193
177
  long result= 1;
194
178
  int error_erno;
195
179
  bool error= false;
196
 
  uint32_t path_len;
 
180
  DatabasePathName database_path(database_name);
197
181
 
198
182
  /* do not create 'information_schema' db */
199
 
  if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.c_str()))
 
183
  if (!my_strcasecmp(system_charset_info, database_name.to_string().c_str(), INFORMATION_SCHEMA_NAME.c_str()))
200
184
  {
201
 
    my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
 
185
    my_error(ER_DB_CREATE_EXISTS, MYF(0), database_name.to_string().c_str());
202
186
    return(-1);
203
187
  }
204
188
 
 
189
  assert(database_name.isValid());
 
190
  schema_message->set_name(database_name.to_string());
 
191
 
205
192
  /*
206
193
    Do not create database if another thread is holding read lock.
207
194
    Wait for global read lock before acquiring LOCK_create_db.
222
209
 
223
210
  pthread_mutex_lock(&LOCK_create_db);
224
211
 
225
 
  /* Check directory */
226
 
  path_len= build_table_filename(path, sizeof(path), db, "", false);
227
 
  path[path_len-1]= 0;                    // Remove last '/' from path
228
 
 
229
 
  if (mkdir(path,0777) == -1)
 
212
  if (mkdir(database_path.to_string().c_str(),0777) == -1)
230
213
  {
231
214
    if (errno == EEXIST)
232
215
    {
233
216
      if (! is_if_not_exists)
234
217
      {
235
 
        my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
 
218
        my_error(ER_DB_CREATE_EXISTS, MYF(0), database_name.to_string().c_str());
236
219
        error= true;
237
220
        goto exit;
238
221
      }
239
222
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
240
 
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
 
223
                          ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
 
224
                          database_name.to_string().c_str());
241
225
      session->my_ok();
242
226
      error= false;
243
227
      goto exit;
244
228
    }
245
229
 
246
 
    my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
 
230
    my_error(ER_CANT_CREATE_DB, MYF(0), database_name.to_string().c_str(), my_errno);
247
231
    error= true;
248
232
    goto exit;
249
233
  }
250
234
 
251
 
  error_erno= write_schema_file(session, path, db, create_info);
 
235
  error_erno= write_schema_file(database_path, *schema_message);
252
236
  if (error_erno && error_erno != EEXIST)
253
237
  {
254
 
    if (rmdir(path) >= 0)
 
238
    if (rmdir(database_path.to_string().c_str()) >= 0)
255
239
    {
256
240
      error= true;
257
241
      goto exit;
273
257
 
274
258
/* db-name is already validated when we come here */
275
259
 
276
 
bool mysql_alter_db(Session *session, const char *db, HA_CREATE_INFO *create_info)
 
260
bool mysql_alter_db(Session *session, const NormalisedDatabaseName &database_name, message::Schema *schema_message)
277
261
{
278
262
  ReplicationServices &replication_services= ReplicationServices::singleton();
279
263
  long result=1;
280
264
  int error= 0;
281
 
  char   path[FN_REFLEN+16];
282
 
  uint32_t path_len;
 
265
  DatabasePathName database_path(database_name);
283
266
 
284
267
  /*
285
268
    Do not alter database if another thread is holding read lock.
296
279
  if ((error=wait_if_global_read_lock(session,0,1)))
297
280
    goto exit;
298
281
 
 
282
  assert(schema_message);
 
283
  assert(database_name.isValid());
 
284
 
 
285
  schema_message->set_name(database_name.to_string());
 
286
 
299
287
  pthread_mutex_lock(&LOCK_create_db);
300
288
 
301
 
  /* Change options if current database is being altered. */
302
 
  path_len= build_table_filename(path, sizeof(path), db, "", false);
303
 
  path[path_len-1]= 0;                    // Remove last '/' from path
304
 
 
305
 
  error= write_schema_file(session, path, db, create_info);
 
289
  error= write_schema_file(database_path, *schema_message);
306
290
  if (error && error != EEXIST)
307
291
  {
308
292
    /* TODO: find some witty way of getting back an error message */
337
321
    ERROR Error
338
322
*/
339
323
 
340
 
bool mysql_rm_db(Session *session,char *db,bool if_exists)
 
324
bool mysql_rm_db(Session *session, const NormalisedDatabaseName &database_name, bool if_exists)
341
325
{
342
326
  long deleted=0;
343
327
  int error= false;
346
330
  uint32_t length;
347
331
  TableList *dropped_tables= NULL;
348
332
 
349
 
  if (db && (strcmp(db, "information_schema") == 0))
 
333
  if (database_name.to_string().compare(INFORMATION_SCHEMA_NAME) == 0)
350
334
  {
351
335
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
352
336
    return true;
372
356
 
373
357
  pthread_mutex_lock(&LOCK_create_db);
374
358
 
375
 
  length= build_table_filename(path, sizeof(path), db, "", false);
 
359
  length= build_table_filename(path, sizeof(path),
 
360
                               database_name.to_string().c_str(), "", false);
376
361
  strcpy(path+length, MY_DB_OPT_FILE);         // Append db option file name
377
362
  unlink(path);
378
363
  path[length]= '\0';                           // Remove file name
383
368
    if (!if_exists)
384
369
    {
385
370
      error= -1;
386
 
      my_error(ER_DB_DROP_EXISTS, MYF(0), db);
 
371
      my_error(ER_DB_DROP_EXISTS, MYF(0), database_name.to_string().c_str());
387
372
      goto exit;
388
373
    }
389
374
    else
390
375
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
391
 
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
 
376
                          ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
 
377
                          database_name.to_string().c_str());
392
378
  }
393
379
  else
394
380
  {
395
381
    pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
396
 
    remove_db_from_cache(db);
 
382
    remove_db_from_cache(database_name.to_string().c_str());
397
383
    pthread_mutex_unlock(&LOCK_open);
398
384
 
399
385
 
400
386
    error= -1;
401
 
    if ((deleted= mysql_rm_known_files(session, dirp, db, path, &dropped_tables)) >= 0)
 
387
    if ((deleted= mysql_rm_known_files(session, dirp, database_name.to_string().c_str(), path, &dropped_tables)) >= 0)
402
388
    {
403
389
      plugin::StorageEngine::dropDatabase(path);
404
390
      error = 0;
408
394
  {
409
395
    const char *query;
410
396
    uint32_t query_length;
411
 
    if (!session->query)
412
 
    {
413
 
      /* The client used the old obsolete mysql_drop_db() call */
414
 
      query= path;
415
 
      query_length= sprintf(path, "drop database `%s`", db);
416
 
    }
417
 
    else
418
 
    {
419
 
      query= session->query;
420
 
      query_length= session->query_length;
421
 
    }
 
397
 
 
398
    assert(session->query);
 
399
 
 
400
    query= session->query;
 
401
    query_length= session->query_length;
 
402
 
422
403
    ReplicationServices &replication_services= ReplicationServices::singleton();
423
404
    replication_services.rawStatement(session, session->getQueryString(), session->getQueryLength());
424
405
    session->clear_error();
436
417
      goto exit; /* not much else we can do */
437
418
    query_pos= query_data_start= strcpy(query,"drop table ")+11;
438
419
    query_end= query + MAX_DROP_TABLE_Q_LEN;
439
 
    db_len= strlen(db);
 
420
    db_len= database_name.to_string().length();
440
421
 
441
422
    ReplicationServices &replication_services= ReplicationServices::singleton();
442
423
    for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
472
453
    SELECT DATABASE() in the future). For this we free() session->db and set
473
454
    it to 0.
474
455
  */
475
 
  if (! session->db.empty() && ! strcmp(session->db.c_str(), db))
476
 
    mysql_change_db_impl(session, NULL);
 
456
  if (! session->db.empty() && session->db.compare(database_name.to_string()) == 0)
 
457
    session->clear_db();
477
458
  pthread_mutex_unlock(&LOCK_create_db);
478
459
  start_waiting_global_read_lock(session);
479
460
exit2:
729
710
}
730
711
 
731
712
/**
732
 
  @brief Internal implementation: switch current database to a valid one.
733
 
 
734
 
  @param session            Thread context.
735
 
  @param new_db_name    Name of the database to switch to. The function will
736
 
                        take ownership of the name (the caller must not free
737
 
                        the allocated memory). If the name is NULL, we're
738
 
                        going to switch to NULL db.
739
 
  @param new_db_charset Character set of the new database.
740
 
*/
741
 
 
742
 
static void mysql_change_db_impl(Session *session, LEX_STRING *new_db_name)
743
 
{
744
 
  /* 1. Change current database in Session. */
745
 
 
746
 
  if (new_db_name == NULL)
747
 
  {
748
 
    /*
749
 
      Session::set_db() does all the job -- it frees previous database name and
750
 
      sets the new one.
751
 
    */
752
 
 
753
 
    session->set_db(NULL, 0);
754
 
  }
755
 
  else
756
 
  {
757
 
    /*
758
 
      Here we already have a copy of database name to be used in Session. So,
759
 
      we just call Session::reset_db(). Since Session::reset_db() does not releases
760
 
      the previous database name, we should do it explicitly.
761
 
    */
762
 
 
763
 
    session->set_db(new_db_name->str, new_db_name->length);
764
 
  }
765
 
}
766
 
 
767
 
/**
768
 
  Return true if db1_name is equal to db2_name, false otherwise.
769
 
 
770
 
  The function allows to compare database names according to the MySQL
771
 
  rules. The database names db1 and db2 are equal if:
772
 
     - db1 is NULL and db2 is NULL;
773
 
     or
774
 
     - db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
775
 
       db2 in system character set (UTF8).
776
 
*/
777
 
 
778
 
static inline bool
779
 
cmp_db_names(const char *db1_name,
780
 
             const char *db2_name)
781
 
{
782
 
  return
783
 
         /* db1 is NULL and db2 is NULL */
784
 
         (!db1_name && !db2_name) ||
785
 
 
786
 
         /* db1 is not-NULL, db2 is not-NULL, db1 == db2. */
787
 
         (db1_name && db2_name && my_strcasecmp(system_charset_info, db1_name, db2_name) == 0);
788
 
}
789
 
 
790
 
 
791
 
/**
792
713
  @brief Change the current database and its attributes unconditionally.
793
714
 
794
715
  @param session          thread handle
850
771
    @retval true  Error
851
772
*/
852
773
 
853
 
bool mysql_change_db(Session *session, const LEX_STRING *new_db_name, bool force_switch)
 
774
bool mysql_change_db(Session *session, const NormalisedDatabaseName &normalised_database_name, bool force_switch)
854
775
{
855
 
  LEX_STRING new_db_file_name;
856
776
  const CHARSET_INFO *db_default_cl;
857
777
 
858
 
  assert(new_db_name);
859
 
  assert(new_db_name->length);
860
 
 
861
 
  if (my_strcasecmp(system_charset_info, new_db_name->str,
 
778
  if (my_strcasecmp(system_charset_info, normalised_database_name.to_string().c_str(),
862
779
                    INFORMATION_SCHEMA_NAME.c_str()) == 0)
863
780
  {
864
 
    /* Switch the current database to INFORMATION_SCHEMA. */
865
 
    /* const_cast<> is safe here: mysql_change_db_impl does a copy */
866
 
    LEX_STRING is_name= { const_cast<char *>(INFORMATION_SCHEMA_NAME.c_str()),
867
 
                          INFORMATION_SCHEMA_NAME.length() };
868
 
    mysql_change_db_impl(session, &is_name);
 
781
    NonNormalisedDatabaseName non_normalised_i_s(INFORMATION_SCHEMA_NAME);
 
782
    NormalisedDatabaseName is_name(non_normalised_i_s);
869
783
 
 
784
    session->set_db(is_name);
870
785
    return false;
871
786
  }
872
787
 
873
788
  /*
874
 
    Now we need to make a copy because check_db_name requires a
875
 
    non-constant argument. Actually, it takes database file name.
876
 
 
877
 
    TODO: fix check_db_name().
878
 
  */
879
 
 
880
 
  new_db_file_name.length= new_db_name->length;
881
 
  new_db_file_name.str= (char *)malloc(new_db_name->length + 1);
882
 
  if (new_db_file_name.str == NULL)
883
 
    return true;                             /* the error is set */
884
 
  memcpy(new_db_file_name.str, new_db_name->str, new_db_name->length);
885
 
  new_db_file_name.str[new_db_name->length]= 0;
886
 
 
887
 
 
888
 
  /*
889
789
    NOTE: if check_db_name() fails, we should throw an error in any case,
890
790
    even if we are called from sp_head::execute().
891
791
 
893
793
    from sp_head::execute(). But let's switch the current database to NULL
894
794
    in this case to be sure.
895
795
  */
896
 
 
897
 
  if (check_db_name(&new_db_file_name))
 
796
  if (! normalised_database_name.isValid())
898
797
  {
899
 
    my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
900
 
    free(new_db_file_name.str);
 
798
    my_error(ER_WRONG_DB_NAME, MYF(0),
 
799
             normalised_database_name.to_string().c_str());
901
800
 
902
801
    if (force_switch)
903
 
      mysql_change_db_impl(session, NULL);
 
802
      session->clear_db();
904
803
 
905
804
    return true;
906
805
  }
907
806
 
908
 
  if (check_db_dir_existence(new_db_file_name.str))
 
807
  DatabasePathName database_path(normalised_database_name);
 
808
 
 
809
  if (! database_path.exists())
909
810
  {
910
811
    if (force_switch)
911
812
    {
913
814
 
914
815
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
915
816
                          ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
916
 
                          new_db_file_name.str);
917
 
 
918
 
      free(new_db_file_name.str);
 
817
                          normalised_database_name.to_string().c_str());
919
818
 
920
819
      /* Change db to NULL. */
921
820
 
922
 
      mysql_change_db_impl(session, NULL);
 
821
      session->clear_db();
923
822
 
924
823
      /* The operation succeed. */
925
824
 
929
828
    {
930
829
      /* Report an error and free new_db_file_name. */
931
830
 
932
 
      my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
933
 
      free(new_db_file_name.str);
 
831
      my_error(ER_BAD_DB_ERROR, MYF(0),
 
832
               normalised_database_name.to_string().c_str());
934
833
 
935
834
      /* The operation failed. */
936
835
 
938
837
    }
939
838
  }
940
839
 
941
 
  db_default_cl= get_default_db_collation(new_db_file_name.str);
 
840
  db_default_cl= get_default_db_collation(normalised_database_name.to_string().c_str());
942
841
 
943
 
  mysql_change_db_impl(session, &new_db_file_name);
944
 
  free(new_db_file_name.str);
 
842
  session->set_db(normalised_database_name);
945
843
 
946
844
  return false;
947
845
}
948
846
 
949
 
/*
950
 
  Check if there is directory for the database name.
951
 
 
952
 
  SYNOPSIS
953
 
    check_db_dir_existence()
954
 
    db_name   database name
955
 
 
956
 
  RETURN VALUES
957
 
    false   There is directory for the specified database name.
958
 
    true    The directory does not exist.
959
 
*/
960
 
 
961
 
bool check_db_dir_existence(const char *db_name)
 
847
NormalisedDatabaseName::NormalisedDatabaseName(const NonNormalisedDatabaseName &dbname)
 
848
{
 
849
  const std::string &non_norm_string= dbname.to_string();
 
850
  database_name= (char*)malloc(non_norm_string.size()+1);
 
851
 
 
852
  assert(database_name); /* FIXME: should throw exception */
 
853
 
 
854
  strncpy(database_name, non_norm_string.c_str(), non_norm_string.size()+1);
 
855
 
 
856
  my_casedn_str(files_charset_info, database_name);
 
857
}
 
858
 
 
859
NormalisedDatabaseName::~NormalisedDatabaseName()
 
860
{
 
861
  free(database_name);
 
862
}
 
863
 
 
864
bool NormalisedDatabaseName::isValid() const
 
865
{
 
866
  LEX_STRING db_lexstring;
 
867
 
 
868
  db_lexstring.str= database_name;
 
869
  db_lexstring.length= strlen(database_name);
 
870
 
 
871
  if (db_lexstring.length == 0
 
872
      || db_lexstring.length > NAME_LEN
 
873
      || database_name[db_lexstring.length - 1] == ' ')
 
874
    return false;
 
875
 
 
876
  return (! check_identifier_name(&db_lexstring));
 
877
}
 
878
 
 
879
DatabasePathName::DatabasePathName(const NormalisedDatabaseName &database_name)
962
880
{
963
881
  char db_dir_path[FN_REFLEN];
964
882
  uint32_t db_dir_path_len;
965
883
 
966
884
  db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
967
 
                                        db_name, "", false);
 
885
                                        database_name.to_string().c_str(),
 
886
                                        "", false);
968
887
 
969
888
  if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
970
889
    db_dir_path[db_dir_path_len - 1]= 0;
971
890
 
972
 
  /* Check access. */
 
891
  database_path.assign(db_dir_path);
 
892
}
973
893
 
974
 
  return my_access(db_dir_path, F_OK);
 
894
bool DatabasePathName::exists() const
 
895
{
 
896
  /* TODO: handle EIO and other fun errors */
 
897
  return access(database_path.c_str(), F_OK) == 0;
975
898
}