~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

  • Committer: Brian Aker
  • Date: 2010-03-31 19:14:14 UTC
  • Revision ID: brian@gaz-20100331191414-9yv44mmpvf0tb7l1
Updated to use show schemas specific table.

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
/* drop and alter of tables */
17
17
 
36
36
#include "drizzled/transaction_services.h"
37
37
#include <drizzled/table_proto.h>
38
38
#include <drizzled/plugin/client.h>
39
 
#include <drizzled/identifier.h>
 
39
#include <drizzled/table_identifier.h>
40
40
#include "drizzled/internal/m_string.h"
41
41
#include "drizzled/global_charset_info.h"
42
42
#include "drizzled/charset.h"
43
43
 
44
 
#include "drizzled/definition/cache.h"
45
 
 
46
44
 
47
45
#include "drizzled/statement/alter_table.h"
48
46
#include "drizzled/sql_table.h"
51
49
#include <algorithm>
52
50
#include <sstream>
53
51
 
54
 
#include <boost/unordered_set.hpp>
55
 
 
56
52
using namespace std;
57
53
 
58
54
namespace drizzled
59
55
{
60
56
 
 
57
extern plugin::StorageEngine *myisam_engine;
61
58
extern pid_t current_pid;
62
59
 
63
 
bool is_primary_key(KeyInfo *key_info)
 
60
bool is_primary_key(KEY *key_info)
64
61
{
65
62
  static const char * primary_key_name="PRIMARY";
66
63
  return (strcmp(key_info->name, primary_key_name)==0);
75
72
    return NULL;
76
73
}
77
74
 
78
 
static bool check_if_keyname_exists(const char *name,KeyInfo *start, KeyInfo *end);
79
 
static char *make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end);
 
75
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
 
76
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
80
77
 
81
78
static bool prepare_blob_field(Session *session, CreateField *sql_field);
82
79
 
107
104
    cursor
108
105
*/
109
106
 
110
 
void write_bin_log(Session *session, const std::string &query)
 
107
void write_bin_log(Session *session,
 
108
                   char const *query)
111
109
{
112
110
  TransactionServices &transaction_services= TransactionServices::singleton();
113
111
  transaction_services.rawStatement(session, query);
114
112
}
115
113
 
 
114
 
 
115
/* Should should be refactored to go away */
 
116
void write_bin_log_drop_table(Session *session, bool if_exists, const char *db_name, const char *table_name)
 
117
{
 
118
  TransactionServices &transaction_services= TransactionServices::singleton();
 
119
  string built_query;
 
120
 
 
121
  if (if_exists)
 
122
    built_query.append("DROP TABLE IF EXISTS ");
 
123
  else
 
124
    built_query.append("DROP TABLE ");
 
125
 
 
126
  built_query.append("`");
 
127
  if (session->db.empty() || strcmp(db_name, session->db.c_str()) != 0)
 
128
  {
 
129
    built_query.append(db_name);
 
130
    built_query.append("`.`");
 
131
  }
 
132
 
 
133
  built_query.append(table_name);
 
134
  built_query.append("`");
 
135
  transaction_services.rawStatement(session, built_query);
 
136
}
 
137
 
116
138
/*
117
139
  Execute the drop of a normal or temporary table
118
140
 
124
146
                        In this case we give an warning of level 'NOTE'
125
147
    drop_temporary      Only drop temporary tables
126
148
 
127
 
  @todo
 
149
  TODO:
128
150
    When logging to the binary log, we should log
129
151
    tmp_tables and transactional tables as separate statements if we
130
152
    are in a transaction;  This is needed to get these tables into the
148
170
  int error= 0;
149
171
  bool foreign_key_error= false;
150
172
 
151
 
  {
152
 
    table::Cache::singleton().mutex().lock(); /* Part 2 of rm a table */
153
 
 
154
 
    if (not drop_temporary && session->lock_table_names_exclusively(tables))
155
 
    {
156
 
      table::Cache::singleton().mutex().unlock();
157
 
      return 1;
158
 
    }
159
 
 
160
 
    /* Don't give warnings for not found errors, as we already generate notes */
161
 
    session->no_warnings_for_error= 1;
162
 
 
163
 
    for (table= tables; table; table= table->next_local)
164
 
    {
165
 
      TableIdentifier tmp_identifier(table->getSchemaName(), table->getTableName());
166
 
 
167
 
      error= session->drop_temporary_table(tmp_identifier);
168
 
 
169
 
      switch (error) {
170
 
      case  0:
171
 
        // removed temporary table
172
 
        continue;
173
 
      case -1:
 
173
  pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
 
174
 
 
175
  /*
 
176
    If we have the table in the definition cache, we don't have to check the
 
177
    .frm cursor to find if the table is a normal table (not view) and what
 
178
    engine to use.
 
179
  */
 
180
 
 
181
  for (table= tables; table; table= table->next_local)
 
182
  {
 
183
    TableIdentifier identifier(table->db, table->table_name);
 
184
    TableShare *share;
 
185
    table->db_type= NULL;
 
186
 
 
187
    if ((share= TableShare::getShare(identifier)))
 
188
    {
 
189
      table->db_type= share->db_type();
 
190
    }
 
191
  }
 
192
 
 
193
  if (not drop_temporary && lock_table_names_exclusively(session, tables))
 
194
  {
 
195
    pthread_mutex_unlock(&LOCK_open);
 
196
    return 1;
 
197
  }
 
198
 
 
199
  /* Don't give warnings for not found errors, as we already generate notes */
 
200
  session->no_warnings_for_error= 1;
 
201
 
 
202
  for (table= tables; table; table= table->next_local)
 
203
  {
 
204
    char *db=table->db;
 
205
 
 
206
    error= session->drop_temporary_table(table);
 
207
 
 
208
    switch (error) {
 
209
    case  0:
 
210
      // removed temporary table
 
211
      continue;
 
212
    case -1:
 
213
      error= 1;
 
214
      goto err_with_placeholders;
 
215
    default:
 
216
      // temporary table not found
 
217
      error= 0;
 
218
    }
 
219
 
 
220
    if (drop_temporary == false)
 
221
    {
 
222
      Table *locked_table;
 
223
      abort_locked_tables(session, db, table->table_name);
 
224
      remove_table_from_cache(session, db, table->table_name,
 
225
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
226
                              RTFC_CHECK_KILLED_FLAG);
 
227
      /*
 
228
        If the table was used in lock tables, remember it so that
 
229
        unlock_table_names can free it
 
230
      */
 
231
      if ((locked_table= drop_locked_tables(session, db, table->table_name)))
 
232
        table->table= locked_table;
 
233
 
 
234
      if (session->killed)
 
235
      {
 
236
        error= -1;
 
237
        goto err_with_placeholders;
 
238
      }
 
239
    }
 
240
    TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? message::Table::INTERNAL : message::Table::STANDARD);
 
241
 
 
242
    if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
 
243
    {
 
244
      // Table was not found on disk and table can't be created from engine
 
245
      if (if_exists)
 
246
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
247
                            ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 
248
                            table->table_name);
 
249
      else
174
250
        error= 1;
175
 
        goto err_with_placeholders;
176
 
      default:
177
 
        // temporary table not found
 
251
    }
 
252
    else
 
253
    {
 
254
      error= plugin::StorageEngine::dropTable(*session, identifier);
 
255
 
 
256
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
 
257
      {
178
258
        error= 0;
179
 
      }
180
 
 
181
 
      if (drop_temporary == false)
182
 
      {
183
 
        Table *locked_table;
184
 
        abort_locked_tables(session, tmp_identifier);
185
 
        table::Cache::singleton().removeTable(session, tmp_identifier,
186
 
                                              RTFC_WAIT_OTHER_THREAD_FLAG |
187
 
                                              RTFC_CHECK_KILLED_FLAG);
188
 
        /*
189
 
          If the table was used in lock tables, remember it so that
190
 
          unlock_table_names can free it
191
 
        */
192
 
        if ((locked_table= drop_locked_tables(session, tmp_identifier)))
193
 
          table->table= locked_table;
194
 
 
195
 
        if (session->getKilled())
196
 
        {
197
 
          error= -1;
198
 
          goto err_with_placeholders;
199
 
        }
200
 
      }
201
 
      TableIdentifier identifier(table->getSchemaName(), table->getTableName(), table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
202
 
 
203
 
      if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
204
 
      {
205
 
        // Table was not found on disk and table can't be created from engine
206
 
        if (if_exists)
207
 
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
208
 
                              ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
209
 
                              table->getTableName());
210
 
        else
211
 
          error= 1;
212
 
      }
213
 
      else
214
 
      {
215
 
        error= plugin::StorageEngine::dropTable(*session, identifier);
216
 
 
217
 
        if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
218
 
        {
219
 
          error= 0;
220
 
          session->clear_error();
221
 
        }
222
 
 
223
 
        if (error == HA_ERR_ROW_IS_REFERENCED)
224
 
        {
225
 
          /* the table is referenced by a foreign key constraint */
226
 
          foreign_key_error= true;
227
 
        }
228
 
      }
229
 
 
230
 
      if (error == 0 || (if_exists && foreign_key_error == false))
231
 
      {
232
 
        TransactionServices &transaction_services= TransactionServices::singleton();
233
 
        transaction_services.dropTable(session, string(table->getSchemaName()), string(table->getTableName()), if_exists);
234
 
      }
235
 
 
236
 
      if (error)
237
 
      {
238
 
        if (wrong_tables.length())
239
 
          wrong_tables.append(',');
240
 
        wrong_tables.append(String(table->getTableName(), system_charset_info));
241
 
      }
242
 
    }
243
 
    /*
244
 
      It's safe to unlock table::Cache::singleton().mutex(): we have an exclusive lock
245
 
      on the table name.
246
 
    */
247
 
    table::Cache::singleton().mutex().unlock();
 
259
        session->clear_error();
 
260
      }
 
261
 
 
262
      if (error == HA_ERR_ROW_IS_REFERENCED)
 
263
      {
 
264
        /* the table is referenced by a foreign key constraint */
 
265
        foreign_key_error= true;
 
266
      }
 
267
    }
 
268
 
 
269
    if (error == 0 || (if_exists && foreign_key_error == false))
 
270
    {
 
271
      TransactionServices &transaction_services= TransactionServices::singleton();
 
272
      transaction_services.dropTable(session, string(db), string(table->table_name), if_exists);
 
273
    }
 
274
 
 
275
    if (error)
 
276
    {
 
277
      if (wrong_tables.length())
 
278
        wrong_tables.append(',');
 
279
      wrong_tables.append(String(table->table_name,system_charset_info));
 
280
    }
248
281
  }
 
282
  /*
 
283
    It's safe to unlock LOCK_open: we have an exclusive lock
 
284
    on the table name.
 
285
  */
 
286
  pthread_mutex_unlock(&LOCK_open);
249
287
  error= 0;
250
288
 
251
289
  if (wrong_tables.length())
262
300
    error= 1;
263
301
  }
264
302
 
265
 
  table::Cache::singleton().mutex().lock(); /* final bit in rm table lock */
 
303
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
266
304
 
267
305
err_with_placeholders:
268
 
  tables->unlock_table_names();
269
 
  table::Cache::singleton().mutex().unlock();
 
306
  unlock_table_names(tables, NULL);
 
307
  pthread_mutex_unlock(&LOCK_open);
270
308
  session->no_warnings_for_error= 0;
271
309
 
272
310
  return error;
273
311
}
274
312
 
 
313
 
 
314
/*
 
315
  Quickly remove a table.
 
316
 
 
317
  SYNOPSIS
 
318
    quick_rm_table()
 
319
      base                      The plugin::StorageEngine handle.
 
320
      db                        The database name.
 
321
      table_name                The table name.
 
322
      is_tmp                    If the table is temp.
 
323
 
 
324
  RETURN
 
325
    0           OK
 
326
    != 0        Error
 
327
*/
 
328
bool quick_rm_table(Session& session,
 
329
                    TableIdentifier &identifier)
 
330
{
 
331
  return (plugin::StorageEngine::dropTable(session, identifier));
 
332
}
 
333
 
275
334
/*
276
335
  Sort keys in the following order:
277
336
  - PRIMARY KEY
285
344
  PRIMARY keys are prioritized.
286
345
*/
287
346
 
288
 
static int sort_keys(KeyInfo *a, KeyInfo *b)
 
347
static int sort_keys(KEY *a, KEY *b)
289
348
{
290
349
  ulong a_flags= a->flags, b_flags= b->flags;
291
350
 
337
396
    1             Error
338
397
*/
339
398
 
340
 
class typelib_set_member
341
 
{
342
 
public:
343
 
  string s;
344
 
  const CHARSET_INFO * const cs;
345
 
 
346
 
  typelib_set_member(const char* value, unsigned int length,
347
 
                     const CHARSET_INFO * const charset)
348
 
    : s(value, length),
349
 
      cs(charset)
350
 
  {}
351
 
};
352
 
 
353
 
static bool operator==(typelib_set_member const& a, typelib_set_member const& b)
354
 
{
355
 
  return (my_strnncoll(a.cs,
356
 
                       (const unsigned char*)a.s.c_str(), a.s.length(),
357
 
                       (const unsigned char*)b.s.c_str(), b.s.length())==0);
358
 
}
359
 
 
360
 
 
361
 
namespace
362
 
{
363
 
class typelib_set_member_hasher
364
 
{
365
 
  boost::hash<string> hasher;
366
 
public:
367
 
  std::size_t operator()(const typelib_set_member& t) const
368
 
  {
369
 
    return hasher(t.s);
370
 
  }
371
 
};
372
 
}
373
 
 
374
399
static bool check_duplicates_in_interval(const char *set_or_name,
375
400
                                         const char *name, TYPELIB *typelib,
376
401
                                         const CHARSET_INFO * const cs,
381
406
  unsigned int *cur_length= typelib->type_lengths;
382
407
  *dup_val_count= 0;
383
408
 
384
 
  boost::unordered_set<typelib_set_member, typelib_set_member_hasher> interval_set;
385
 
 
386
 
  for ( ; tmp.count > 0; cur_value++, cur_length++)
 
409
  for ( ; tmp.count > 1; cur_value++, cur_length++)
387
410
  {
388
411
    tmp.type_names++;
389
412
    tmp.type_lengths++;
390
413
    tmp.count--;
391
 
    if (interval_set.find(typelib_set_member(*cur_value, *cur_length, cs)) != interval_set.end())
 
414
    if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
392
415
    {
393
416
      my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
394
417
               name,*cur_value,set_or_name);
395
418
      return 1;
396
419
    }
397
 
    else
398
 
      interval_set.insert(typelib_set_member(*cur_value, *cur_length, cs));
399
420
  }
400
421
  return 0;
401
422
}
468
489
 
469
490
  switch (sql_field->sql_type) {
470
491
  case DRIZZLE_TYPE_BLOB:
 
492
    sql_field->pack_flag= pack_length_to_packflag(sql_field->pack_length - portable_sizeof_char_ptr);
471
493
    sql_field->length= 8; // Unireg field length
472
494
    (*blob_columns)++;
473
495
    break;
474
496
  case DRIZZLE_TYPE_VARCHAR:
 
497
    sql_field->pack_flag=0;
475
498
    break;
476
499
  case DRIZZLE_TYPE_ENUM:
 
500
    sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length);
477
501
    if (check_duplicates_in_interval("ENUM",
478
502
                                     sql_field->field_name,
479
503
                                     sql_field->interval,
484
508
  case DRIZZLE_TYPE_DATE:  // Rest of string types
485
509
  case DRIZZLE_TYPE_DATETIME:
486
510
  case DRIZZLE_TYPE_NULL:
 
511
    sql_field->pack_flag=f_settype((uint32_t) sql_field->sql_type);
487
512
    break;
488
513
  case DRIZZLE_TYPE_DECIMAL:
 
514
    sql_field->pack_flag= 0;
489
515
    break;
490
516
  case DRIZZLE_TYPE_TIMESTAMP:
491
517
    /* We should replace old TIMESTAMP fields with their newer analogs */
497
523
        (*timestamps_with_niladic)++;
498
524
      }
499
525
      else
500
 
      {
501
526
        sql_field->unireg_check= Field::NONE;
502
 
      }
503
527
    }
504
528
    else if (sql_field->unireg_check != Field::NONE)
505
529
      (*timestamps_with_niladic)++;
507
531
    (*timestamps)++;
508
532
    /* fall-through */
509
533
  default:
 
534
    sql_field->pack_flag=(0 |
 
535
                          f_settype((uint32_t) sql_field->sql_type));
510
536
    break;
511
537
  }
512
 
 
513
538
  return 0;
514
539
}
515
540
 
519
544
                                      AlterInfo *alter_info,
520
545
                                      bool tmp_table,
521
546
                                      uint32_t *db_options,
522
 
                                      KeyInfo **key_info_buffer,
 
547
                                      KEY **key_info_buffer,
523
548
                                      uint32_t *key_count,
524
549
                                      int select_field_count)
525
550
{
527
552
  CreateField   *sql_field,*dup_field;
528
553
  uint          field,null_fields,blob_columns,max_key_length;
529
554
  ulong         record_offset= 0;
530
 
  KeyInfo               *key_info;
531
 
  KeyPartInfo *key_part_info;
 
555
  KEY           *key_info;
 
556
  KEY_PART_INFO *key_part_info;
532
557
  int           timestamps= 0, timestamps_with_niladic= 0;
533
558
  int           field_no,dup_no;
534
559
  int           select_field_pos,auto_increment=0;
606
631
 
607
632
    if (sql_field->sql_type == DRIZZLE_TYPE_ENUM)
608
633
    {
609
 
      size_t dummy;
 
634
      uint32_t dummy;
610
635
      const CHARSET_INFO * const cs= sql_field->charset;
611
636
      TYPELIB *interval= sql_field->interval;
612
637
 
639
664
          if (String::needs_conversion(tmp->length(), tmp->charset(),
640
665
                                       cs, &dummy))
641
666
          {
642
 
            size_t cnv_errs;
 
667
            uint32_t cnv_errs;
643
668
            conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
644
 
            interval->type_names[i]= session->mem_root->strmake_root(conv.ptr(), conv.length());
 
669
            interval->type_names[i]= strmake_root(session->mem_root, conv.ptr(),
 
670
                                                  conv.length());
645
671
            interval->type_lengths[i]= conv.length();
646
672
          }
647
673
 
681
707
            }
682
708
          }
683
709
        }
684
 
        uint32_t new_dummy;
685
 
        calculate_interval_lengths(cs, interval, &field_length, &new_dummy);
 
710
        calculate_interval_lengths(cs, interval, &field_length, &dummy);
686
711
        sql_field->length= field_length;
687
712
      }
688
713
      set_if_smaller(sql_field->length, (uint32_t)MAX_FIELD_WIDTH-1);
750
775
    /** @todo Get rid of this MyISAM-specific crap. */
751
776
    if (not create_proto.engine().name().compare("MyISAM") &&
752
777
        ((sql_field->flags & BLOB_FLAG) ||
753
 
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
 
778
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED)))
754
779
      (*db_options)|= HA_OPTION_PACK_RECORD;
755
780
    it2.rewind();
756
781
  }
818
843
      fk_key_count++;
819
844
      if (((Foreign_key *)key)->validate(alter_info->create_list))
820
845
        return true;
821
 
 
822
846
      Foreign_key *fk_key= (Foreign_key*) key;
823
 
 
824
 
      add_foreign_key_to_table_message(&create_proto,
825
 
                                       fk_key->name.str,
826
 
                                       fk_key->columns,
827
 
                                       fk_key->ref_table,
828
 
                                       fk_key->ref_columns,
829
 
                                       fk_key->delete_opt,
830
 
                                       fk_key->update_opt,
831
 
                                       fk_key->match_opt);
832
 
 
833
847
      if (fk_key->ref_columns.elements &&
834
848
          fk_key->ref_columns.elements != fk_key->columns.elements)
835
849
      {
864
878
             key2->name.str != ignore_key &&
865
879
             !foreign_key_prefix(key, key2)))
866
880
        {
867
 
          /* @todo issue warning message */
 
881
          /* TODO: issue warning message */
868
882
          /* mark that the generated key should be ignored */
869
883
          if (!key2->generated ||
870
884
              (key->generated && key->columns.elements <
898
912
    return(true);
899
913
  }
900
914
 
901
 
  (*key_info_buffer)= key_info= (KeyInfo*) memory::sql_calloc(sizeof(KeyInfo) * (*key_count));
902
 
  key_part_info=(KeyPartInfo*) memory::sql_calloc(sizeof(KeyPartInfo)*key_parts);
 
915
  (*key_info_buffer)= key_info= (KEY*) memory::sql_calloc(sizeof(KEY) * (*key_count));
 
916
  key_part_info=(KEY_PART_INFO*) memory::sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
903
917
  if (!*key_info_buffer || ! key_part_info)
904
918
    return(true);                               // Out of memory
905
919
 
939
953
    key_info->usable_key_parts= key_number;
940
954
    key_info->algorithm= key->key_create_info.algorithm;
941
955
 
 
956
    /* Take block size from key part or table part */
 
957
    /*
 
958
      TODO: Add warning if block size changes. We can't do it here, as
 
959
      this may depend on the size of the key
 
960
    */
 
961
    key_info->block_size= (key->key_create_info.block_size ?
 
962
                           key->key_create_info.block_size :
 
963
                           create_proto.options().key_block_size());
 
964
 
 
965
    if (key_info->block_size)
 
966
      key_info->flags|= HA_USES_BLOCK_SIZE;
 
967
 
942
968
    uint32_t tmp_len= system_charset_info->cset->charpos(system_charset_info,
943
969
                                           key->key_create_info.comment.str,
944
970
                                           key->key_create_info.comment.str +
1048
1074
 
1049
1075
      key_part_info->fieldnr= field;
1050
1076
      key_part_info->offset=  (uint16_t) sql_field->offset;
1051
 
      key_part_info->key_type= 0;
 
1077
      key_part_info->key_type=sql_field->pack_flag;
1052
1078
      length= sql_field->key_length;
1053
1079
 
1054
1080
      if (column->length)
1116
1142
      key_part_info->length=(uint16_t) length;
1117
1143
      /* Use packed keys for long strings on the first column */
1118
1144
      if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
1119
 
          (length >= KEY_DEFAULT_PACK_LENGTH &&
1120
 
           (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
1121
 
            sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
 
1145
          (length >= KEY_DEFAULT_PACK_LENGTH &&
 
1146
           (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
 
1147
      sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
1122
1148
      {
1123
1149
        if ((column_nr == 0 && sql_field->sql_type == DRIZZLE_TYPE_BLOB) ||
1124
1150
            sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)
1125
 
        {
1126
1151
          key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
1127
 
        }
1128
1152
        else
1129
 
        {
1130
1153
          key_info->flags|= HA_PACK_KEY;
1131
 
        }
1132
1154
      }
1133
1155
      /* Check if the key segment is partial, set the key flag accordingly */
1134
1156
      if (length != sql_field->key_length)
1190
1212
    return(true);
1191
1213
  }
1192
1214
  /* Sort keys in optimized order */
1193
 
  internal::my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KeyInfo),
 
1215
  internal::my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KEY),
1194
1216
                     (qsort_cmp) sort_keys);
1195
1217
 
1196
1218
  /* Check fields. */
1265
1287
}
1266
1288
 
1267
1289
static bool locked_create_event(Session *session,
1268
 
                                const TableIdentifier &identifier,
 
1290
                                TableIdentifier &identifier,
1269
1291
                                HA_CREATE_INFO *create_info,
1270
1292
                                message::Table &table_proto,
1271
1293
                                AlterInfo *alter_info,
1273
1295
                                bool internal_tmp_table,
1274
1296
                                uint db_options,
1275
1297
                                uint key_count,
1276
 
                                KeyInfo *key_info_buffer)
 
1298
                                KEY *key_info_buffer)
1277
1299
{
1278
1300
  bool error= true;
1279
1301
 
1300
1322
        return error;
1301
1323
      }
1302
1324
 
1303
 
      std::string path;
1304
 
      identifier.getSQLPath(path);
1305
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1306
 
 
 
1325
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1307
1326
      return error;
1308
1327
    }
1309
1328
 
1320
1339
      /*
1321
1340
        @todo improve this error condition.
1322
1341
      */
1323
 
      if (definition::Cache::singleton().find(identifier.getKey()))
 
1342
      if (TableShare::getShare(identifier))
1324
1343
      {
1325
 
        std::string path;
1326
 
        identifier.getSQLPath(path);
1327
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1328
 
 
 
1344
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1329
1345
        return error;
1330
1346
      }
1331
1347
    }
1401
1417
*/
1402
1418
 
1403
1419
bool mysql_create_table_no_lock(Session *session,
1404
 
                                const TableIdentifier &identifier,
 
1420
                                TableIdentifier &identifier,
1405
1421
                                HA_CREATE_INFO *create_info,
1406
1422
                                message::Table &table_proto,
1407
1423
                                AlterInfo *alter_info,
1410
1426
                                bool is_if_not_exists)
1411
1427
{
1412
1428
  uint          db_options, key_count;
1413
 
  KeyInfo               *key_info_buffer;
 
1429
  KEY           *key_info_buffer;
1414
1430
  bool          error= true;
 
1431
  TableShare share;
1415
1432
 
1416
1433
  /* Check for duplicate fields and check type of table to create */
1417
1434
  if (not alter_info->create_list.elements)
1423
1440
  assert(identifier.getTableName() == table_proto.name());
1424
1441
  db_options= create_info->table_options;
1425
1442
 
 
1443
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
 
1444
    db_options|=HA_OPTION_PACK_RECORD;
 
1445
 
1426
1446
  set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1427
1447
 
1428
1448
  /* Build a Table object to pass down to the engine, and the do the actual create. */
1429
1449
  if (not mysql_prepare_create_table(session, create_info, table_proto, alter_info,
1430
 
                                     internal_tmp_table,
1431
 
                                     &db_options,
1432
 
                                     &key_info_buffer, &key_count,
1433
 
                                     select_field_count))
 
1450
                                 internal_tmp_table,
 
1451
                                 &db_options,
 
1452
                                 &key_info_buffer, &key_count,
 
1453
                                 select_field_count))
1434
1454
  {
1435
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* CREATE TABLE (some confussion on naming, double check) */
 
1455
    pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1436
1456
    error= locked_create_event(session,
1437
1457
                               identifier,
1438
1458
                               create_info,
1442
1462
                               internal_tmp_table,
1443
1463
                               db_options, key_count,
1444
1464
                               key_info_buffer);
 
1465
    pthread_mutex_unlock(&LOCK_open);
1445
1466
  }
1446
1467
 
1447
1468
  session->set_proc_info("After create");
1453
1474
  @note the following two methods implement create [temporary] table.
1454
1475
*/
1455
1476
static bool drizzle_create_table(Session *session,
1456
 
                                 const TableIdentifier &identifier,
 
1477
                                 TableIdentifier &identifier,
1457
1478
                                 HA_CREATE_INFO *create_info,
1458
1479
                                 message::Table &table_proto,
1459
1480
                                 AlterInfo *alter_info,
1480
1501
    }
1481
1502
    else
1482
1503
    {
1483
 
      std::string path;
1484
 
      identifier.getSQLPath(path);
1485
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
1504
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1486
1505
      result= true;
1487
1506
    }
1488
1507
  }
1500
1519
 
1501
1520
  if (name_lock)
1502
1521
  {
1503
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* Lock for removing name_lock during table create */
 
1522
    pthread_mutex_lock(&LOCK_open); /* Lock for removing name_lock during table create */
1504
1523
    session->unlink_open_table(name_lock);
 
1524
    pthread_mutex_unlock(&LOCK_open);
1505
1525
  }
1506
1526
 
1507
1527
  return(result);
1512
1532
  Database locking aware wrapper for mysql_create_table_no_lock(),
1513
1533
*/
1514
1534
bool mysql_create_table(Session *session,
1515
 
                        const TableIdentifier &identifier,
 
1535
                        TableIdentifier &identifier,
1516
1536
                        HA_CREATE_INFO *create_info,
1517
1537
                        message::Table &table_proto,
1518
1538
                        AlterInfo *alter_info,
1548
1568
**/
1549
1569
 
1550
1570
static bool
1551
 
check_if_keyname_exists(const char *name, KeyInfo *start, KeyInfo *end)
 
1571
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
1552
1572
{
1553
 
  for (KeyInfo *key=start ; key != end ; key++)
 
1573
  for (KEY *key=start ; key != end ; key++)
1554
1574
    if (!my_strcasecmp(system_charset_info,name,key->name))
1555
1575
      return 1;
1556
1576
  return 0;
1558
1578
 
1559
1579
 
1560
1580
static char *
1561
 
make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end)
 
1581
make_unique_key_name(const char *field_name,KEY *start,KEY *end)
1562
1582
{
1563
1583
  char buff[MAX_FIELD_NAME],*buff_end;
1564
1584
 
1593
1613
 
1594
1614
  SYNOPSIS
1595
1615
    mysql_rename_table()
1596
 
      session
1597
1616
      base                      The plugin::StorageEngine handle.
1598
1617
      old_db                    The old database name.
1599
1618
      old_name                  The old table name.
1600
1619
      new_db                    The new database name.
1601
1620
      new_name                  The new table name.
 
1621
      flags                     flags for build_table_filename().
 
1622
                                FN_FROM_IS_TMP old_name is temporary.
 
1623
                                FN_TO_IS_TMP   new_name is temporary.
1602
1624
 
1603
1625
  RETURN
1604
1626
    false   OK
1606
1628
*/
1607
1629
 
1608
1630
bool
1609
 
mysql_rename_table(Session &session,
1610
 
                   plugin::StorageEngine *base,
1611
 
                   const TableIdentifier &from,
1612
 
                   const TableIdentifier &to)
 
1631
mysql_rename_table(plugin::StorageEngine *base,
 
1632
                   TableIdentifier &from,
 
1633
                   TableIdentifier &to,
 
1634
                   uint32_t )
1613
1635
{
 
1636
  Session *session= current_session;
1614
1637
  int error= 0;
1615
1638
 
1616
1639
  assert(base);
1621
1644
    return true;
1622
1645
  }
1623
1646
 
1624
 
  error= base->renameTable(session, from, to);
 
1647
  error= base->renameTable(*session, from, to);
1625
1648
 
1626
1649
  if (error == HA_ERR_WRONG_COMMAND)
1627
1650
  {
1629
1652
  }
1630
1653
  else if (error)
1631
1654
  {
1632
 
    std::string from_path;
1633
 
    std::string to_path;
1634
 
 
1635
 
    from.getSQLPath(from_path);
1636
 
    to.getSQLPath(to_path);
1637
 
 
1638
 
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from_path.c_str();
1639
 
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to_path.c_str();
 
1655
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from.getSQLPath().c_str();
 
1656
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to.getSQLPath().c_str();
1640
1657
 
1641
1658
    my_error(ER_ERROR_ON_RENAME, MYF(0), from_identifier, to_identifier, error);
1642
1659
  }
1660
1677
   the table is closed.
1661
1678
 
1662
1679
  PREREQUISITES
1663
 
    Lock on table::Cache::singleton().mutex()
 
1680
    Lock on LOCK_open
1664
1681
    Win32 clients must also have a WRITE LOCK on the table !
1665
1682
*/
1666
1683
 
1668
1685
                              enum ha_extra_function function)
1669
1686
{
1670
1687
 
1671
 
  safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
 
1688
  safe_mutex_assert_owner(&LOCK_open);
1672
1689
 
1673
1690
  table->cursor->extra(function);
1674
1691
  /* Mark all tables that are in use as 'old' */
1675
 
  session->abortLock(table);    /* end threads waiting on lock */
 
1692
  mysql_lock_abort(session, table);     /* end threads waiting on lock */
1676
1693
 
1677
1694
  /* Wait until all there are no other threads that has this table open */
1678
 
  TableIdentifier identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName());
1679
 
  table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
 
1695
  remove_table_from_cache(session, table->s->getSchemaName(),
 
1696
                          table->s->table_name.str,
 
1697
                          RTFC_WAIT_OTHER_THREAD_FLAG);
1680
1698
}
1681
1699
 
1682
1700
/*
1692
1710
    reopen the table.
1693
1711
 
1694
1712
  PREREQUISITES
1695
 
    Lock on table::Cache::singleton().mutex()
 
1713
    Lock on LOCK_open
1696
1714
    Win32 clients must also have a WRITE LOCK on the table !
1697
1715
*/
1698
1716
 
1703
1721
  /* Close lock if this is not got with LOCK TABLES */
1704
1722
  if (lock)
1705
1723
  {
1706
 
    unlockTables(lock);
 
1724
    mysql_unlock_tables(this, lock);
1707
1725
    lock= NULL;                 // Start locked threads
1708
1726
  }
1709
1727
  /* Close all copies of 'table'.  This also frees all LOCK TABLES lock */
1710
1728
  unlink_open_table(table);
1711
1729
 
1712
 
  /* When lock on table::Cache::singleton().mutex() is freed other threads can continue */
1713
 
  locking::broadcast_refresh();
 
1730
  /* When lock on LOCK_open is freed other threads can continue */
 
1731
  broadcast_refresh();
1714
1732
}
1715
1733
 
1716
1734
/*
1754
1772
  for (table= tables; table; table= table->next_local)
1755
1773
  {
1756
1774
    char table_name[NAME_LEN*2+2];
 
1775
    char* db = table->db;
1757
1776
    bool fatal_error=0;
1758
1777
 
1759
 
    snprintf(table_name, sizeof(table_name), "%s.%s", table->getSchemaName(), table->getTableName());
 
1778
    sprintf(table_name,"%s.%s",db,table->table_name);
1760
1779
    table->lock_type= lock_type;
1761
1780
    /* open only one table from local list of command */
1762
1781
    {
1769
1788
      /*
1770
1789
        Time zone tables and SP tables can be add to lex->query_tables list,
1771
1790
        so it have to be prepared.
1772
 
        @todo Investigate if we can put extra tables into argument instead of using lex->query_tables
 
1791
        TODO: Investigate if we can put extra tables into argument instead of
 
1792
        using lex->query_tables
1773
1793
      */
1774
1794
      lex->query_tables= table;
1775
1795
      lex->query_tables_last= &table->next_global;
1809
1829
      length= snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
1810
1830
                       table_name);
1811
1831
      session->client->store(buff, length);
1812
 
      transaction_services.autocommitOrRollback(session, false);
 
1832
      transaction_services.ha_autocommit_or_rollback(session, false);
1813
1833
      session->endTransaction(COMMIT);
1814
1834
      session->close_thread_tables();
1815
1835
      lex->reset_query_tables_list(false);
1820
1840
    }
1821
1841
 
1822
1842
    /* Close all instances of the table to allow repair to rename files */
1823
 
    if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
 
1843
    if (lock_type == TL_WRITE && table->table->s->version)
1824
1844
    {
1825
 
      table::Cache::singleton().mutex().lock(); /* Lock type is TL_WRITE and we lock to repair the table */
1826
 
      const char *old_message=session->enter_cond(COND_refresh, table::Cache::singleton().mutex(),
1827
 
                                                  "Waiting to get writelock");
1828
 
      session->abortLock(table->table);
1829
 
      TableIdentifier identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1830
 
      table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG);
 
1845
      pthread_mutex_lock(&LOCK_open); /* Lock type is TL_WRITE and we lock to repair the table */
 
1846
      const char *old_message=session->enter_cond(&COND_refresh, &LOCK_open,
 
1847
                                              "Waiting to get writelock");
 
1848
      mysql_lock_abort(session,table->table);
 
1849
      remove_table_from_cache(session, table->table->s->getSchemaName(),
 
1850
                              table->table->s->table_name.str,
 
1851
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
1852
                              RTFC_CHECK_KILLED_FLAG);
1831
1853
      session->exit_cond(old_message);
1832
 
      if (session->getKilled())
 
1854
      if (session->killed)
1833
1855
        goto err;
1834
1856
      open_for_modify= 0;
1835
1857
    }
1916
1938
    if (table->table)
1917
1939
    {
1918
1940
      if (fatal_error)
1919
 
      {
1920
 
        table->table->getMutableShare()->resetVersion();               // Force close of table
1921
 
      }
 
1941
        table->table->s->version=0;               // Force close of table
1922
1942
      else if (open_for_modify)
1923
1943
      {
1924
 
        if (table->table->getShare()->getType())
1925
 
        {
 
1944
        if (table->table->s->tmp_table)
1926
1945
          table->table->cursor->info(HA_STATUS_CONST);
1927
 
        }
1928
1946
        else
1929
1947
        {
1930
 
          boost::unique_lock<boost::mutex> lock(table::Cache::singleton().mutex());
1931
 
          TableIdentifier identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1932
 
          table::Cache::singleton().removeTable(session, identifier, RTFC_NO_FLAG);
 
1948
          pthread_mutex_lock(&LOCK_open);
 
1949
          remove_table_from_cache(session, table->table->s->getSchemaName(),
 
1950
                                  table->table->s->table_name.str, RTFC_NO_FLAG);
 
1951
          pthread_mutex_unlock(&LOCK_open);
1933
1952
        }
1934
1953
      }
1935
1954
    }
1936
 
    transaction_services.autocommitOrRollback(session, false);
 
1955
    transaction_services.ha_autocommit_or_rollback(session, false);
1937
1956
    session->endTransaction(COMMIT);
1938
1957
    session->close_thread_tables();
1939
1958
    table->table=0;                             // For query cache
1945
1964
  return(false);
1946
1965
 
1947
1966
err:
1948
 
  transaction_services.autocommitOrRollback(session, true);
 
1967
  transaction_services.ha_autocommit_or_rollback(session, true);
1949
1968
  session->endTransaction(ROLLBACK);
1950
1969
  session->close_thread_tables();                       // Shouldn't be needed
1951
1970
  if (table)
1953
1972
  return(true);
1954
1973
}
1955
1974
 
 
1975
/*
 
1976
  We have to write the query before we unlock the named table.
 
1977
 
 
1978
  Since temporary tables are not replicated under row-based
 
1979
  replication, CREATE TABLE ... LIKE ... needs special
 
1980
  treatement.  We have four cases to consider, according to the
 
1981
  following decision table:
 
1982
 
 
1983
  ==== ========= ========= ==============================
 
1984
  Case    Target    Source Write to binary log
 
1985
  ==== ========= ========= ==============================
 
1986
  1       normal    normal Original statement
 
1987
  2       normal temporary Generated statement
 
1988
  3    temporary    normal Nothing
 
1989
  4    temporary temporary Nothing
 
1990
  ==== ========= ========= ==============================
 
1991
*/
 
1992
static bool replicateCreateTableLike(Session *session, TableList *table, Table *name_lock,
 
1993
                                     bool is_src_table_tmp, bool is_if_not_exists)
 
1994
{
 
1995
  if (is_src_table_tmp)
 
1996
  {
 
1997
    char buf[2048];
 
1998
    String query(buf, sizeof(buf), system_charset_info);
 
1999
    query.length(0);  // Have to zero it since constructor doesn't
 
2000
 
 
2001
 
 
2002
    /*
 
2003
      Here we open the destination table, on which we already have
 
2004
      name-lock. This is needed for store_create_info() to work.
 
2005
      The table will be closed by unlink_open_table() at the end
 
2006
      of this function.
 
2007
    */
 
2008
    table->table= name_lock;
 
2009
    pthread_mutex_lock(&LOCK_open); /* Open new table we have just acquired */
 
2010
    if (session->reopen_name_locked_table(table, false))
 
2011
    {
 
2012
      pthread_mutex_unlock(&LOCK_open);
 
2013
      return false;
 
2014
    }
 
2015
    pthread_mutex_unlock(&LOCK_open);
 
2016
 
 
2017
    int result= store_create_info(table, &query, is_if_not_exists);
 
2018
 
 
2019
    assert(result == 0); // store_create_info() always return 0
 
2020
    write_bin_log(session, query.ptr());
 
2021
  }
 
2022
  else                                      // Case 1
 
2023
  {
 
2024
    write_bin_log(session, session->query.c_str());
 
2025
  }
 
2026
 
 
2027
  return true;
 
2028
}
 
2029
 
1956
2030
  /*
1957
2031
    Create a new table by copying from source table
1958
2032
 
1959
2033
    Altough exclusive name-lock on target table protects us from concurrent
1960
2034
    DML and DDL operations on it we still want to wrap .FRM creation and call
1961
2035
    to plugin::StorageEngine::createTable() in critical section protected by
1962
 
    table::Cache::singleton().mutex() in order to provide minimal atomicity against operations which
 
2036
    LOCK_open in order to provide minimal atomicity against operations which
1963
2037
    disregard name-locks, like I_S implementation, for example. This is a
1964
2038
    temporary and should not be copied. Instead we should fix our code to
1965
2039
    always honor name-locks.
1966
2040
 
1967
 
    Also some engines (e.g. NDB cluster) require that table::Cache::singleton().mutex() should be held
 
2041
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
1968
2042
    during the call to plugin::StorageEngine::createTable().
1969
2043
    See bug #28614 for more info.
1970
2044
  */
1971
2045
static bool create_table_wrapper(Session &session, const message::Table& create_table_proto,
1972
 
                                 const TableIdentifier &destination_identifier,
1973
 
                                 const TableIdentifier &src_table,
 
2046
                                 TableIdentifier &destination_identifier,
 
2047
                                 TableIdentifier &src_table,
1974
2048
                                 bool is_engine_set)
1975
2049
{
1976
2050
  int protoerr= EEXIST;
1977
2051
  message::Table new_proto;
1978
 
  message::table::shared_ptr src_proto;
 
2052
  message::Table src_proto;
1979
2053
 
1980
2054
  protoerr= plugin::StorageEngine::getTableDefinition(session,
1981
2055
                                                      src_table,
1982
2056
                                                      src_proto);
1983
 
  new_proto.CopyFrom(*src_proto);
 
2057
  new_proto.CopyFrom(src_proto);
1984
2058
 
1985
2059
  if (destination_identifier.isTmp())
1986
2060
  {
1993
2067
 
1994
2068
  if (is_engine_set)
1995
2069
  {
1996
 
    new_proto.mutable_engine()->set_name(create_table_proto.engine().name());
 
2070
    message::Table::StorageEngine *protoengine;
 
2071
 
 
2072
    protoengine= new_proto.mutable_engine();
 
2073
    protoengine->set_name(create_table_proto.engine().name());
1997
2074
  }
1998
2075
 
1999
2076
  { // We now do a selective copy of elements on to the new table.
2019
2096
  */
2020
2097
  int err= plugin::StorageEngine::createTable(session,
2021
2098
                                              destination_identifier,
2022
 
                                              new_proto);
2023
 
 
2024
 
  if (err == false && not destination_identifier.isTmp())
2025
 
  {
2026
 
    TransactionServices &transaction_services= TransactionServices::singleton();
2027
 
    transaction_services.createTable(&session, new_proto);
2028
 
  }
 
2099
                                              true, new_proto);
2029
2100
 
2030
2101
  return err ? false : true;
2031
2102
}
2046
2117
*/
2047
2118
 
2048
2119
bool mysql_create_like_table(Session* session,
2049
 
                             const TableIdentifier &destination_identifier,
 
2120
                             TableIdentifier &destination_identifier,
2050
2121
                             TableList* table, TableList* src_table,
2051
2122
                             message::Table &create_table_proto,
2052
2123
                             bool is_if_not_exists,
2053
2124
                             bool is_engine_set)
2054
2125
{
 
2126
  Table *name_lock= 0;
 
2127
  char *db= table->db;
 
2128
  char *table_name= table->table_name;
2055
2129
  bool res= true;
2056
2130
  uint32_t not_used;
 
2131
  bool was_created;
2057
2132
 
2058
2133
  /*
2059
2134
    By opening source table we guarantee that it exists and no concurrent
2067
2142
  if (session->open_tables_from_list(&src_table, &not_used))
2068
2143
    return true;
2069
2144
 
2070
 
  TableIdentifier src_identifier(src_table->table->getShare()->getSchemaName(),
2071
 
                                 src_table->table->getShare()->getTableName(), src_table->table->getShare()->getType());
 
2145
  TableIdentifier src_identifier(src_table->table->s->getSchemaName(),
 
2146
                                 src_table->table->s->table_name.str, src_table->table->s->tmp_table);
2072
2147
 
2073
2148
 
2074
2149
 
2075
2150
  /*
2076
2151
    Check that destination tables does not exist. Note that its name
2077
2152
    was already checked when it was added to the table list.
2078
 
 
2079
 
    For temporary tables we don't aim to grab locks.
2080
2153
  */
2081
2154
  bool table_exists= false;
2082
2155
  if (destination_identifier.isTmp())
2083
2156
  {
2084
 
    if (session->find_temporary_table(destination_identifier))
 
2157
    if (session->find_temporary_table(db, table_name))
2085
2158
    {
2086
2159
      table_exists= true;
2087
2160
    }
2088
 
    else
2089
 
    {
2090
 
      bool was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2091
 
                                             src_identifier, is_engine_set);
2092
 
      if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2093
 
      {
2094
 
        (void) session->rm_temporary_table(destination_identifier, true);
2095
 
      }
2096
 
      else if (not session->open_temporary_table(destination_identifier))
2097
 
      {
2098
 
        // We created, but we can't open... also, a hack.
2099
 
        (void) session->rm_temporary_table(destination_identifier, true);
2100
 
      }
2101
 
      else
2102
 
      {
2103
 
        res= false;
2104
 
      }
2105
 
    }
2106
2161
  }
2107
 
  else // Standard table which will require locks.
 
2162
  else
2108
2163
  {
2109
 
    Table *name_lock= 0;
2110
 
 
2111
 
    if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
 
2164
    if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
2112
2165
    {
2113
2166
      if (name_lock)
2114
2167
      {
2115
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
 
2168
        pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2116
2169
        session->unlink_open_table(name_lock);
 
2170
        pthread_mutex_unlock(&LOCK_open);
2117
2171
      }
2118
2172
 
2119
2173
      return res;
2127
2181
    {
2128
2182
      table_exists= true;
2129
2183
    }
2130
 
    else // Otherwise we create the table
2131
 
    {
2132
 
      bool was_created;
2133
 
      {
2134
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
2135
 
        was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2136
 
                                               src_identifier, is_engine_set);
2137
 
      }
2138
 
 
2139
 
      // So we blew the creation of the table, and we scramble to clean up
2140
 
      // anything that might have been created (read... it is a hack)
2141
 
      if (not was_created)
2142
 
      {
2143
 
        plugin::StorageEngine::dropTable(*session, destination_identifier);
2144
 
      } 
2145
 
      else
2146
 
      {
2147
 
        res= false;
2148
 
      }
2149
 
    }
2150
 
 
2151
 
    if (name_lock)
2152
 
    {
2153
 
      boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2154
 
      session->unlink_open_table(name_lock);
2155
 
    }
2156
2184
  }
2157
2185
 
2158
2186
  if (table_exists)
2161
2189
    {
2162
2190
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
2163
2191
      snprintf(warn_buff, sizeof(warn_buff),
2164
 
               ER(ER_TABLE_EXISTS_ERROR), table->getTableName());
 
2192
               ER(ER_TABLE_EXISTS_ERROR), table_name);
2165
2193
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2166
2194
                   ER_TABLE_EXISTS_ERROR,warn_buff);
2167
2195
      res= false;
2168
2196
    }
2169
2197
    else
2170
2198
    {
2171
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table->getTableName());
2172
 
    }
 
2199
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
2200
    }
 
2201
  }
 
2202
  else // Otherwise we create the table
 
2203
  {
 
2204
    pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
 
2205
    was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
 
2206
                                      src_identifier, is_engine_set);
 
2207
    pthread_mutex_unlock(&LOCK_open);
 
2208
 
 
2209
    // So we blew the creation of the table, and we scramble to clean up
 
2210
    // anything that might have been created (read... it is a hack)
 
2211
    if (not was_created)
 
2212
    {
 
2213
      if (destination_identifier.isTmp())
 
2214
      {
 
2215
        (void) session->rm_temporary_table(destination_identifier);
 
2216
      }
 
2217
      else
 
2218
      {
 
2219
        quick_rm_table(*session, destination_identifier);
 
2220
      }
 
2221
    } 
 
2222
    else if (destination_identifier.isTmp() && not session->open_temporary_table(destination_identifier))
 
2223
    {
 
2224
      // We created, but we can't open... also, a hack.
 
2225
      (void) session->rm_temporary_table(destination_identifier);
 
2226
    }
 
2227
    else
 
2228
    {
 
2229
      if (not destination_identifier.isTmp())
 
2230
      {
 
2231
        bool rc= replicateCreateTableLike(session, table, name_lock, (src_table->table->s->tmp_table), is_if_not_exists);
 
2232
        (void)rc;
 
2233
      }
 
2234
 
 
2235
      res= false;
 
2236
    }
 
2237
  }
 
2238
 
 
2239
  if (name_lock)
 
2240
  {
 
2241
    pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
 
2242
    session->unlink_open_table(name_lock);
 
2243
    pthread_mutex_unlock(&LOCK_open);
2173
2244
  }
2174
2245
 
2175
2246
  return(res);
2196
2267
                                &Cursor::ha_check));
2197
2268
}
2198
2269
 
 
2270
 
 
2271
bool mysql_checksum_table(Session *session, TableList *tables,
 
2272
                          HA_CHECK_OPT *)
 
2273
{
 
2274
  TableList *table;
 
2275
  List<Item> field_list;
 
2276
  Item *item;
 
2277
 
 
2278
  field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
 
2279
  item->maybe_null= 1;
 
2280
  field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
 
2281
                                          MY_INT64_NUM_DECIMAL_DIGITS));
 
2282
  item->maybe_null= 1;
 
2283
  if (session->client->sendFields(&field_list))
 
2284
    return true;
 
2285
 
 
2286
  /* Open one table after the other to keep lock time as short as possible. */
 
2287
  for (table= tables; table; table= table->next_local)
 
2288
  {
 
2289
    char table_name[NAME_LEN*2+2];
 
2290
    Table *t;
 
2291
 
 
2292
    sprintf(table_name,"%s.%s",table->db,table->table_name);
 
2293
 
 
2294
    t= table->table= session->openTableLock(table, TL_READ);
 
2295
    session->clear_error();                     // these errors shouldn't get client
 
2296
 
 
2297
    session->client->store(table_name);
 
2298
 
 
2299
    if (!t)
 
2300
    {
 
2301
      /* Table didn't exist */
 
2302
      session->client->store();
 
2303
      session->clear_error();
 
2304
    }
 
2305
    else
 
2306
    {
 
2307
      /**
 
2308
        @note if the engine keeps a checksum then we return the checksum, otherwise we calculate
 
2309
      */
 
2310
      if (t->cursor->getEngine()->check_flag(HTON_BIT_HAS_CHECKSUM))
 
2311
      {
 
2312
        session->client->store((uint64_t)t->cursor->checksum());
 
2313
      }
 
2314
      else
 
2315
      {
 
2316
        /* calculating table's checksum */
 
2317
        internal::ha_checksum crc= 0;
 
2318
        unsigned char null_mask=256 -  (1 << t->s->last_null_bit_pos);
 
2319
 
 
2320
        t->use_all_columns();
 
2321
 
 
2322
        if (t->cursor->ha_rnd_init(1))
 
2323
          session->client->store();
 
2324
        else
 
2325
        {
 
2326
          for (;;)
 
2327
          {
 
2328
            internal::ha_checksum row_crc= 0;
 
2329
            int error= t->cursor->rnd_next(t->record[0]);
 
2330
            if (unlikely(error))
 
2331
            {
 
2332
              if (error == HA_ERR_RECORD_DELETED)
 
2333
                continue;
 
2334
              break;
 
2335
            }
 
2336
            if (t->s->null_bytes)
 
2337
            {
 
2338
              /* fix undefined null bits */
 
2339
              t->record[0][t->s->null_bytes-1] |= null_mask;
 
2340
              if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
 
2341
                t->record[0][0] |= 1;
 
2342
 
 
2343
              row_crc= internal::my_checksum(row_crc, t->record[0], t->s->null_bytes);
 
2344
            }
 
2345
 
 
2346
            for (uint32_t i= 0; i < t->s->fields; i++ )
 
2347
            {
 
2348
              Field *f= t->field[i];
 
2349
              if ((f->type() == DRIZZLE_TYPE_BLOB) ||
 
2350
                  (f->type() == DRIZZLE_TYPE_VARCHAR))
 
2351
              {
 
2352
                String tmp;
 
2353
                f->val_str(&tmp);
 
2354
                row_crc= internal::my_checksum(row_crc, (unsigned char*) tmp.ptr(), tmp.length());
 
2355
              }
 
2356
              else
 
2357
                row_crc= internal::my_checksum(row_crc, f->ptr,
 
2358
                                     f->pack_length());
 
2359
            }
 
2360
 
 
2361
            crc+= row_crc;
 
2362
          }
 
2363
          session->client->store((uint64_t)crc);
 
2364
          t->cursor->ha_rnd_end();
 
2365
        }
 
2366
      }
 
2367
      session->clear_error();
 
2368
      session->close_thread_tables();
 
2369
      table->table=0;                           // For query cache
 
2370
    }
 
2371
    if (session->client->flush())
 
2372
      goto err;
 
2373
  }
 
2374
 
 
2375
  session->my_eof();
 
2376
  return(false);
 
2377
 
 
2378
 err:
 
2379
  session->close_thread_tables();                       // Shouldn't be needed
 
2380
  if (table)
 
2381
    table->table=0;
 
2382
  return(true);
 
2383
}
 
2384
 
2199
2385
} /* namespace drizzled */