~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

  • Committer: Monty Taylor
  • Date: 2010-09-28 07:45:44 UTC
  • mto: (1799.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1800.
  • Revision ID: mordred@inaugust.com-20100928074544-s3ujnv6s8wro74l2
Added BSD copying file.

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
 
18
 
#include <config.h>
 
18
#include "config.h"
19
19
#include <plugin/myisam/myisam.h>
20
20
#include <drizzled/show.h>
21
21
#include <drizzled/error.h>
26
26
#include <drizzled/sql_lex.h>
27
27
#include <drizzled/session.h>
28
28
#include <drizzled/sql_base.h>
 
29
#include "drizzled/strfunc.h"
 
30
#include <drizzled/db.h>
29
31
#include <drizzled/lock.h>
30
32
#include <drizzled/unireg.h>
31
33
#include <drizzled/item/int.h>
32
34
#include <drizzled/item/empty_string.h>
33
35
#include <drizzled/transaction_services.h>
34
 
#include <drizzled/transaction_services.h>
 
36
#include "drizzled/transaction_services.h"
35
37
#include <drizzled/table_proto.h>
36
38
#include <drizzled/plugin/client.h>
37
39
#include <drizzled/identifier.h>
38
 
#include <drizzled/internal/m_string.h>
39
 
#include <drizzled/global_charset_info.h>
40
 
#include <drizzled/charset.h>
41
 
 
42
 
#include <drizzled/definition/cache.h>
43
 
 
44
 
#include <drizzled/statement/alter_table.h>
45
 
#include <drizzled/sql_table.h>
46
 
#include <drizzled/pthread_globals.h>
47
 
#include <drizzled/typelib.h>
48
 
#include <drizzled/plugin/storage_engine.h>
 
40
#include "drizzled/internal/m_string.h"
 
41
#include "drizzled/global_charset_info.h"
 
42
#include "drizzled/charset.h"
 
43
 
 
44
 
 
45
#include "drizzled/statement/alter_table.h"
 
46
#include "drizzled/sql_table.h"
 
47
#include "drizzled/pthread_globals.h"
49
48
 
50
49
#include <algorithm>
51
50
#include <sstream>
57
56
namespace drizzled
58
57
{
59
58
 
 
59
extern pid_t current_pid;
 
60
 
60
61
bool is_primary_key(KeyInfo *key_info)
61
62
{
62
63
  static const char * primary_key_name="PRIMARY";
84
85
    let's fetch the database default character set and
85
86
    apply it to the table.
86
87
  */
87
 
  identifier::Schema identifier(db);
 
88
  SchemaIdentifier identifier(db);
88
89
  if (create_info->default_table_charset == NULL)
89
90
    create_info->default_table_charset= plugin::StorageEngine::getSchemaCollation(identifier);
90
91
}
104
105
    cursor
105
106
*/
106
107
 
107
 
void write_bin_log(Session *session, const std::string &query)
 
108
void write_bin_log(Session *session,
 
109
                   char const *query)
108
110
{
109
111
  TransactionServices &transaction_services= TransactionServices::singleton();
110
 
  transaction_services.rawStatement(*session, query);
 
112
  transaction_services.rawStatement(session, query);
111
113
}
112
114
 
113
115
/*
114
116
  Execute the drop of a normal or temporary table
115
117
 
116
118
  SYNOPSIS
117
 
    rm_table_part2()
 
119
    mysql_rm_table_part2()
118
120
    session                     Thread Cursor
119
121
    tables              Tables to drop
120
122
    if_exists           If set, don't give an error if table doesn't exists.
137
139
   -1   Thread was killed
138
140
*/
139
141
 
140
 
int rm_table_part2(Session *session, TableList *tables, bool if_exists,
141
 
                   bool drop_temporary)
 
142
int mysql_rm_table_part2(Session *session, TableList *tables, bool if_exists,
 
143
                         bool drop_temporary)
142
144
{
143
145
  TableList *table;
144
 
  util::string::vector wrong_tables;
 
146
  String wrong_tables;
145
147
  int error= 0;
146
148
  bool foreign_key_error= false;
147
149
 
148
 
  do
149
 
  {
150
 
    boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
151
 
 
152
 
    if (not drop_temporary && session->lock_table_names_exclusively(tables))
153
 
    {
154
 
      return 1;
155
 
    }
156
 
 
157
 
    /* Don't give warnings for not found errors, as we already generate notes */
158
 
    session->no_warnings_for_error= 1;
159
 
 
160
 
    for (table= tables; table; table= table->next_local)
161
 
    {
162
 
      identifier::Table tmp_identifier(table->getSchemaName(), table->getTableName());
163
 
 
164
 
      error= session->drop_temporary_table(tmp_identifier);
165
 
 
166
 
      switch (error) {
167
 
      case  0:
168
 
        // removed temporary table
169
 
        continue;
170
 
      case -1:
 
150
  LOCK_open.lock(); /* Part 2 of rm a table */
 
151
 
 
152
  /*
 
153
    If we have the table in the definition cache, we don't have to check the
 
154
    .frm cursor to find if the table is a normal table (not view) and what
 
155
    engine to use.
 
156
  */
 
157
 
 
158
  for (table= tables; table; table= table->next_local)
 
159
  {
 
160
    TableIdentifier identifier(table->db, table->table_name);
 
161
    TableShare *share;
 
162
    table->setDbType(NULL);
 
163
 
 
164
    if ((share= TableShare::getShare(identifier)))
 
165
    {
 
166
      table->setDbType(share->db_type());
 
167
    }
 
168
  }
 
169
 
 
170
  if (not drop_temporary && lock_table_names_exclusively(session, tables))
 
171
  {
 
172
    LOCK_open.unlock();
 
173
    return 1;
 
174
  }
 
175
 
 
176
  /* Don't give warnings for not found errors, as we already generate notes */
 
177
  session->no_warnings_for_error= 1;
 
178
 
 
179
  for (table= tables; table; table= table->next_local)
 
180
  {
 
181
    char *db=table->db;
 
182
 
 
183
    error= session->drop_temporary_table(table);
 
184
 
 
185
    switch (error) {
 
186
    case  0:
 
187
      // removed temporary table
 
188
      continue;
 
189
    case -1:
 
190
      error= 1;
 
191
      goto err_with_placeholders;
 
192
    default:
 
193
      // temporary table not found
 
194
      error= 0;
 
195
    }
 
196
 
 
197
    if (drop_temporary == false)
 
198
    {
 
199
      Table *locked_table;
 
200
      TableIdentifier identifier(db, table->table_name);
 
201
      abort_locked_tables(session, identifier);
 
202
      remove_table_from_cache(session, identifier,
 
203
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
204
                              RTFC_CHECK_KILLED_FLAG);
 
205
      /*
 
206
        If the table was used in lock tables, remember it so that
 
207
        unlock_table_names can free it
 
208
      */
 
209
      if ((locked_table= drop_locked_tables(session, identifier)))
 
210
        table->table= locked_table;
 
211
 
 
212
      if (session->killed)
 
213
      {
 
214
        error= -1;
 
215
        goto err_with_placeholders;
 
216
      }
 
217
    }
 
218
    TableIdentifier identifier(db, table->table_name, table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
 
219
 
 
220
    if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
 
221
    {
 
222
      // Table was not found on disk and table can't be created from engine
 
223
      if (if_exists)
 
224
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
225
                            ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 
226
                            table->table_name);
 
227
      else
171
228
        error= 1;
172
 
        break;
173
 
      default:
174
 
        // temporary table not found
 
229
    }
 
230
    else
 
231
    {
 
232
      error= plugin::StorageEngine::dropTable(*session, identifier);
 
233
 
 
234
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
 
235
      {
175
236
        error= 0;
176
 
      }
177
 
 
178
 
      if (drop_temporary == false)
179
 
      {
180
 
        Table *locked_table;
181
 
        abort_locked_tables(session, tmp_identifier);
182
 
        table::Cache::singleton().removeTable(session, tmp_identifier,
183
 
                                              RTFC_WAIT_OTHER_THREAD_FLAG |
184
 
                                              RTFC_CHECK_KILLED_FLAG);
185
 
        /*
186
 
          If the table was used in lock tables, remember it so that
187
 
          unlock_table_names can free it
188
 
        */
189
 
        if ((locked_table= drop_locked_tables(session, tmp_identifier)))
190
 
          table->table= locked_table;
191
 
 
192
 
        if (session->getKilled())
193
 
        {
194
 
          error= -1;
195
 
          break;
196
 
        }
197
 
      }
198
 
      identifier::Table identifier(table->getSchemaName(), table->getTableName(), table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
199
 
 
200
 
      message::table::shared_ptr message= plugin::StorageEngine::getTableMessage(*session, identifier, true);
201
 
 
202
 
      if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
203
 
      {
204
 
        // Table was not found on disk and table can't be created from engine
205
 
        if (if_exists)
206
 
        {
207
 
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
208
 
                              ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
209
 
                              table->getTableName());
210
 
        }
211
 
        else
212
 
        {
213
 
          error= 1;
214
 
        }
215
 
      }
216
 
      else
217
 
      {
218
 
        drizzled::error_t local_error;
219
 
 
220
 
        /* Generate transaction event ONLY when we successfully drop */ 
221
 
        if (plugin::StorageEngine::dropTable(*session, identifier, local_error))
222
 
        {
223
 
          if (message) // If we have no definition, we don't know if the table should have been replicated
224
 
          {
225
 
            TransactionServices &transaction_services= TransactionServices::singleton();
226
 
            transaction_services.dropTable(*session, identifier, *message, if_exists);
227
 
          }
228
 
        }
229
 
        else
230
 
        {
231
 
          if (local_error == HA_ERR_NO_SUCH_TABLE and if_exists)
232
 
          {
233
 
            error= 0;
234
 
            session->clear_error();
235
 
          }
236
 
 
237
 
          if (local_error == HA_ERR_ROW_IS_REFERENCED)
238
 
          {
239
 
            /* the table is referenced by a foreign key constraint */
240
 
            foreign_key_error= true;
241
 
          }
242
 
          error= local_error;
243
 
        }
244
 
      }
245
 
 
246
 
      if (error)
247
 
      {
248
 
        wrong_tables.push_back(table->getTableName());
249
 
      }
250
 
    }
251
 
 
252
 
    tables->unlock_table_names();
253
 
 
254
 
  } while (0);
255
 
 
256
 
  if (wrong_tables.size())
 
237
        session->clear_error();
 
238
      }
 
239
 
 
240
      if (error == HA_ERR_ROW_IS_REFERENCED)
 
241
      {
 
242
        /* the table is referenced by a foreign key constraint */
 
243
        foreign_key_error= true;
 
244
      }
 
245
    }
 
246
 
 
247
    if (error == 0 || (if_exists && foreign_key_error == false))
 
248
    {
 
249
      TransactionServices &transaction_services= TransactionServices::singleton();
 
250
      transaction_services.dropTable(session, string(db), string(table->table_name), if_exists);
 
251
    }
 
252
 
 
253
    if (error)
 
254
    {
 
255
      if (wrong_tables.length())
 
256
        wrong_tables.append(',');
 
257
      wrong_tables.append(String(table->table_name,system_charset_info));
 
258
    }
 
259
  }
 
260
  /*
 
261
    It's safe to unlock LOCK_open: we have an exclusive lock
 
262
    on the table name.
 
263
  */
 
264
  LOCK_open.unlock();
 
265
  error= 0;
 
266
 
 
267
  if (wrong_tables.length())
257
268
  {
258
269
    if (not foreign_key_error)
259
270
    {
260
 
      std::string table_error;
261
 
 
262
 
      for (util::string::vector::iterator iter= wrong_tables.begin();
263
 
           iter != wrong_tables.end();
264
 
           iter++)
265
 
      {
266
 
        table_error+= *iter;
267
 
        table_error+= ',';
268
 
      }
269
 
      table_error.resize(table_error.size() -1);
270
 
 
271
271
      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
272
 
                      table_error.c_str());
 
272
                      wrong_tables.c_ptr());
273
273
    }
274
274
    else
275
275
    {
278
278
    error= 1;
279
279
  }
280
280
 
 
281
  LOCK_open.lock(); /* final bit in rm table lock */
 
282
 
 
283
err_with_placeholders:
 
284
  unlock_table_names(tables, NULL);
 
285
  LOCK_open.unlock();
281
286
  session->no_warnings_for_error= 0;
282
287
 
283
288
  return error;
284
289
}
285
290
 
 
291
 
 
292
/*
 
293
  Quickly remove a table.
 
294
 
 
295
  SYNOPSIS
 
296
    quick_rm_table()
 
297
      base                      The plugin::StorageEngine handle.
 
298
      db                        The database name.
 
299
      table_name                The table name.
 
300
      is_tmp                    If the table is temp.
 
301
 
 
302
  RETURN
 
303
    0           OK
 
304
    != 0        Error
 
305
*/
 
306
bool quick_rm_table(Session& session,
 
307
                    TableIdentifier &identifier)
 
308
{
 
309
  return (plugin::StorageEngine::dropTable(session, identifier));
 
310
}
 
311
 
286
312
/*
287
313
  Sort keys in the following order:
288
314
  - PRIMARY KEY
482
508
    sql_field->length= 8; // Unireg field length
483
509
    (*blob_columns)++;
484
510
    break;
485
 
 
 
511
  case DRIZZLE_TYPE_VARCHAR:
 
512
    break;
486
513
  case DRIZZLE_TYPE_ENUM:
487
 
    {
488
 
      if (check_duplicates_in_interval("ENUM",
489
 
                                       sql_field->field_name,
490
 
                                       sql_field->interval,
491
 
                                       sql_field->charset,
492
 
                                       &dup_val_count))
493
 
      {
494
 
        return 1;
495
 
      }
496
 
    }
497
 
    break;
498
 
 
499
 
  case DRIZZLE_TYPE_MICROTIME:
 
514
    if (check_duplicates_in_interval("ENUM",
 
515
                                     sql_field->field_name,
 
516
                                     sql_field->interval,
 
517
                                     sql_field->charset,
 
518
                                     &dup_val_count))
 
519
      return 1;
 
520
    break;
 
521
  case DRIZZLE_TYPE_DATE:  // Rest of string types
 
522
  case DRIZZLE_TYPE_DATETIME:
 
523
  case DRIZZLE_TYPE_NULL:
 
524
    break;
 
525
  case DRIZZLE_TYPE_DECIMAL:
 
526
    break;
500
527
  case DRIZZLE_TYPE_TIMESTAMP:
501
528
    /* We should replace old TIMESTAMP fields with their newer analogs */
502
529
    if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
512
539
      }
513
540
    }
514
541
    else if (sql_field->unireg_check != Field::NONE)
515
 
    {
516
542
      (*timestamps_with_niladic)++;
517
 
    }
518
543
 
519
544
    (*timestamps)++;
520
 
 
521
 
    break;
522
 
 
523
 
  case DRIZZLE_TYPE_BOOLEAN:
524
 
  case DRIZZLE_TYPE_DATE:  // Rest of string types
525
 
  case DRIZZLE_TYPE_DATETIME:
526
 
  case DRIZZLE_TYPE_DECIMAL:
527
 
  case DRIZZLE_TYPE_DOUBLE:
528
 
  case DRIZZLE_TYPE_LONG:
529
 
  case DRIZZLE_TYPE_LONGLONG:
530
 
  case DRIZZLE_TYPE_NULL:
531
 
  case DRIZZLE_TYPE_TIME:
532
 
  case DRIZZLE_TYPE_UUID:
533
 
  case DRIZZLE_TYPE_VARCHAR:
 
545
    /* fall-through */
 
546
  default:
534
547
    break;
535
548
  }
536
549
 
537
550
  return 0;
538
551
}
539
552
 
540
 
static int prepare_create_table(Session *session,
541
 
                                HA_CREATE_INFO *create_info,
542
 
                                message::Table &create_proto,
543
 
                                AlterInfo *alter_info,
544
 
                                bool tmp_table,
545
 
                                uint32_t *db_options,
546
 
                                KeyInfo **key_info_buffer,
547
 
                                uint32_t *key_count,
548
 
                                int select_field_count)
 
553
static int mysql_prepare_create_table(Session *session,
 
554
                                      HA_CREATE_INFO *create_info,
 
555
                                      message::Table &create_proto,
 
556
                                      AlterInfo *alter_info,
 
557
                                      bool tmp_table,
 
558
                                      uint32_t *db_options,
 
559
                                      KeyInfo **key_info_buffer,
 
560
                                      uint32_t *key_count,
 
561
                                      int select_field_count)
549
562
{
550
563
  const char    *key_name;
551
564
  CreateField   *sql_field,*dup_field;
554
567
  KeyInfo               *key_info;
555
568
  KeyPartInfo *key_part_info;
556
569
  int           timestamps= 0, timestamps_with_niladic= 0;
557
 
  int           dup_no;
 
570
  int           field_no,dup_no;
558
571
  int           select_field_pos,auto_increment=0;
559
 
  List<CreateField>::iterator it(alter_info->create_list.begin());
560
 
  List<CreateField>::iterator it2(alter_info->create_list.begin());
 
572
  List_iterator<CreateField> it(alter_info->create_list);
 
573
  List_iterator<CreateField> it2(alter_info->create_list);
561
574
  uint32_t total_uneven_bit_length= 0;
562
575
 
563
576
  plugin::StorageEngine *engine= plugin::StorageEngine::findByName(create_proto.engine().name());
564
577
 
565
 
  select_field_pos= alter_info->create_list.size() - select_field_count;
 
578
  select_field_pos= alter_info->create_list.elements - select_field_count;
566
579
  null_fields=blob_columns=0;
567
580
  max_key_length= engine->max_key_length();
568
581
 
569
 
  for (int32_t field_no=0; (sql_field=it++) ; field_no++)
 
582
  for (field_no=0; (sql_field=it++) ; field_no++)
570
583
  {
571
584
    const CHARSET_INFO *save_cs;
572
585
 
576
589
      executing a prepared statement for the second time.
577
590
    */
578
591
    sql_field->length= sql_field->char_length;
579
 
 
580
592
    if (!sql_field->charset)
581
593
      sql_field->charset= create_info->default_table_charset;
582
 
 
583
594
    /*
584
595
      table_charset is set in ALTER Table if we want change character set
585
596
      for all varchar/char columns.
632
643
 
633
644
    if (sql_field->sql_type == DRIZZLE_TYPE_ENUM)
634
645
    {
635
 
      size_t dummy;
 
646
      uint32_t dummy;
636
647
      const CHARSET_INFO * const cs= sql_field->charset;
637
648
      TYPELIB *interval= sql_field->interval;
638
649
 
651
662
        interval= sql_field->interval= typelib(session->mem_root,
652
663
                                               sql_field->interval_list);
653
664
 
654
 
        List<String>::iterator int_it(sql_field->interval_list.begin());
 
665
        List_iterator<String> int_it(sql_field->interval_list);
655
666
        String conv, *tmp;
656
667
        char comma_buf[4];
657
668
        int comma_length= cs->cset->wc_mb(cs, ',', (unsigned char*) comma_buf,
665
676
          if (String::needs_conversion(tmp->length(), tmp->charset(),
666
677
                                       cs, &dummy))
667
678
          {
668
 
            size_t cnv_errs;
 
679
            uint32_t cnv_errs;
669
680
            conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
670
681
            interval->type_names[i]= session->mem_root->strmake_root(conv.ptr(), conv.length());
671
682
            interval->type_lengths[i]= conv.length();
677
688
          interval->type_lengths[i]= lengthsp;
678
689
          ((unsigned char *)interval->type_names[i])[lengthsp]= '\0';
679
690
        }
680
 
        sql_field->interval_list.clear(); // Don't need interval_list anymore
 
691
        sql_field->interval_list.empty(); // Don't need interval_list anymore
681
692
      }
682
693
 
683
694
      /* DRIZZLE_TYPE_ENUM */
700
711
          else /* not NULL */
701
712
          {
702
713
            def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
703
 
            if (interval->find_type2(def->ptr(), def->length(), cs) == 0) /* not found */
 
714
            if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
704
715
            {
705
716
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
706
717
              return(true);
707
718
            }
708
719
          }
709
720
        }
710
 
        uint32_t new_dummy;
711
 
        calculate_interval_lengths(cs, interval, &field_length, &new_dummy);
 
721
        calculate_interval_lengths(cs, interval, &field_length, &dummy);
712
722
        sql_field->length= field_length;
713
723
      }
714
724
      set_if_smaller(sql_field->length, (uint32_t)MAX_FIELD_WIDTH-1);
777
787
    if (not create_proto.engine().name().compare("MyISAM") &&
778
788
        ((sql_field->flags & BLOB_FLAG) ||
779
789
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
780
 
    {
781
790
      (*db_options)|= HA_OPTION_PACK_RECORD;
782
 
    }
783
 
 
784
 
    it2= alter_info->create_list.begin();
 
791
    it2.rewind();
785
792
  }
786
793
 
787
794
  /* record_offset will be increased with 'length-of-null-bits' later */
788
795
  record_offset= 0;
789
796
  null_fields+= total_uneven_bit_length;
790
797
 
791
 
  it= alter_info->create_list.begin();
 
798
  it.rewind();
792
799
  while ((sql_field=it++))
793
800
  {
794
801
    assert(sql_field->charset != 0);
828
835
 
829
836
  /* Create keys */
830
837
 
831
 
  List<Key>::iterator key_iterator(alter_info->key_list.begin());
832
 
  List<Key>::iterator key_iterator2(alter_info->key_list.begin());
 
838
  List_iterator<Key> key_iterator(alter_info->key_list);
 
839
  List_iterator<Key> key_iterator2(alter_info->key_list);
833
840
  uint32_t key_parts=0, fk_key_count=0;
834
841
  bool primary_key=0,unique_key=0;
835
842
  Key *key, *key2;
859
866
                                       fk_key->update_opt,
860
867
                                       fk_key->match_opt);
861
868
 
862
 
      if (fk_key->ref_columns.size() &&
863
 
          fk_key->ref_columns.size() != fk_key->columns.size())
 
869
      if (fk_key->ref_columns.elements &&
 
870
          fk_key->ref_columns.elements != fk_key->columns.elements)
864
871
      {
865
872
        my_error(ER_WRONG_FK_DEF, MYF(0),
866
873
                 (fk_key->name.str ? fk_key->name.str :
872
879
    }
873
880
    (*key_count)++;
874
881
    tmp= engine->max_key_parts();
875
 
    if (key->columns.size() > tmp)
 
882
    if (key->columns.elements > tmp)
876
883
    {
877
884
      my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
878
885
      return(true);
879
886
    }
880
887
    if (check_identifier_name(&key->name, ER_TOO_LONG_IDENT))
881
888
      return(true);
882
 
    key_iterator2= alter_info->key_list.begin();
 
889
    key_iterator2.rewind ();
883
890
    if (key->type != Key::FOREIGN_KEY)
884
891
    {
885
892
      while ((key2 = key_iterator2++) != key)
896
903
          /* @todo issue warning message */
897
904
          /* mark that the generated key should be ignored */
898
905
          if (!key2->generated ||
899
 
              (key->generated && key->columns.size() <
900
 
               key2->columns.size()))
 
906
              (key->generated && key->columns.elements <
 
907
               key2->columns.elements))
901
908
            key->name.str= ignore_key;
902
909
          else
903
910
          {
904
911
            key2->name.str= ignore_key;
905
 
            key_parts-= key2->columns.size();
 
912
            key_parts-= key2->columns.elements;
906
913
            (*key_count)--;
907
914
          }
908
915
          break;
910
917
      }
911
918
    }
912
919
    if (key->name.str != ignore_key)
913
 
      key_parts+=key->columns.size();
 
920
      key_parts+=key->columns.elements;
914
921
    else
915
922
      (*key_count)--;
916
923
    if (key->name.str && !tmp_table && (key->type != Key::PRIMARY) &&
932
939
  if (!*key_info_buffer || ! key_part_info)
933
940
    return(true);                               // Out of memory
934
941
 
935
 
  key_iterator= alter_info->key_list.begin();
 
942
  key_iterator.rewind();
936
943
  key_number=0;
937
944
  for (; (key=key_iterator++) ; key_number++)
938
945
  {
963
970
    if (key->generated)
964
971
      key_info->flags|= HA_GENERATED_KEY;
965
972
 
966
 
    key_info->key_parts=(uint8_t) key->columns.size();
 
973
    key_info->key_parts=(uint8_t) key->columns.elements;
967
974
    key_info->key_part=key_part_info;
968
975
    key_info->usable_key_parts= key_number;
969
976
    key_info->algorithm= key->key_create_info.algorithm;
991
998
 
992
999
    message::Table::Field *protofield= NULL;
993
1000
 
994
 
    List<Key_part_spec>::iterator cols(key->columns.begin());
995
 
    List<Key_part_spec>::iterator cols2(key->columns.begin());
 
1001
    List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
996
1002
    for (uint32_t column_nr=0 ; (column=cols++) ; column_nr++)
997
1003
    {
998
1004
      uint32_t length;
999
1005
      Key_part_spec *dup_column;
1000
1006
      int proto_field_nr= 0;
1001
1007
 
1002
 
      it= alter_info->create_list.begin();
 
1008
      it.rewind();
1003
1009
      field=0;
1004
1010
      while ((sql_field=it++) && ++proto_field_nr &&
1005
1011
             my_strcasecmp(system_charset_info,
1006
1012
                           column->field_name.str,
1007
1013
                           sql_field->field_name))
1008
 
      {
1009
1014
        field++;
1010
 
      }
1011
 
 
1012
1015
      if (!sql_field)
1013
1016
      {
1014
1017
        my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
1015
1018
        return(true);
1016
1019
      }
1017
 
 
1018
1020
      while ((dup_column= cols2++) != column)
1019
1021
      {
1020
1022
        if (!my_strcasecmp(system_charset_info,
1026
1028
          return(true);
1027
1029
        }
1028
1030
      }
1029
 
      cols2= key->columns.begin();
 
1031
      cols2.rewind();
1030
1032
 
1031
1033
      if (create_proto.field_size() > 0)
1032
1034
        protofield= create_proto.mutable_field(proto_field_nr - 1);
1047
1049
            return true;
1048
1050
          }
1049
1051
        }
1050
 
 
1051
1052
        if (! (sql_field->flags & NOT_NULL_FLAG))
1052
1053
        {
1053
1054
          if (key->type == Key::PRIMARY)
1060
1061
            {
1061
1062
              message::Table::Field::FieldConstraints *constraints;
1062
1063
              constraints= protofield->mutable_constraints();
1063
 
              constraints->set_is_notnull(true);
 
1064
              constraints->set_is_nullable(false);
1064
1065
            }
1065
1066
 
1066
1067
          }
1074
1075
            }
1075
1076
          }
1076
1077
        }
1077
 
 
1078
1078
        if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
1079
1079
        {
1080
1080
          if (column_nr == 0 || (engine->check_flag(HTON_BIT_AUTO_PART_KEY)))
1199
1199
        key_info->name=(char*) key_name;
1200
1200
      }
1201
1201
    }
1202
 
 
1203
1202
    if (!key_info->name || check_column_name(key_info->name))
1204
1203
    {
1205
1204
      my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
1206
1205
      return(true);
1207
1206
    }
1208
 
 
1209
1207
    if (!(key_info->flags & HA_NULL_PART_KEY))
1210
 
    {
1211
1208
      unique_key=1;
1212
 
    }
1213
 
 
1214
1209
    key_info->key_length=(uint16_t) key_length;
1215
 
 
1216
1210
    if (key_length > max_key_length)
1217
1211
    {
1218
1212
      my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
1219
1213
      return(true);
1220
1214
    }
1221
 
 
1222
1215
    key_info++;
1223
1216
  }
1224
 
 
1225
1217
  if (!unique_key && !primary_key &&
1226
1218
      (engine->check_flag(HTON_BIT_REQUIRE_PRIMARY_KEY)))
1227
1219
  {
1228
1220
    my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
1229
1221
    return(true);
1230
1222
  }
1231
 
 
1232
1223
  if (auto_increment > 0)
1233
1224
  {
1234
1225
    my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
1239
1230
                     (qsort_cmp) sort_keys);
1240
1231
 
1241
1232
  /* Check fields. */
1242
 
  it= alter_info->create_list.begin();
 
1233
  it.rewind();
1243
1234
  while ((sql_field=it++))
1244
1235
  {
1245
1236
    Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
1246
1237
 
1247
1238
    if (session->variables.sql_mode & MODE_NO_ZERO_DATE &&
1248
1239
        !sql_field->def &&
1249
 
        (sql_field->sql_type == DRIZZLE_TYPE_TIMESTAMP  or sql_field->sql_type == DRIZZLE_TYPE_MICROTIME) &&
 
1240
        sql_field->sql_type == DRIZZLE_TYPE_TIMESTAMP &&
1250
1241
        (sql_field->flags & NOT_NULL_FLAG) &&
1251
1242
        (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
1252
1243
    {
1310
1301
}
1311
1302
 
1312
1303
static bool locked_create_event(Session *session,
1313
 
                                const identifier::Table &identifier,
 
1304
                                TableIdentifier &identifier,
1314
1305
                                HA_CREATE_INFO *create_info,
1315
1306
                                message::Table &table_proto,
1316
1307
                                AlterInfo *alter_info,
1345
1336
        return error;
1346
1337
      }
1347
1338
 
1348
 
      my_error(ER_TABLE_EXISTS_ERROR, identifier);
1349
 
 
 
1339
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1350
1340
      return error;
1351
1341
    }
1352
1342
 
1363
1353
      /*
1364
1354
        @todo improve this error condition.
1365
1355
      */
1366
 
      if (definition::Cache::singleton().find(identifier.getKey()))
 
1356
      if (TableShare::getShare(identifier))
1367
1357
      {
1368
 
        my_error(ER_TABLE_EXISTS_ERROR, identifier);
1369
 
 
 
1358
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1370
1359
        return error;
1371
1360
      }
1372
1361
    }
1404
1393
  if (table_proto.type() == message::Table::STANDARD && not internal_tmp_table)
1405
1394
  {
1406
1395
    TransactionServices &transaction_services= TransactionServices::singleton();
1407
 
    transaction_services.createTable(*session, table_proto);
 
1396
    transaction_services.createTable(session, table_proto);
1408
1397
  }
1409
1398
 
1410
1399
  return false;
1417
1406
  Create a table
1418
1407
 
1419
1408
  SYNOPSIS
1420
 
    create_table_no_lock()
 
1409
    mysql_create_table_no_lock()
1421
1410
    session                     Thread object
1422
1411
    db                  Database
1423
1412
    table_name          Table name
1433
1422
 
1434
1423
    Note that this function assumes that caller already have taken
1435
1424
    name-lock on table being created or used some other way to ensure
1436
 
    that concurrent operations won't intervene. create_table()
 
1425
    that concurrent operations won't intervene. mysql_create_table()
1437
1426
    is a wrapper that can be used for this.
1438
1427
 
1439
1428
  RETURN VALUES
1441
1430
    true  error
1442
1431
*/
1443
1432
 
1444
 
bool create_table_no_lock(Session *session,
1445
 
                                const identifier::Table &identifier,
 
1433
bool mysql_create_table_no_lock(Session *session,
 
1434
                                TableIdentifier &identifier,
1446
1435
                                HA_CREATE_INFO *create_info,
1447
1436
                                message::Table &table_proto,
1448
1437
                                AlterInfo *alter_info,
1455
1444
  bool          error= true;
1456
1445
 
1457
1446
  /* Check for duplicate fields and check type of table to create */
1458
 
  if (not alter_info->create_list.size())
 
1447
  if (not alter_info->create_list.elements)
1459
1448
  {
1460
1449
    my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
1461
1450
               MYF(0));
1467
1456
  set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1468
1457
 
1469
1458
  /* Build a Table object to pass down to the engine, and the do the actual create. */
1470
 
  if (not prepare_create_table(session, create_info, table_proto, alter_info,
1471
 
                               internal_tmp_table,
1472
 
                               &db_options,
1473
 
                               &key_info_buffer, &key_count,
1474
 
                               select_field_count))
 
1459
  if (not mysql_prepare_create_table(session, create_info, table_proto, alter_info,
 
1460
                                 internal_tmp_table,
 
1461
                                 &db_options,
 
1462
                                 &key_info_buffer, &key_count,
 
1463
                                 select_field_count))
1475
1464
  {
1476
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* CREATE TABLE (some confussion on naming, double check) */
 
1465
    boost::mutex::scoped_lock lock(LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1477
1466
    error= locked_create_event(session,
1478
1467
                               identifier,
1479
1468
                               create_info,
1494
1483
  @note the following two methods implement create [temporary] table.
1495
1484
*/
1496
1485
static bool drizzle_create_table(Session *session,
1497
 
                                 const identifier::Table &identifier,
 
1486
                                 TableIdentifier &identifier,
1498
1487
                                 HA_CREATE_INFO *create_info,
1499
1488
                                 message::Table &table_proto,
1500
1489
                                 AlterInfo *alter_info,
1521
1510
    }
1522
1511
    else
1523
1512
    {
1524
 
      my_error(ER_TABLE_EXISTS_ERROR, identifier);
 
1513
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1525
1514
      result= true;
1526
1515
    }
1527
1516
  }
1528
1517
  else
1529
1518
  {
1530
 
    result= create_table_no_lock(session,
 
1519
    result= mysql_create_table_no_lock(session,
1531
1520
                                       identifier,
1532
1521
                                       create_info,
1533
1522
                                       table_proto,
1539
1528
 
1540
1529
  if (name_lock)
1541
1530
  {
1542
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* Lock for removing name_lock during table create */
 
1531
    boost::mutex::scoped_lock lock(LOCK_open); /* Lock for removing name_lock during table create */
1543
1532
    session->unlink_open_table(name_lock);
1544
1533
  }
1545
1534
 
1548
1537
 
1549
1538
 
1550
1539
/*
1551
 
  Database locking aware wrapper for create_table_no_lock(),
 
1540
  Database locking aware wrapper for mysql_create_table_no_lock(),
1552
1541
*/
1553
 
bool create_table(Session *session,
1554
 
                        const identifier::Table &identifier,
 
1542
bool mysql_create_table(Session *session,
 
1543
                        TableIdentifier &identifier,
1555
1544
                        HA_CREATE_INFO *create_info,
1556
1545
                        message::Table &table_proto,
1557
1546
                        AlterInfo *alter_info,
1561
1550
{
1562
1551
  if (identifier.isTmp())
1563
1552
  {
1564
 
    return create_table_no_lock(session,
 
1553
    return mysql_create_table_no_lock(session,
1565
1554
                                      identifier,
1566
1555
                                      create_info,
1567
1556
                                      table_proto,
1631
1620
  Rename a table.
1632
1621
 
1633
1622
  SYNOPSIS
1634
 
    rename_table()
 
1623
    mysql_rename_table()
1635
1624
      session
1636
1625
      base                      The plugin::StorageEngine handle.
1637
1626
      old_db                    The old database name.
1645
1634
*/
1646
1635
 
1647
1636
bool
1648
 
rename_table(Session &session,
 
1637
mysql_rename_table(Session &session,
1649
1638
                   plugin::StorageEngine *base,
1650
 
                   const identifier::Table &from,
1651
 
                   const identifier::Table &to)
 
1639
                   TableIdentifier &from,
 
1640
                   TableIdentifier &to)
1652
1641
{
1653
1642
  int error= 0;
1654
1643
 
1668
1657
  }
1669
1658
  else if (error)
1670
1659
  {
1671
 
    std::string from_path;
1672
 
    std::string to_path;
1673
 
 
1674
 
    from.getSQLPath(from_path);
1675
 
    to.getSQLPath(to_path);
1676
 
 
1677
 
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from_path.c_str();
1678
 
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to_path.c_str();
 
1660
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from.getSQLPath().c_str();
 
1661
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to.getSQLPath().c_str();
1679
1662
 
1680
1663
    my_error(ER_ERROR_ON_RENAME, MYF(0), from_identifier, to_identifier, error);
1681
1664
  }
1699
1682
   the table is closed.
1700
1683
 
1701
1684
  PREREQUISITES
1702
 
    Lock on table::Cache::singleton().mutex()
 
1685
    Lock on LOCK_open
1703
1686
    Win32 clients must also have a WRITE LOCK on the table !
1704
1687
*/
1705
1688
 
1707
1690
                              enum ha_extra_function function)
1708
1691
{
1709
1692
 
1710
 
  safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
 
1693
  safe_mutex_assert_owner(LOCK_open.native_handle());
1711
1694
 
1712
1695
  table->cursor->extra(function);
1713
1696
  /* Mark all tables that are in use as 'old' */
1714
 
  session->abortLock(table);    /* end threads waiting on lock */
 
1697
  mysql_lock_abort(session, table);     /* end threads waiting on lock */
1715
1698
 
1716
1699
  /* Wait until all there are no other threads that has this table open */
1717
 
  identifier::Table identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName());
1718
 
  table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
 
1700
  TableIdentifier identifier(table->getMutableShare()->getSchemaName(), table->getMutableShare()->getTableName());
 
1701
  remove_table_from_cache(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
1719
1702
}
1720
1703
 
1721
1704
/*
1731
1714
    reopen the table.
1732
1715
 
1733
1716
  PREREQUISITES
1734
 
    Lock on table::Cache::singleton().mutex()
 
1717
    Lock on LOCK_open
1735
1718
    Win32 clients must also have a WRITE LOCK on the table !
1736
1719
*/
1737
1720
 
1742
1725
  /* Close lock if this is not got with LOCK TABLES */
1743
1726
  if (lock)
1744
1727
  {
1745
 
    unlockTables(lock);
 
1728
    mysql_unlock_tables(this, lock);
1746
1729
    lock= NULL;                 // Start locked threads
1747
1730
  }
1748
1731
  /* Close all copies of 'table'.  This also frees all LOCK TABLES lock */
1749
1732
  unlink_open_table(table);
1750
1733
 
1751
 
  /* When lock on table::Cache::singleton().mutex() is freed other threads can continue */
1752
 
  locking::broadcast_refresh();
 
1734
  /* When lock on LOCK_open is freed other threads can continue */
 
1735
  broadcast_refresh();
1753
1736
}
1754
1737
 
1755
1738
/*
1758
1741
    true  Message should be sent by caller
1759
1742
          (admin operation or network communication failed)
1760
1743
*/
1761
 
static bool admin_table(Session* session, TableList* tables,
 
1744
static bool mysql_admin_table(Session* session, TableList* tables,
1762
1745
                              HA_CHECK_OPT* check_opt,
1763
1746
                              const char *operator_name,
1764
1747
                              thr_lock_type lock_type,
1767
1750
                                                            HA_CHECK_OPT *))
1768
1751
{
1769
1752
  TableList *table;
1770
 
  Select_Lex *select= &session->getLex()->select_lex;
 
1753
  Select_Lex *select= &session->lex->select_lex;
1771
1754
  List<Item> field_list;
1772
1755
  Item *item;
 
1756
  LEX *lex= session->lex;
1773
1757
  int result_code= 0;
1774
1758
  TransactionServices &transaction_services= TransactionServices::singleton();
1775
1759
  const CHARSET_INFO * const cs= system_charset_info;
1776
1760
 
1777
1761
  if (! session->endActiveTransaction())
1778
1762
    return 1;
1779
 
 
1780
1763
  field_list.push_back(item = new Item_empty_string("Table",
1781
1764
                                                    NAME_CHAR_LEN * 2,
1782
1765
                                                    cs));
1787
1770
  item->maybe_null = 1;
1788
1771
  field_list.push_back(item = new Item_empty_string("Msg_text", 255, cs));
1789
1772
  item->maybe_null = 1;
1790
 
  if (session->getClient()->sendFields(&field_list))
 
1773
  if (session->client->sendFields(&field_list))
1791
1774
    return true;
1792
1775
 
1793
1776
  for (table= tables; table; table= table->next_local)
1794
1777
  {
1795
 
    identifier::Table table_identifier(table->getSchemaName(), table->getTableName());
1796
 
    std::string table_name;
 
1778
    char table_name[NAME_LEN*2+2];
 
1779
    char* db = table->db;
1797
1780
    bool fatal_error=0;
1798
1781
 
1799
 
    table_identifier.getSQLPath(table_name);
1800
 
 
 
1782
    snprintf(table_name, sizeof(table_name), "%s.%s",db,table->table_name);
1801
1783
    table->lock_type= lock_type;
1802
1784
    /* open only one table from local list of command */
1803
1785
    {
1812
1794
        so it have to be prepared.
1813
1795
        @todo Investigate if we can put extra tables into argument instead of using lex->query_tables
1814
1796
      */
1815
 
      session->getLex()->query_tables= table;
1816
 
      session->getLex()->query_tables_last= &table->next_global;
1817
 
      session->getLex()->query_tables_own_last= 0;
 
1797
      lex->query_tables= table;
 
1798
      lex->query_tables_last= &table->next_global;
 
1799
      lex->query_tables_own_last= 0;
1818
1800
      session->no_warnings_for_error= 0;
1819
1801
 
1820
1802
      session->openTablesLock(table);
1833
1815
    */
1834
1816
    if (!table->table)
1835
1817
    {
1836
 
      if (!session->warn_list.size())
 
1818
      if (!session->warn_list.elements)
1837
1819
        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1838
1820
                     ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE));
1839
1821
      result_code= HA_ADMIN_CORRUPT;
1844
1826
    {
1845
1827
      char buff[FN_REFLEN + DRIZZLE_ERRMSG_SIZE];
1846
1828
      uint32_t length;
1847
 
      session->getClient()->store(table_name.c_str());
1848
 
      session->getClient()->store(operator_name);
1849
 
      session->getClient()->store(STRING_WITH_LEN("error"));
 
1829
      session->client->store(table_name);
 
1830
      session->client->store(operator_name);
 
1831
      session->client->store(STRING_WITH_LEN("error"));
1850
1832
      length= snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
1851
 
                       table_name.c_str());
1852
 
      session->getClient()->store(buff, length);
1853
 
      transaction_services.autocommitOrRollback(*session, false);
 
1833
                       table_name);
 
1834
      session->client->store(buff, length);
 
1835
      transaction_services.autocommitOrRollback(session, false);
1854
1836
      session->endTransaction(COMMIT);
1855
1837
      session->close_thread_tables();
1856
 
      session->getLex()->reset_query_tables_list(false);
 
1838
      lex->reset_query_tables_list(false);
1857
1839
      table->table=0;                           // For query cache
1858
 
      if (session->getClient()->flush())
 
1840
      if (session->client->flush())
1859
1841
        goto err;
1860
1842
      continue;
1861
1843
    }
1863
1845
    /* Close all instances of the table to allow repair to rename files */
1864
1846
    if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
1865
1847
    {
1866
 
      table::Cache::singleton().mutex().lock(); /* Lock type is TL_WRITE and we lock to repair the table */
1867
 
      const char *old_message=session->enter_cond(COND_refresh, table::Cache::singleton().mutex(),
 
1848
      LOCK_open.lock(); /* Lock type is TL_WRITE and we lock to repair the table */
 
1849
      const char *old_message=session->enter_cond(COND_refresh, LOCK_open,
1868
1850
                                                  "Waiting to get writelock");
1869
 
      session->abortLock(table->table);
1870
 
      identifier::Table identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1871
 
      table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG);
 
1851
      mysql_lock_abort(session,table->table);
 
1852
      TableIdentifier identifier(table->table->getMutableShare()->getSchemaName(), table->table->getMutableShare()->getTableName());
 
1853
      remove_table_from_cache(session, identifier,
 
1854
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
1855
                              RTFC_CHECK_KILLED_FLAG);
1872
1856
      session->exit_cond(old_message);
1873
 
      if (session->getKilled())
 
1857
      if (session->killed)
1874
1858
        goto err;
1875
1859
      open_for_modify= 0;
1876
1860
    }
1879
1863
 
1880
1864
send_result:
1881
1865
 
1882
 
    session->getLex()->cleanup_after_one_table_open();
 
1866
    lex->cleanup_after_one_table_open();
1883
1867
    session->clear_error();  // these errors shouldn't get client
1884
1868
    {
1885
 
      List<DRIZZLE_ERROR>::iterator it(session->warn_list.begin());
 
1869
      List_iterator_fast<DRIZZLE_ERROR> it(session->warn_list);
1886
1870
      DRIZZLE_ERROR *err;
1887
1871
      while ((err= it++))
1888
1872
      {
1889
 
        session->getClient()->store(table_name.c_str());
1890
 
        session->getClient()->store(operator_name);
1891
 
        session->getClient()->store(warning_level_names[err->level].str,
 
1873
        session->client->store(table_name);
 
1874
        session->client->store(operator_name);
 
1875
        session->client->store(warning_level_names[err->level].str,
1892
1876
                               warning_level_names[err->level].length);
1893
 
        session->getClient()->store(err->msg);
1894
 
        if (session->getClient()->flush())
 
1877
        session->client->store(err->msg);
 
1878
        if (session->client->flush())
1895
1879
          goto err;
1896
1880
      }
1897
1881
      drizzle_reset_errors(session, true);
1898
1882
    }
1899
 
    session->getClient()->store(table_name.c_str());
1900
 
    session->getClient()->store(operator_name);
 
1883
    session->client->store(table_name);
 
1884
    session->client->store(operator_name);
1901
1885
 
1902
1886
    switch (result_code) {
1903
1887
    case HA_ADMIN_NOT_IMPLEMENTED:
1905
1889
        char buf[ERRMSGSIZE+20];
1906
1890
        uint32_t length=snprintf(buf, ERRMSGSIZE,
1907
1891
                             ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
1908
 
        session->getClient()->store(STRING_WITH_LEN("note"));
1909
 
        session->getClient()->store(buf, length);
 
1892
        session->client->store(STRING_WITH_LEN("note"));
 
1893
        session->client->store(buf, length);
1910
1894
      }
1911
1895
      break;
1912
1896
 
1913
1897
    case HA_ADMIN_OK:
1914
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1915
 
      session->getClient()->store(STRING_WITH_LEN("OK"));
 
1898
      session->client->store(STRING_WITH_LEN("status"));
 
1899
      session->client->store(STRING_WITH_LEN("OK"));
1916
1900
      break;
1917
1901
 
1918
1902
    case HA_ADMIN_FAILED:
1919
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1920
 
      session->getClient()->store(STRING_WITH_LEN("Operation failed"));
 
1903
      session->client->store(STRING_WITH_LEN("status"));
 
1904
      session->client->store(STRING_WITH_LEN("Operation failed"));
1921
1905
      break;
1922
1906
 
1923
1907
    case HA_ADMIN_REJECT:
1924
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1925
 
      session->getClient()->store(STRING_WITH_LEN("Operation need committed state"));
 
1908
      session->client->store(STRING_WITH_LEN("status"));
 
1909
      session->client->store(STRING_WITH_LEN("Operation need committed state"));
1926
1910
      open_for_modify= false;
1927
1911
      break;
1928
1912
 
1929
1913
    case HA_ADMIN_ALREADY_DONE:
1930
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1931
 
      session->getClient()->store(STRING_WITH_LEN("Table is already up to date"));
 
1914
      session->client->store(STRING_WITH_LEN("status"));
 
1915
      session->client->store(STRING_WITH_LEN("Table is already up to date"));
1932
1916
      break;
1933
1917
 
1934
1918
    case HA_ADMIN_CORRUPT:
1935
 
      session->getClient()->store(STRING_WITH_LEN("error"));
1936
 
      session->getClient()->store(STRING_WITH_LEN("Corrupt"));
 
1919
      session->client->store(STRING_WITH_LEN("error"));
 
1920
      session->client->store(STRING_WITH_LEN("Corrupt"));
1937
1921
      fatal_error=1;
1938
1922
      break;
1939
1923
 
1940
1924
    case HA_ADMIN_INVALID:
1941
 
      session->getClient()->store(STRING_WITH_LEN("error"));
1942
 
      session->getClient()->store(STRING_WITH_LEN("Invalid argument"));
 
1925
      session->client->store(STRING_WITH_LEN("error"));
 
1926
      session->client->store(STRING_WITH_LEN("Invalid argument"));
1943
1927
      break;
1944
1928
 
1945
1929
    default:                            // Probably HA_ADMIN_INTERNAL_ERROR
1948
1932
        uint32_t length=snprintf(buf, ERRMSGSIZE,
1949
1933
                             _("Unknown - internal error %d during operation"),
1950
1934
                             result_code);
1951
 
        session->getClient()->store(STRING_WITH_LEN("error"));
1952
 
        session->getClient()->store(buf, length);
 
1935
        session->client->store(STRING_WITH_LEN("error"));
 
1936
        session->client->store(buf, length);
1953
1937
        fatal_error=1;
1954
1938
        break;
1955
1939
      }
1968
1952
        }
1969
1953
        else
1970
1954
        {
1971
 
          boost::unique_lock<boost::mutex> lock(table::Cache::singleton().mutex());
1972
 
          identifier::Table identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1973
 
          table::Cache::singleton().removeTable(session, identifier, RTFC_NO_FLAG);
 
1955
          boost::mutex::scoped_lock lock(LOCK_open);
 
1956
          TableIdentifier identifier(table->table->getMutableShare()->getSchemaName(), table->table->getMutableShare()->getTableName());
 
1957
          remove_table_from_cache(session, identifier, RTFC_NO_FLAG);
1974
1958
        }
1975
1959
      }
1976
1960
    }
1977
 
    transaction_services.autocommitOrRollback(*session, false);
 
1961
    transaction_services.autocommitOrRollback(session, false);
1978
1962
    session->endTransaction(COMMIT);
1979
1963
    session->close_thread_tables();
1980
1964
    table->table=0;                             // For query cache
1981
 
    if (session->getClient()->flush())
 
1965
    if (session->client->flush())
1982
1966
      goto err;
1983
1967
  }
1984
1968
 
1986
1970
  return(false);
1987
1971
 
1988
1972
err:
1989
 
  transaction_services.autocommitOrRollback(*session, true);
 
1973
  transaction_services.autocommitOrRollback(session, true);
1990
1974
  session->endTransaction(ROLLBACK);
1991
1975
  session->close_thread_tables();                       // Shouldn't be needed
1992
1976
  if (table)
2000
1984
    Altough exclusive name-lock on target table protects us from concurrent
2001
1985
    DML and DDL operations on it we still want to wrap .FRM creation and call
2002
1986
    to plugin::StorageEngine::createTable() in critical section protected by
2003
 
    table::Cache::singleton().mutex() in order to provide minimal atomicity against operations which
 
1987
    LOCK_open in order to provide minimal atomicity against operations which
2004
1988
    disregard name-locks, like I_S implementation, for example. This is a
2005
1989
    temporary and should not be copied. Instead we should fix our code to
2006
1990
    always honor name-locks.
2007
1991
 
2008
 
    Also some engines (e.g. NDB cluster) require that table::Cache::singleton().mutex() should be held
 
1992
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
2009
1993
    during the call to plugin::StorageEngine::createTable().
2010
1994
    See bug #28614 for more info.
2011
1995
  */
2012
 
static bool create_table_wrapper(Session &session,
2013
 
                                 const message::Table& create_table_proto,
2014
 
                                 identifier::Table::const_reference destination_identifier,
2015
 
                                 identifier::Table::const_reference source_identifier,
 
1996
static bool create_table_wrapper(Session &session, const message::Table& create_table_proto,
 
1997
                                 TableIdentifier &destination_identifier,
 
1998
                                 TableIdentifier &src_table,
2016
1999
                                 bool is_engine_set)
2017
2000
{
2018
 
  // We require an additional table message because during parsing we used
2019
 
  // a "new" message and it will not have all of the information that the
2020
 
  // source table message would have.
2021
 
  message::Table new_table_message;
2022
 
 
2023
 
  message::table::shared_ptr source_table_message= plugin::StorageEngine::getTableMessage(session, source_identifier);
2024
 
 
2025
 
  if (not source_table_message)
2026
 
  {
2027
 
    my_error(ER_TABLE_UNKNOWN, source_identifier);
2028
 
    return false;
2029
 
  }
2030
 
 
2031
 
  new_table_message.CopyFrom(*source_table_message);
 
2001
  int protoerr= EEXIST;
 
2002
  message::Table new_proto;
 
2003
  message::Table src_proto;
 
2004
 
 
2005
  protoerr= plugin::StorageEngine::getTableDefinition(session,
 
2006
                                                      src_table,
 
2007
                                                      src_proto);
 
2008
  new_proto.CopyFrom(src_proto);
2032
2009
 
2033
2010
  if (destination_identifier.isTmp())
2034
2011
  {
2035
 
    new_table_message.set_type(message::Table::TEMPORARY);
 
2012
    new_proto.set_type(message::Table::TEMPORARY);
2036
2013
  }
2037
2014
  else
2038
2015
  {
2039
 
    new_table_message.set_type(message::Table::STANDARD);
 
2016
    new_proto.set_type(message::Table::STANDARD);
2040
2017
  }
2041
2018
 
2042
2019
  if (is_engine_set)
2043
2020
  {
2044
 
    new_table_message.mutable_engine()->set_name(create_table_proto.engine().name());
 
2021
    new_proto.mutable_engine()->set_name(create_table_proto.engine().name());
2045
2022
  }
2046
2023
 
2047
2024
  { // We now do a selective copy of elements on to the new table.
2048
 
    new_table_message.set_name(create_table_proto.name());
2049
 
    new_table_message.set_schema(create_table_proto.schema());
2050
 
    new_table_message.set_catalog(create_table_proto.catalog());
 
2025
    new_proto.set_name(create_table_proto.name());
 
2026
    new_proto.set_schema(create_table_proto.schema());
 
2027
    new_proto.set_catalog(create_table_proto.catalog());
2051
2028
  }
2052
2029
 
2053
 
  /* Fix names of foreign keys being added */
2054
 
  for (int32_t j= 0; j < new_table_message.fk_constraint_size(); j++)
 
2030
  if (protoerr && protoerr != EEXIST)
2055
2031
  {
2056
 
    if (new_table_message.fk_constraint(j).has_name())
2057
 
    {
2058
 
      std::string name(new_table_message.name());
2059
 
      char number[20];
2060
 
 
2061
 
      name.append("_ibfk_");
2062
 
      snprintf(number, sizeof(number), "%d", j+1);
2063
 
      name.append(number);
2064
 
 
2065
 
      message::Table::ForeignKeyConstraint *pfkey= new_table_message.mutable_fk_constraint(j);
2066
 
      pfkey->set_name(name);
2067
 
    }
 
2032
    if (errno == ENOENT)
 
2033
      my_error(ER_BAD_DB_ERROR,MYF(0), destination_identifier.getSchemaName().c_str());
 
2034
    else
 
2035
      my_error(ER_CANT_CREATE_FILE, MYF(0), destination_identifier.getPath().c_str(), errno);
 
2036
 
 
2037
    return false;
2068
2038
  }
2069
2039
 
2070
2040
  /*
2071
2041
    As mysql_truncate don't work on a new table at this stage of
2072
 
    creation, instead create the table directly (for both normal and temporary tables).
 
2042
    creation, instead create the table directly (for both normal
 
2043
    and temporary tables).
2073
2044
  */
2074
 
  bool success= plugin::StorageEngine::createTable(session,
2075
 
                                                   destination_identifier,
2076
 
                                                   new_table_message);
 
2045
  int err= plugin::StorageEngine::createTable(session,
 
2046
                                              destination_identifier,
 
2047
                                              new_proto);
2077
2048
 
2078
 
  if (success && not destination_identifier.isTmp())
 
2049
  if (err == false && not destination_identifier.isTmp())
2079
2050
  {
2080
2051
    TransactionServices &transaction_services= TransactionServices::singleton();
2081
 
    transaction_services.createTable(session, new_table_message);
 
2052
    transaction_services.createTable(&session, new_proto);
2082
2053
  }
2083
2054
 
2084
 
  return success;
 
2055
  return err ? false : true;
2085
2056
}
2086
2057
 
2087
2058
/*
2088
2059
  Create a table identical to the specified table
2089
2060
 
2090
2061
  SYNOPSIS
2091
 
    create_like_table()
 
2062
    mysql_create_like_table()
2092
2063
    session             Thread object
2093
2064
    table       Table list element for target table
2094
2065
    src_table   Table list element for source table
2099
2070
    true  error
2100
2071
*/
2101
2072
 
2102
 
bool create_like_table(Session* session,
2103
 
                       identifier::Table::const_reference destination_identifier,
2104
 
                       identifier::Table::const_reference source_identifier,
2105
 
                       message::Table &create_table_proto,
2106
 
                       bool is_if_not_exists,
2107
 
                       bool is_engine_set)
 
2073
bool mysql_create_like_table(Session* session,
 
2074
                             TableIdentifier &destination_identifier,
 
2075
                             TableList* table, TableList* src_table,
 
2076
                             message::Table &create_table_proto,
 
2077
                             bool is_if_not_exists,
 
2078
                             bool is_engine_set)
2108
2079
{
 
2080
  char *db= table->db;
 
2081
  char *table_name= table->table_name;
2109
2082
  bool res= true;
2110
 
  bool table_exists= false;
 
2083
  uint32_t not_used;
 
2084
 
 
2085
  /*
 
2086
    By opening source table we guarantee that it exists and no concurrent
 
2087
    DDL operation will mess with it. Later we also take an exclusive
 
2088
    name-lock on target table name, which makes copying of .frm cursor,
 
2089
    call to plugin::StorageEngine::createTable() and binlogging atomic
 
2090
    against concurrent DML and DDL operations on target table.
 
2091
    Thus by holding both these "locks" we ensure that our statement is
 
2092
    properly isolated from all concurrent operations which matter.
 
2093
  */
 
2094
  if (session->open_tables_from_list(&src_table, &not_used))
 
2095
    return true;
 
2096
 
 
2097
  TableIdentifier src_identifier(src_table->table->getMutableShare()->getSchemaName(),
 
2098
                                 src_table->table->getMutableShare()->getTableName(), src_table->table->getMutableShare()->getType());
 
2099
 
 
2100
 
2111
2101
 
2112
2102
  /*
2113
2103
    Check that destination tables does not exist. Note that its name
2115
2105
 
2116
2106
    For temporary tables we don't aim to grab locks.
2117
2107
  */
 
2108
  bool table_exists= false;
2118
2109
  if (destination_identifier.isTmp())
2119
2110
  {
2120
 
    if (session->find_temporary_table(destination_identifier))
 
2111
    if (session->find_temporary_table(db, table_name))
2121
2112
    {
2122
2113
      table_exists= true;
2123
2114
    }
2124
2115
    else
2125
2116
    {
2126
 
      bool was_created= create_table_wrapper(*session,
2127
 
                                             create_table_proto,
2128
 
                                             destination_identifier,
2129
 
                                             source_identifier,
2130
 
                                             is_engine_set);
 
2117
      bool was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
 
2118
                                             src_identifier, is_engine_set);
2131
2119
      if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2132
2120
      {
2133
2121
        (void) session->rm_temporary_table(destination_identifier, true);
2151
2139
    {
2152
2140
      if (name_lock)
2153
2141
      {
2154
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
 
2142
        boost::mutex::scoped_lock lock(LOCK_open); /* unlink open tables for create table like*/
2155
2143
        session->unlink_open_table(name_lock);
2156
2144
      }
2157
2145
 
2170
2158
    {
2171
2159
      bool was_created;
2172
2160
      {
2173
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
 
2161
        boost::mutex::scoped_lock lock(LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
2174
2162
        was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2175
 
                                          source_identifier, is_engine_set);
 
2163
                                               src_identifier, is_engine_set);
2176
2164
      }
2177
2165
 
2178
2166
      // So we blew the creation of the table, and we scramble to clean up
2179
2167
      // anything that might have been created (read... it is a hack)
2180
2168
      if (not was_created)
2181
2169
      {
2182
 
        plugin::StorageEngine::dropTable(*session, destination_identifier);
 
2170
        quick_rm_table(*session, destination_identifier);
2183
2171
      } 
2184
2172
      else
2185
2173
      {
2189
2177
 
2190
2178
    if (name_lock)
2191
2179
    {
2192
 
      boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
 
2180
      boost::mutex::scoped_lock lock(LOCK_open); /* unlink open tables for create table like*/
2193
2181
      session->unlink_open_table(name_lock);
2194
2182
    }
2195
2183
  }
2200
2188
    {
2201
2189
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
2202
2190
      snprintf(warn_buff, sizeof(warn_buff),
2203
 
               ER(ER_TABLE_EXISTS_ERROR), destination_identifier.getTableName().c_str());
 
2191
               ER(ER_TABLE_EXISTS_ERROR), table_name);
2204
2192
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2205
 
                   ER_TABLE_EXISTS_ERROR, warn_buff);
2206
 
      return false;
2207
 
    }
2208
 
 
2209
 
    my_error(ER_TABLE_EXISTS_ERROR, destination_identifier);
2210
 
 
2211
 
    return true;
 
2193
                   ER_TABLE_EXISTS_ERROR,warn_buff);
 
2194
      res= false;
 
2195
    }
 
2196
    else
 
2197
    {
 
2198
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
2199
    }
2212
2200
  }
2213
2201
 
2214
 
  return res;
 
2202
  return(res);
2215
2203
}
2216
2204
 
2217
2205
 
2218
 
bool analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
 
2206
bool mysql_analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
2219
2207
{
2220
2208
  thr_lock_type lock_type = TL_READ_NO_INSERT;
2221
2209
 
2222
 
  return(admin_table(session, tables, check_opt,
 
2210
  return(mysql_admin_table(session, tables, check_opt,
2223
2211
                                "analyze", lock_type, true,
2224
2212
                                &Cursor::ha_analyze));
2225
2213
}
2226
2214
 
2227
2215
 
2228
 
bool check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
 
2216
bool mysql_check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
2229
2217
{
2230
2218
  thr_lock_type lock_type = TL_READ_NO_INSERT;
2231
2219
 
2232
 
  return(admin_table(session, tables, check_opt,
 
2220
  return(mysql_admin_table(session, tables, check_opt,
2233
2221
                                "check", lock_type,
2234
2222
                                false,
2235
2223
                                &Cursor::ha_check));