~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

  • Committer: Monty Taylor
  • Date: 2010-12-06 20:03:48 UTC
  • mto: (1977.1.1 build)
  • mto: This revision was merged to the branch mainline in revision 1980.
  • Revision ID: mordred@inaugust.com-20101206200348-ds31k1kc8ougn7fg
four more variables

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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  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/table_identifier.h>
 
39
#include <drizzled/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
 
44
46
 
45
47
#include "drizzled/statement/alter_table.h"
46
48
#include "drizzled/sql_table.h"
49
51
#include <algorithm>
50
52
#include <sstream>
51
53
 
 
54
#include <boost/unordered_set.hpp>
 
55
 
52
56
using namespace std;
53
57
 
54
58
namespace drizzled
55
59
{
56
60
 
57
 
extern plugin::StorageEngine *myisam_engine;
58
61
extern pid_t current_pid;
59
62
 
60
 
bool is_primary_key(KEY *key_info)
 
63
bool is_primary_key(KeyInfo *key_info)
61
64
{
62
65
  static const char * primary_key_name="PRIMARY";
63
66
  return (strcmp(key_info->name, primary_key_name)==0);
72
75
    return NULL;
73
76
}
74
77
 
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);
 
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);
77
80
 
78
81
static bool prepare_blob_field(Session *session, CreateField *sql_field);
79
82
 
104
107
    cursor
105
108
*/
106
109
 
107
 
void write_bin_log(Session *session,
108
 
                   char const *query)
 
110
void write_bin_log(Session *session, const std::string &query)
109
111
{
110
112
  TransactionServices &transaction_services= TransactionServices::singleton();
111
113
  transaction_services.rawStatement(session, query);
112
114
}
113
115
 
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
 
 
138
116
/*
139
117
  Execute the drop of a normal or temporary table
140
118
 
146
124
                        In this case we give an warning of level 'NOTE'
147
125
    drop_temporary      Only drop temporary tables
148
126
 
149
 
  TODO:
 
127
  @todo
150
128
    When logging to the binary log, we should log
151
129
    tmp_tables and transactional tables as separate statements if we
152
130
    are in a transaction;  This is needed to get these tables into the
170
148
  int error= 0;
171
149
  bool foreign_key_error= false;
172
150
 
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;
 
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:
 
174
        error= 1;
237
175
        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
250
 
        error= 1;
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
 
      {
 
176
      default:
 
177
        // temporary table not found
258
178
        error= 0;
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
 
    }
 
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();
281
248
  }
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);
287
249
  error= 0;
288
250
 
289
251
  if (wrong_tables.length())
300
262
    error= 1;
301
263
  }
302
264
 
303
 
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
 
265
  table::Cache::singleton().mutex().lock(); /* final bit in rm table lock */
304
266
 
305
267
err_with_placeholders:
306
 
  unlock_table_names(tables, NULL);
307
 
  pthread_mutex_unlock(&LOCK_open);
 
268
  tables->unlock_table_names();
 
269
  table::Cache::singleton().mutex().unlock();
308
270
  session->no_warnings_for_error= 0;
309
271
 
310
272
  return error;
311
273
}
312
274
 
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
 
 
334
275
/*
335
276
  Sort keys in the following order:
336
277
  - PRIMARY KEY
344
285
  PRIMARY keys are prioritized.
345
286
*/
346
287
 
347
 
static int sort_keys(KEY *a, KEY *b)
 
288
static int sort_keys(KeyInfo *a, KeyInfo *b)
348
289
{
349
290
  ulong a_flags= a->flags, b_flags= b->flags;
350
291
 
396
337
    1             Error
397
338
*/
398
339
 
 
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
 
399
374
static bool check_duplicates_in_interval(const char *set_or_name,
400
375
                                         const char *name, TYPELIB *typelib,
401
376
                                         const CHARSET_INFO * const cs,
406
381
  unsigned int *cur_length= typelib->type_lengths;
407
382
  *dup_val_count= 0;
408
383
 
409
 
  for ( ; tmp.count > 1; cur_value++, cur_length++)
 
384
  boost::unordered_set<typelib_set_member, typelib_set_member_hasher> interval_set;
 
385
 
 
386
  for ( ; tmp.count > 0; cur_value++, cur_length++)
410
387
  {
411
388
    tmp.type_names++;
412
389
    tmp.type_lengths++;
413
390
    tmp.count--;
414
 
    if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
 
391
    if (interval_set.find(typelib_set_member(*cur_value, *cur_length, cs)) != interval_set.end())
415
392
    {
416
393
      my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
417
394
               name,*cur_value,set_or_name);
418
395
      return 1;
419
396
    }
 
397
    else
 
398
      interval_set.insert(typelib_set_member(*cur_value, *cur_length, cs));
420
399
  }
421
400
  return 0;
422
401
}
489
468
 
490
469
  switch (sql_field->sql_type) {
491
470
  case DRIZZLE_TYPE_BLOB:
492
 
    sql_field->pack_flag= pack_length_to_packflag(sql_field->pack_length - portable_sizeof_char_ptr);
493
471
    sql_field->length= 8; // Unireg field length
494
472
    (*blob_columns)++;
495
473
    break;
496
474
  case DRIZZLE_TYPE_VARCHAR:
497
 
    sql_field->pack_flag=0;
498
475
    break;
499
476
  case DRIZZLE_TYPE_ENUM:
500
 
    sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length);
501
477
    if (check_duplicates_in_interval("ENUM",
502
478
                                     sql_field->field_name,
503
479
                                     sql_field->interval,
508
484
  case DRIZZLE_TYPE_DATE:  // Rest of string types
509
485
  case DRIZZLE_TYPE_DATETIME:
510
486
  case DRIZZLE_TYPE_NULL:
511
 
    sql_field->pack_flag=f_settype((uint32_t) sql_field->sql_type);
512
487
    break;
513
488
  case DRIZZLE_TYPE_DECIMAL:
514
 
    sql_field->pack_flag= 0;
515
489
    break;
516
490
  case DRIZZLE_TYPE_TIMESTAMP:
517
491
    /* We should replace old TIMESTAMP fields with their newer analogs */
523
497
        (*timestamps_with_niladic)++;
524
498
      }
525
499
      else
 
500
      {
526
501
        sql_field->unireg_check= Field::NONE;
 
502
      }
527
503
    }
528
504
    else if (sql_field->unireg_check != Field::NONE)
529
505
      (*timestamps_with_niladic)++;
531
507
    (*timestamps)++;
532
508
    /* fall-through */
533
509
  default:
534
 
    sql_field->pack_flag=(0 |
535
 
                          f_settype((uint32_t) sql_field->sql_type));
536
510
    break;
537
511
  }
 
512
 
538
513
  return 0;
539
514
}
540
515
 
544
519
                                      AlterInfo *alter_info,
545
520
                                      bool tmp_table,
546
521
                                      uint32_t *db_options,
547
 
                                      KEY **key_info_buffer,
 
522
                                      KeyInfo **key_info_buffer,
548
523
                                      uint32_t *key_count,
549
524
                                      int select_field_count)
550
525
{
552
527
  CreateField   *sql_field,*dup_field;
553
528
  uint          field,null_fields,blob_columns,max_key_length;
554
529
  ulong         record_offset= 0;
555
 
  KEY           *key_info;
556
 
  KEY_PART_INFO *key_part_info;
 
530
  KeyInfo               *key_info;
 
531
  KeyPartInfo *key_part_info;
557
532
  int           timestamps= 0, timestamps_with_niladic= 0;
558
533
  int           field_no,dup_no;
559
534
  int           select_field_pos,auto_increment=0;
631
606
 
632
607
    if (sql_field->sql_type == DRIZZLE_TYPE_ENUM)
633
608
    {
634
 
      uint32_t dummy;
 
609
      size_t dummy;
635
610
      const CHARSET_INFO * const cs= sql_field->charset;
636
611
      TYPELIB *interval= sql_field->interval;
637
612
 
664
639
          if (String::needs_conversion(tmp->length(), tmp->charset(),
665
640
                                       cs, &dummy))
666
641
          {
667
 
            uint32_t cnv_errs;
 
642
            size_t cnv_errs;
668
643
            conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
669
 
            interval->type_names[i]= strmake_root(session->mem_root, conv.ptr(),
670
 
                                                  conv.length());
 
644
            interval->type_names[i]= session->mem_root->strmake_root(conv.ptr(), conv.length());
671
645
            interval->type_lengths[i]= conv.length();
672
646
          }
673
647
 
707
681
            }
708
682
          }
709
683
        }
710
 
        calculate_interval_lengths(cs, interval, &field_length, &dummy);
 
684
        uint32_t new_dummy;
 
685
        calculate_interval_lengths(cs, interval, &field_length, &new_dummy);
711
686
        sql_field->length= field_length;
712
687
      }
713
688
      set_if_smaller(sql_field->length, (uint32_t)MAX_FIELD_WIDTH-1);
775
750
    /** @todo Get rid of this MyISAM-specific crap. */
776
751
    if (not create_proto.engine().name().compare("MyISAM") &&
777
752
        ((sql_field->flags & BLOB_FLAG) ||
778
 
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED)))
 
753
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
779
754
      (*db_options)|= HA_OPTION_PACK_RECORD;
780
755
    it2.rewind();
781
756
  }
843
818
      fk_key_count++;
844
819
      if (((Foreign_key *)key)->validate(alter_info->create_list))
845
820
        return true;
 
821
 
846
822
      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
 
847
833
      if (fk_key->ref_columns.elements &&
848
834
          fk_key->ref_columns.elements != fk_key->columns.elements)
849
835
      {
878
864
             key2->name.str != ignore_key &&
879
865
             !foreign_key_prefix(key, key2)))
880
866
        {
881
 
          /* TODO: issue warning message */
 
867
          /* @todo issue warning message */
882
868
          /* mark that the generated key should be ignored */
883
869
          if (!key2->generated ||
884
870
              (key->generated && key->columns.elements <
912
898
    return(true);
913
899
  }
914
900
 
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);
 
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);
917
903
  if (!*key_info_buffer || ! key_part_info)
918
904
    return(true);                               // Out of memory
919
905
 
953
939
    key_info->usable_key_parts= key_number;
954
940
    key_info->algorithm= key->key_create_info.algorithm;
955
941
 
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
 
 
968
942
    uint32_t tmp_len= system_charset_info->cset->charpos(system_charset_info,
969
943
                                           key->key_create_info.comment.str,
970
944
                                           key->key_create_info.comment.str +
1074
1048
 
1075
1049
      key_part_info->fieldnr= field;
1076
1050
      key_part_info->offset=  (uint16_t) sql_field->offset;
1077
 
      key_part_info->key_type=sql_field->pack_flag;
 
1051
      key_part_info->key_type= 0;
1078
1052
      length= sql_field->key_length;
1079
1053
 
1080
1054
      if (column->length)
1142
1116
      key_part_info->length=(uint16_t) length;
1143
1117
      /* Use packed keys for long strings on the first column */
1144
1118
      if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
1145
 
          (length >= KEY_DEFAULT_PACK_LENGTH &&
1146
 
           (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
1147
 
      sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
 
1119
          (length >= KEY_DEFAULT_PACK_LENGTH &&
 
1120
           (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
 
1121
            sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
1148
1122
      {
1149
1123
        if ((column_nr == 0 && sql_field->sql_type == DRIZZLE_TYPE_BLOB) ||
1150
1124
            sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)
 
1125
        {
1151
1126
          key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
 
1127
        }
1152
1128
        else
 
1129
        {
1153
1130
          key_info->flags|= HA_PACK_KEY;
 
1131
        }
1154
1132
      }
1155
1133
      /* Check if the key segment is partial, set the key flag accordingly */
1156
1134
      if (length != sql_field->key_length)
1212
1190
    return(true);
1213
1191
  }
1214
1192
  /* Sort keys in optimized order */
1215
 
  internal::my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KEY),
 
1193
  internal::my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KeyInfo),
1216
1194
                     (qsort_cmp) sort_keys);
1217
1195
 
1218
1196
  /* Check fields. */
1287
1265
}
1288
1266
 
1289
1267
static bool locked_create_event(Session *session,
1290
 
                                TableIdentifier &identifier,
 
1268
                                const TableIdentifier &identifier,
1291
1269
                                HA_CREATE_INFO *create_info,
1292
1270
                                message::Table &table_proto,
1293
1271
                                AlterInfo *alter_info,
1295
1273
                                bool internal_tmp_table,
1296
1274
                                uint db_options,
1297
1275
                                uint key_count,
1298
 
                                KEY *key_info_buffer)
 
1276
                                KeyInfo *key_info_buffer)
1299
1277
{
1300
1278
  bool error= true;
1301
1279
 
1322
1300
        return error;
1323
1301
      }
1324
1302
 
1325
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
 
1303
      std::string path;
 
1304
      identifier.getSQLPath(path);
 
1305
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
1306
 
1326
1307
      return error;
1327
1308
    }
1328
1309
 
1339
1320
      /*
1340
1321
        @todo improve this error condition.
1341
1322
      */
1342
 
      if (TableShare::getShare(identifier))
 
1323
      if (definition::Cache::singleton().find(identifier.getKey()))
1343
1324
      {
1344
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
 
1325
        std::string path;
 
1326
        identifier.getSQLPath(path);
 
1327
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
1328
 
1345
1329
        return error;
1346
1330
      }
1347
1331
    }
1417
1401
*/
1418
1402
 
1419
1403
bool mysql_create_table_no_lock(Session *session,
1420
 
                                TableIdentifier &identifier,
 
1404
                                const TableIdentifier &identifier,
1421
1405
                                HA_CREATE_INFO *create_info,
1422
1406
                                message::Table &table_proto,
1423
1407
                                AlterInfo *alter_info,
1426
1410
                                bool is_if_not_exists)
1427
1411
{
1428
1412
  uint          db_options, key_count;
1429
 
  KEY           *key_info_buffer;
 
1413
  KeyInfo               *key_info_buffer;
1430
1414
  bool          error= true;
1431
 
  TableShare share;
1432
1415
 
1433
1416
  /* Check for duplicate fields and check type of table to create */
1434
1417
  if (not alter_info->create_list.elements)
1440
1423
  assert(identifier.getTableName() == table_proto.name());
1441
1424
  db_options= create_info->table_options;
1442
1425
 
1443
 
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
1444
 
    db_options|=HA_OPTION_PACK_RECORD;
1445
 
 
1446
1426
  set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1447
1427
 
1448
1428
  /* Build a Table object to pass down to the engine, and the do the actual create. */
1449
1429
  if (not mysql_prepare_create_table(session, create_info, table_proto, alter_info,
1450
 
                                 internal_tmp_table,
1451
 
                                 &db_options,
1452
 
                                 &key_info_buffer, &key_count,
1453
 
                                 select_field_count))
 
1430
                                     internal_tmp_table,
 
1431
                                     &db_options,
 
1432
                                     &key_info_buffer, &key_count,
 
1433
                                     select_field_count))
1454
1434
  {
1455
 
    pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
 
1435
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* CREATE TABLE (some confussion on naming, double check) */
1456
1436
    error= locked_create_event(session,
1457
1437
                               identifier,
1458
1438
                               create_info,
1462
1442
                               internal_tmp_table,
1463
1443
                               db_options, key_count,
1464
1444
                               key_info_buffer);
1465
 
    pthread_mutex_unlock(&LOCK_open);
1466
1445
  }
1467
1446
 
1468
1447
  session->set_proc_info("After create");
1474
1453
  @note the following two methods implement create [temporary] table.
1475
1454
*/
1476
1455
static bool drizzle_create_table(Session *session,
1477
 
                                 TableIdentifier &identifier,
 
1456
                                 const TableIdentifier &identifier,
1478
1457
                                 HA_CREATE_INFO *create_info,
1479
1458
                                 message::Table &table_proto,
1480
1459
                                 AlterInfo *alter_info,
1501
1480
    }
1502
1481
    else
1503
1482
    {
1504
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
 
1483
      std::string path;
 
1484
      identifier.getSQLPath(path);
 
1485
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1505
1486
      result= true;
1506
1487
    }
1507
1488
  }
1519
1500
 
1520
1501
  if (name_lock)
1521
1502
  {
1522
 
    pthread_mutex_lock(&LOCK_open); /* Lock for removing name_lock during table create */
 
1503
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* Lock for removing name_lock during table create */
1523
1504
    session->unlink_open_table(name_lock);
1524
 
    pthread_mutex_unlock(&LOCK_open);
1525
1505
  }
1526
1506
 
1527
1507
  return(result);
1532
1512
  Database locking aware wrapper for mysql_create_table_no_lock(),
1533
1513
*/
1534
1514
bool mysql_create_table(Session *session,
1535
 
                        TableIdentifier &identifier,
 
1515
                        const TableIdentifier &identifier,
1536
1516
                        HA_CREATE_INFO *create_info,
1537
1517
                        message::Table &table_proto,
1538
1518
                        AlterInfo *alter_info,
1568
1548
**/
1569
1549
 
1570
1550
static bool
1571
 
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
 
1551
check_if_keyname_exists(const char *name, KeyInfo *start, KeyInfo *end)
1572
1552
{
1573
 
  for (KEY *key=start ; key != end ; key++)
 
1553
  for (KeyInfo *key=start ; key != end ; key++)
1574
1554
    if (!my_strcasecmp(system_charset_info,name,key->name))
1575
1555
      return 1;
1576
1556
  return 0;
1578
1558
 
1579
1559
 
1580
1560
static char *
1581
 
make_unique_key_name(const char *field_name,KEY *start,KEY *end)
 
1561
make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end)
1582
1562
{
1583
1563
  char buff[MAX_FIELD_NAME],*buff_end;
1584
1564
 
1613
1593
 
1614
1594
  SYNOPSIS
1615
1595
    mysql_rename_table()
 
1596
      session
1616
1597
      base                      The plugin::StorageEngine handle.
1617
1598
      old_db                    The old database name.
1618
1599
      old_name                  The old table name.
1619
1600
      new_db                    The new database name.
1620
1601
      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.
1624
1602
 
1625
1603
  RETURN
1626
1604
    false   OK
1628
1606
*/
1629
1607
 
1630
1608
bool
1631
 
mysql_rename_table(plugin::StorageEngine *base,
1632
 
                   TableIdentifier &from,
1633
 
                   TableIdentifier &to,
1634
 
                   uint32_t )
 
1609
mysql_rename_table(Session &session,
 
1610
                   plugin::StorageEngine *base,
 
1611
                   const TableIdentifier &from,
 
1612
                   const TableIdentifier &to)
1635
1613
{
1636
 
  Session *session= current_session;
1637
1614
  int error= 0;
1638
1615
 
1639
1616
  assert(base);
1644
1621
    return true;
1645
1622
  }
1646
1623
 
1647
 
  error= base->renameTable(*session, from, to);
 
1624
  error= base->renameTable(session, from, to);
1648
1625
 
1649
1626
  if (error == HA_ERR_WRONG_COMMAND)
1650
1627
  {
1652
1629
  }
1653
1630
  else if (error)
1654
1631
  {
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();
 
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();
1657
1640
 
1658
1641
    my_error(ER_ERROR_ON_RENAME, MYF(0), from_identifier, to_identifier, error);
1659
1642
  }
1677
1660
   the table is closed.
1678
1661
 
1679
1662
  PREREQUISITES
1680
 
    Lock on LOCK_open
 
1663
    Lock on table::Cache::singleton().mutex()
1681
1664
    Win32 clients must also have a WRITE LOCK on the table !
1682
1665
*/
1683
1666
 
1685
1668
                              enum ha_extra_function function)
1686
1669
{
1687
1670
 
1688
 
  safe_mutex_assert_owner(&LOCK_open);
 
1671
  safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
1689
1672
 
1690
1673
  table->cursor->extra(function);
1691
1674
  /* Mark all tables that are in use as 'old' */
1692
 
  mysql_lock_abort(session, table);     /* end threads waiting on lock */
 
1675
  session->abortLock(table);    /* end threads waiting on lock */
1693
1676
 
1694
1677
  /* Wait until all there are no other threads that has this table open */
1695
 
  remove_table_from_cache(session, table->s->getSchemaName(),
1696
 
                          table->s->table_name.str,
1697
 
                          RTFC_WAIT_OTHER_THREAD_FLAG);
 
1678
  TableIdentifier identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName());
 
1679
  table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
1698
1680
}
1699
1681
 
1700
1682
/*
1710
1692
    reopen the table.
1711
1693
 
1712
1694
  PREREQUISITES
1713
 
    Lock on LOCK_open
 
1695
    Lock on table::Cache::singleton().mutex()
1714
1696
    Win32 clients must also have a WRITE LOCK on the table !
1715
1697
*/
1716
1698
 
1721
1703
  /* Close lock if this is not got with LOCK TABLES */
1722
1704
  if (lock)
1723
1705
  {
1724
 
    mysql_unlock_tables(this, lock);
 
1706
    unlockTables(lock);
1725
1707
    lock= NULL;                 // Start locked threads
1726
1708
  }
1727
1709
  /* Close all copies of 'table'.  This also frees all LOCK TABLES lock */
1728
1710
  unlink_open_table(table);
1729
1711
 
1730
 
  /* When lock on LOCK_open is freed other threads can continue */
1731
 
  broadcast_refresh();
 
1712
  /* When lock on table::Cache::singleton().mutex() is freed other threads can continue */
 
1713
  locking::broadcast_refresh();
1732
1714
}
1733
1715
 
1734
1716
/*
1772
1754
  for (table= tables; table; table= table->next_local)
1773
1755
  {
1774
1756
    char table_name[NAME_LEN*2+2];
1775
 
    char* db = table->db;
1776
1757
    bool fatal_error=0;
1777
1758
 
1778
 
    sprintf(table_name,"%s.%s",db,table->table_name);
 
1759
    snprintf(table_name, sizeof(table_name), "%s.%s", table->getSchemaName(), table->getTableName());
1779
1760
    table->lock_type= lock_type;
1780
1761
    /* open only one table from local list of command */
1781
1762
    {
1788
1769
      /*
1789
1770
        Time zone tables and SP tables can be add to lex->query_tables list,
1790
1771
        so it have to be prepared.
1791
 
        TODO: Investigate if we can put extra tables into argument instead of
1792
 
        using lex->query_tables
 
1772
        @todo Investigate if we can put extra tables into argument instead of using lex->query_tables
1793
1773
      */
1794
1774
      lex->query_tables= table;
1795
1775
      lex->query_tables_last= &table->next_global;
1829
1809
      length= snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
1830
1810
                       table_name);
1831
1811
      session->client->store(buff, length);
1832
 
      transaction_services.ha_autocommit_or_rollback(session, false);
 
1812
      transaction_services.autocommitOrRollback(session, false);
1833
1813
      session->endTransaction(COMMIT);
1834
1814
      session->close_thread_tables();
1835
1815
      lex->reset_query_tables_list(false);
1840
1820
    }
1841
1821
 
1842
1822
    /* Close all instances of the table to allow repair to rename files */
1843
 
    if (lock_type == TL_WRITE && table->table->s->version)
 
1823
    if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
1844
1824
    {
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);
 
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);
1853
1831
      session->exit_cond(old_message);
1854
 
      if (session->killed)
 
1832
      if (session->getKilled())
1855
1833
        goto err;
1856
1834
      open_for_modify= 0;
1857
1835
    }
1938
1916
    if (table->table)
1939
1917
    {
1940
1918
      if (fatal_error)
1941
 
        table->table->s->version=0;               // Force close of table
 
1919
      {
 
1920
        table->table->getMutableShare()->resetVersion();               // Force close of table
 
1921
      }
1942
1922
      else if (open_for_modify)
1943
1923
      {
1944
 
        if (table->table->s->tmp_table)
 
1924
        if (table->table->getShare()->getType())
 
1925
        {
1945
1926
          table->table->cursor->info(HA_STATUS_CONST);
 
1927
        }
1946
1928
        else
1947
1929
        {
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);
 
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);
1952
1933
        }
1953
1934
      }
1954
1935
    }
1955
 
    transaction_services.ha_autocommit_or_rollback(session, false);
 
1936
    transaction_services.autocommitOrRollback(session, false);
1956
1937
    session->endTransaction(COMMIT);
1957
1938
    session->close_thread_tables();
1958
1939
    table->table=0;                             // For query cache
1964
1945
  return(false);
1965
1946
 
1966
1947
err:
1967
 
  transaction_services.ha_autocommit_or_rollback(session, true);
 
1948
  transaction_services.autocommitOrRollback(session, true);
1968
1949
  session->endTransaction(ROLLBACK);
1969
1950
  session->close_thread_tables();                       // Shouldn't be needed
1970
1951
  if (table)
1972
1953
  return(true);
1973
1954
}
1974
1955
 
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
 
 
2030
1956
  /*
2031
1957
    Create a new table by copying from source table
2032
1958
 
2033
1959
    Altough exclusive name-lock on target table protects us from concurrent
2034
1960
    DML and DDL operations on it we still want to wrap .FRM creation and call
2035
1961
    to plugin::StorageEngine::createTable() in critical section protected by
2036
 
    LOCK_open in order to provide minimal atomicity against operations which
 
1962
    table::Cache::singleton().mutex() in order to provide minimal atomicity against operations which
2037
1963
    disregard name-locks, like I_S implementation, for example. This is a
2038
1964
    temporary and should not be copied. Instead we should fix our code to
2039
1965
    always honor name-locks.
2040
1966
 
2041
 
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
 
1967
    Also some engines (e.g. NDB cluster) require that table::Cache::singleton().mutex() should be held
2042
1968
    during the call to plugin::StorageEngine::createTable().
2043
1969
    See bug #28614 for more info.
2044
1970
  */
2045
1971
static bool create_table_wrapper(Session &session, const message::Table& create_table_proto,
2046
 
                                 TableIdentifier &destination_identifier,
2047
 
                                 TableIdentifier &src_table,
 
1972
                                 const TableIdentifier &destination_identifier,
 
1973
                                 const TableIdentifier &src_table,
2048
1974
                                 bool is_engine_set)
2049
1975
{
2050
1976
  int protoerr= EEXIST;
2051
1977
  message::Table new_proto;
2052
 
  message::Table src_proto;
 
1978
  message::table::shared_ptr src_proto;
2053
1979
 
2054
1980
  protoerr= plugin::StorageEngine::getTableDefinition(session,
2055
1981
                                                      src_table,
2056
1982
                                                      src_proto);
2057
 
  new_proto.CopyFrom(src_proto);
 
1983
  new_proto.CopyFrom(*src_proto);
2058
1984
 
2059
1985
  if (destination_identifier.isTmp())
2060
1986
  {
2067
1993
 
2068
1994
  if (is_engine_set)
2069
1995
  {
2070
 
    message::Table::StorageEngine *protoengine;
2071
 
 
2072
 
    protoengine= new_proto.mutable_engine();
2073
 
    protoengine->set_name(create_table_proto.engine().name());
 
1996
    new_proto.mutable_engine()->set_name(create_table_proto.engine().name());
2074
1997
  }
2075
1998
 
2076
1999
  { // We now do a selective copy of elements on to the new table.
2096
2019
  */
2097
2020
  int err= plugin::StorageEngine::createTable(session,
2098
2021
                                              destination_identifier,
2099
 
                                              true, new_proto);
 
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
  }
2100
2029
 
2101
2030
  return err ? false : true;
2102
2031
}
2117
2046
*/
2118
2047
 
2119
2048
bool mysql_create_like_table(Session* session,
2120
 
                             TableIdentifier &destination_identifier,
 
2049
                             const TableIdentifier &destination_identifier,
2121
2050
                             TableList* table, TableList* src_table,
2122
2051
                             message::Table &create_table_proto,
2123
2052
                             bool is_if_not_exists,
2124
2053
                             bool is_engine_set)
2125
2054
{
2126
 
  Table *name_lock= 0;
2127
 
  char *db= table->db;
2128
 
  char *table_name= table->table_name;
2129
2055
  bool res= true;
2130
2056
  uint32_t not_used;
2131
 
  bool was_created;
2132
2057
 
2133
2058
  /*
2134
2059
    By opening source table we guarantee that it exists and no concurrent
2142
2067
  if (session->open_tables_from_list(&src_table, &not_used))
2143
2068
    return true;
2144
2069
 
2145
 
  TableIdentifier src_identifier(src_table->table->s->getSchemaName(),
2146
 
                                 src_table->table->s->table_name.str, src_table->table->s->tmp_table);
 
2070
  TableIdentifier src_identifier(src_table->table->getShare()->getSchemaName(),
 
2071
                                 src_table->table->getShare()->getTableName(), src_table->table->getShare()->getType());
2147
2072
 
2148
2073
 
2149
2074
 
2150
2075
  /*
2151
2076
    Check that destination tables does not exist. Note that its name
2152
2077
    was already checked when it was added to the table list.
 
2078
 
 
2079
    For temporary tables we don't aim to grab locks.
2153
2080
  */
2154
2081
  bool table_exists= false;
2155
2082
  if (destination_identifier.isTmp())
2156
2083
  {
2157
 
    if (session->find_temporary_table(db, table_name))
 
2084
    if (session->find_temporary_table(destination_identifier))
2158
2085
    {
2159
2086
      table_exists= true;
2160
2087
    }
 
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
    }
2161
2106
  }
2162
 
  else
 
2107
  else // Standard table which will require locks.
2163
2108
  {
2164
 
    if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
 
2109
    Table *name_lock= 0;
 
2110
 
 
2111
    if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
2165
2112
    {
2166
2113
      if (name_lock)
2167
2114
      {
2168
 
        pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
 
2115
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2169
2116
        session->unlink_open_table(name_lock);
2170
 
        pthread_mutex_unlock(&LOCK_open);
2171
2117
      }
2172
2118
 
2173
2119
      return res;
2181
2127
    {
2182
2128
      table_exists= true;
2183
2129
    }
 
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
    }
2184
2156
  }
2185
2157
 
2186
2158
  if (table_exists)
2189
2161
    {
2190
2162
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
2191
2163
      snprintf(warn_buff, sizeof(warn_buff),
2192
 
               ER(ER_TABLE_EXISTS_ERROR), table_name);
 
2164
               ER(ER_TABLE_EXISTS_ERROR), table->getTableName());
2193
2165
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2194
2166
                   ER_TABLE_EXISTS_ERROR,warn_buff);
2195
2167
      res= false;
2196
2168
    }
2197
2169
    else
2198
2170
    {
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);
 
2171
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table->getTableName());
 
2172
    }
2244
2173
  }
2245
2174
 
2246
2175
  return(res);
2267
2196
                                &Cursor::ha_check));
2268
2197
}
2269
2198
 
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
 
 
2385
2199
} /* namespace drizzled */