~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

  • Committer: Monty Taylor
  • Date: 2010-07-19 05:06:59 UTC
  • mto: (1662.1.2 rollup)
  • mto: This revision was merged to the branch mainline in revision 1663.
  • Revision ID: mordred@inaugust.com-20100719050659-if3thz0k66m1jkaf
Backed out two bits that snuck in to the merge.

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>
 
29
#include "drizzled/strfunc.h"
 
30
#include <drizzled/db.h>
30
31
#include <drizzled/lock.h>
31
32
#include <drizzled/unireg.h>
32
33
#include <drizzled/item/int.h>
33
34
#include <drizzled/item/empty_string.h>
34
35
#include <drizzled/transaction_services.h>
35
 
#include <drizzled/transaction_services.h>
 
36
#include "drizzled/transaction_services.h"
36
37
#include <drizzled/table_proto.h>
37
38
#include <drizzled/plugin/client.h>
38
39
#include <drizzled/identifier.h>
39
 
#include <drizzled/internal/m_string.h>
40
 
#include <drizzled/global_charset_info.h>
41
 
#include <drizzled/charset.h>
42
 
 
43
 
#include <drizzled/definition/cache.h>
44
 
 
45
 
#include <drizzled/statement/alter_table.h>
46
 
#include <drizzled/sql_table.h>
47
 
#include <drizzled/pthread_globals.h>
48
 
#include <drizzled/typelib.h>
49
 
#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"
50
48
 
51
49
#include <algorithm>
52
50
#include <sstream>
58
56
namespace drizzled
59
57
{
60
58
 
 
59
extern pid_t current_pid;
 
60
 
61
61
bool is_primary_key(KeyInfo *key_info)
62
62
{
63
63
  static const char * primary_key_name="PRIMARY";
85
85
    let's fetch the database default character set and
86
86
    apply it to the table.
87
87
  */
88
 
  identifier::Schema identifier(db);
 
88
  SchemaIdentifier identifier(db);
89
89
  if (create_info->default_table_charset == NULL)
90
90
    create_info->default_table_charset= plugin::StorageEngine::getSchemaCollation(identifier);
91
91
}
105
105
    cursor
106
106
*/
107
107
 
108
 
void write_bin_log(Session *session, const std::string &query)
109
 
{
110
 
  TransactionServices &transaction_services= TransactionServices::singleton();
111
 
  transaction_services.rawStatement(*session, query);
 
108
void write_bin_log(Session *session,
 
109
                   char const *query)
 
110
{
 
111
  TransactionServices &transaction_services= TransactionServices::singleton();
 
112
  transaction_services.rawStatement(session, query);
 
113
}
 
114
 
 
115
 
 
116
/* Should should be refactored to go away */
 
117
void write_bin_log_drop_table(Session *session, bool if_exists, const char *db_name, const char *table_name)
 
118
{
 
119
  TransactionServices &transaction_services= TransactionServices::singleton();
 
120
  string built_query;
 
121
 
 
122
  if (if_exists)
 
123
    built_query.append("DROP TABLE IF EXISTS ");
 
124
  else
 
125
    built_query.append("DROP TABLE ");
 
126
 
 
127
  built_query.append("`");
 
128
  if (session->db.empty() || strcmp(db_name, session->db.c_str()) != 0)
 
129
  {
 
130
    built_query.append(db_name);
 
131
    built_query.append("`.`");
 
132
  }
 
133
 
 
134
  built_query.append(table_name);
 
135
  built_query.append("`");
 
136
  transaction_services.rawStatement(session, built_query);
112
137
}
113
138
 
114
139
/*
115
140
  Execute the drop of a normal or temporary table
116
141
 
117
142
  SYNOPSIS
118
 
    rm_table_part2()
 
143
    mysql_rm_table_part2()
119
144
    session                     Thread Cursor
120
145
    tables              Tables to drop
121
146
    if_exists           If set, don't give an error if table doesn't exists.
122
147
                        In this case we give an warning of level 'NOTE'
123
148
    drop_temporary      Only drop temporary tables
124
149
 
125
 
  @todo
 
150
  TODO:
126
151
    When logging to the binary log, we should log
127
152
    tmp_tables and transactional tables as separate statements if we
128
153
    are in a transaction;  This is needed to get these tables into the
138
163
   -1   Thread was killed
139
164
*/
140
165
 
141
 
int rm_table_part2(Session *session, TableList *tables, bool if_exists,
142
 
                   bool drop_temporary)
 
166
int mysql_rm_table_part2(Session *session, TableList *tables, bool if_exists,
 
167
                         bool drop_temporary)
143
168
{
144
169
  TableList *table;
145
 
  util::string::vector wrong_tables;
 
170
  String wrong_tables;
146
171
  int error= 0;
147
172
  bool foreign_key_error= false;
148
173
 
149
 
  do
150
 
  {
151
 
    boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
152
 
 
153
 
    if (not drop_temporary && session->lock_table_names_exclusively(tables))
154
 
    {
155
 
      return 1;
156
 
    }
157
 
 
158
 
    /* Don't give warnings for not found errors, as we already generate notes */
159
 
    session->no_warnings_for_error= 1;
160
 
 
161
 
    for (table= tables; table; table= table->next_local)
162
 
    {
163
 
      identifier::Table tmp_identifier(table->getSchemaName(), table->getTableName());
164
 
 
165
 
      error= session->drop_temporary_table(tmp_identifier);
166
 
 
167
 
      switch (error) {
168
 
      case  0:
169
 
        // removed temporary table
170
 
        continue;
171
 
      case -1:
 
174
  pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
 
175
 
 
176
  /*
 
177
    If we have the table in the definition cache, we don't have to check the
 
178
    .frm cursor to find if the table is a normal table (not view) and what
 
179
    engine to use.
 
180
  */
 
181
 
 
182
  for (table= tables; table; table= table->next_local)
 
183
  {
 
184
    TableIdentifier identifier(table->db, table->table_name);
 
185
    TableShare *share;
 
186
    table->setDbType(NULL);
 
187
 
 
188
    if ((share= TableShare::getShare(identifier)))
 
189
    {
 
190
      table->setDbType(share->db_type());
 
191
    }
 
192
  }
 
193
 
 
194
  if (not drop_temporary && lock_table_names_exclusively(session, tables))
 
195
  {
 
196
    pthread_mutex_unlock(&LOCK_open);
 
197
    return 1;
 
198
  }
 
199
 
 
200
  /* Don't give warnings for not found errors, as we already generate notes */
 
201
  session->no_warnings_for_error= 1;
 
202
 
 
203
  for (table= tables; table; table= table->next_local)
 
204
  {
 
205
    char *db=table->db;
 
206
 
 
207
    error= session->drop_temporary_table(table);
 
208
 
 
209
    switch (error) {
 
210
    case  0:
 
211
      // removed temporary table
 
212
      continue;
 
213
    case -1:
 
214
      error= 1;
 
215
      goto err_with_placeholders;
 
216
    default:
 
217
      // temporary table not found
 
218
      error= 0;
 
219
    }
 
220
 
 
221
    if (drop_temporary == false)
 
222
    {
 
223
      Table *locked_table;
 
224
      abort_locked_tables(session, db, table->table_name);
 
225
      TableIdentifier identifier(db, table->table_name);
 
226
      remove_table_from_cache(session, identifier,
 
227
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
228
                              RTFC_CHECK_KILLED_FLAG);
 
229
      /*
 
230
        If the table was used in lock tables, remember it so that
 
231
        unlock_table_names can free it
 
232
      */
 
233
      if ((locked_table= drop_locked_tables(session, db, table->table_name)))
 
234
        table->table= locked_table;
 
235
 
 
236
      if (session->killed)
 
237
      {
 
238
        error= -1;
 
239
        goto err_with_placeholders;
 
240
      }
 
241
    }
 
242
    TableIdentifier identifier(db, table->table_name, table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
 
243
 
 
244
    if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
 
245
    {
 
246
      // Table was not found on disk and table can't be created from engine
 
247
      if (if_exists)
 
248
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
249
                            ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 
250
                            table->table_name);
 
251
      else
172
252
        error= 1;
173
 
        break;
174
 
      default:
175
 
        // temporary table not found
 
253
    }
 
254
    else
 
255
    {
 
256
      error= plugin::StorageEngine::dropTable(*session, identifier);
 
257
 
 
258
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
 
259
      {
176
260
        error= 0;
177
 
      }
178
 
 
179
 
      if (drop_temporary == false)
180
 
      {
181
 
        Table *locked_table;
182
 
        abort_locked_tables(session, tmp_identifier);
183
 
        table::Cache::singleton().removeTable(session, tmp_identifier,
184
 
                                              RTFC_WAIT_OTHER_THREAD_FLAG |
185
 
                                              RTFC_CHECK_KILLED_FLAG);
186
 
        /*
187
 
          If the table was used in lock tables, remember it so that
188
 
          unlock_table_names can free it
189
 
        */
190
 
        if ((locked_table= drop_locked_tables(session, tmp_identifier)))
191
 
          table->table= locked_table;
192
 
 
193
 
        if (session->getKilled())
194
 
        {
195
 
          error= -1;
196
 
          break;
197
 
        }
198
 
      }
199
 
      identifier::Table identifier(table->getSchemaName(), table->getTableName(), table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
200
 
 
201
 
      message::table::shared_ptr message= plugin::StorageEngine::getTableMessage(*session, identifier, true);
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
 
        {
208
 
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
209
 
                              ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
210
 
                              table->getTableName());
211
 
        }
212
 
        else
213
 
        {
214
 
          error= 1;
215
 
        }
216
 
      }
217
 
      else
218
 
      {
219
 
        drizzled::error_t local_error;
220
 
 
221
 
        /* Generate transaction event ONLY when we successfully drop */ 
222
 
        if (plugin::StorageEngine::dropTable(*session, identifier, local_error))
223
 
        {
224
 
          if (message) // If we have no definition, we don't know if the table should have been replicated
225
 
          {
226
 
            TransactionServices &transaction_services= TransactionServices::singleton();
227
 
            transaction_services.dropTable(*session, identifier, *message, if_exists);
228
 
          }
229
 
        }
230
 
        else
231
 
        {
232
 
          if (local_error == HA_ERR_NO_SUCH_TABLE and if_exists)
233
 
          {
234
 
            error= 0;
235
 
            session->clear_error();
236
 
          }
237
 
 
238
 
          if (local_error == HA_ERR_ROW_IS_REFERENCED)
239
 
          {
240
 
            /* the table is referenced by a foreign key constraint */
241
 
            foreign_key_error= true;
242
 
          }
243
 
          error= local_error;
244
 
        }
245
 
      }
246
 
 
247
 
      if (error)
248
 
      {
249
 
        wrong_tables.push_back(table->getTableName());
250
 
      }
251
 
    }
252
 
 
253
 
    tables->unlock_table_names();
254
 
 
255
 
  } while (0);
256
 
 
257
 
  if (wrong_tables.size())
 
261
        session->clear_error();
 
262
      }
 
263
 
 
264
      if (error == HA_ERR_ROW_IS_REFERENCED)
 
265
      {
 
266
        /* the table is referenced by a foreign key constraint */
 
267
        foreign_key_error= true;
 
268
      }
 
269
    }
 
270
 
 
271
    if (error == 0 || (if_exists && foreign_key_error == false))
 
272
    {
 
273
      TransactionServices &transaction_services= TransactionServices::singleton();
 
274
      transaction_services.dropTable(session, string(db), string(table->table_name), if_exists);
 
275
    }
 
276
 
 
277
    if (error)
 
278
    {
 
279
      if (wrong_tables.length())
 
280
        wrong_tables.append(',');
 
281
      wrong_tables.append(String(table->table_name,system_charset_info));
 
282
    }
 
283
  }
 
284
  /*
 
285
    It's safe to unlock LOCK_open: we have an exclusive lock
 
286
    on the table name.
 
287
  */
 
288
  pthread_mutex_unlock(&LOCK_open);
 
289
  error= 0;
 
290
 
 
291
  if (wrong_tables.length())
258
292
  {
259
293
    if (not foreign_key_error)
260
294
    {
261
 
      std::string table_error;
262
 
 
263
 
      for (util::string::vector::iterator iter= wrong_tables.begin();
264
 
           iter != wrong_tables.end();
265
 
           iter++)
266
 
      {
267
 
        table_error+= *iter;
268
 
        table_error+= ',';
269
 
      }
270
 
      table_error.resize(table_error.size() -1);
271
 
 
272
295
      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
273
 
                      table_error.c_str());
 
296
                      wrong_tables.c_ptr());
274
297
    }
275
298
    else
276
299
    {
279
302
    error= 1;
280
303
  }
281
304
 
 
305
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
 
306
 
 
307
err_with_placeholders:
 
308
  unlock_table_names(tables, NULL);
 
309
  pthread_mutex_unlock(&LOCK_open);
282
310
  session->no_warnings_for_error= 0;
283
311
 
284
312
  return error;
285
313
}
286
314
 
 
315
 
 
316
/*
 
317
  Quickly remove a table.
 
318
 
 
319
  SYNOPSIS
 
320
    quick_rm_table()
 
321
      base                      The plugin::StorageEngine handle.
 
322
      db                        The database name.
 
323
      table_name                The table name.
 
324
      is_tmp                    If the table is temp.
 
325
 
 
326
  RETURN
 
327
    0           OK
 
328
    != 0        Error
 
329
*/
 
330
bool quick_rm_table(Session& session,
 
331
                    TableIdentifier &identifier)
 
332
{
 
333
  return (plugin::StorageEngine::dropTable(session, identifier));
 
334
}
 
335
 
287
336
/*
288
337
  Sort keys in the following order:
289
338
  - PRIMARY KEY
483
532
    sql_field->length= 8; // Unireg field length
484
533
    (*blob_columns)++;
485
534
    break;
486
 
 
 
535
  case DRIZZLE_TYPE_VARCHAR:
 
536
    break;
487
537
  case DRIZZLE_TYPE_ENUM:
488
 
    {
489
 
      if (check_duplicates_in_interval("ENUM",
490
 
                                       sql_field->field_name,
491
 
                                       sql_field->interval,
492
 
                                       sql_field->charset,
493
 
                                       &dup_val_count))
494
 
      {
495
 
        return 1;
496
 
      }
497
 
    }
498
 
    break;
499
 
 
500
 
  case DRIZZLE_TYPE_MICROTIME:
 
538
    if (check_duplicates_in_interval("ENUM",
 
539
                                     sql_field->field_name,
 
540
                                     sql_field->interval,
 
541
                                     sql_field->charset,
 
542
                                     &dup_val_count))
 
543
      return 1;
 
544
    break;
 
545
  case DRIZZLE_TYPE_DATE:  // Rest of string types
 
546
  case DRIZZLE_TYPE_DATETIME:
 
547
  case DRIZZLE_TYPE_NULL:
 
548
    break;
 
549
  case DRIZZLE_TYPE_DECIMAL:
 
550
    break;
501
551
  case DRIZZLE_TYPE_TIMESTAMP:
502
552
    /* We should replace old TIMESTAMP fields with their newer analogs */
503
553
    if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
513
563
      }
514
564
    }
515
565
    else if (sql_field->unireg_check != Field::NONE)
516
 
    {
517
566
      (*timestamps_with_niladic)++;
518
 
    }
519
567
 
520
568
    (*timestamps)++;
521
 
 
522
 
    break;
523
 
 
524
 
  case DRIZZLE_TYPE_BOOLEAN:
525
 
  case DRIZZLE_TYPE_DATE:  // Rest of string types
526
 
  case DRIZZLE_TYPE_DATETIME:
527
 
  case DRIZZLE_TYPE_DECIMAL:
528
 
  case DRIZZLE_TYPE_DOUBLE:
529
 
  case DRIZZLE_TYPE_LONG:
530
 
  case DRIZZLE_TYPE_LONGLONG:
531
 
  case DRIZZLE_TYPE_NULL:
532
 
  case DRIZZLE_TYPE_TIME:
533
 
  case DRIZZLE_TYPE_UUID:
534
 
  case DRIZZLE_TYPE_VARCHAR:
 
569
    /* fall-through */
 
570
  default:
535
571
    break;
536
572
  }
537
573
 
538
574
  return 0;
539
575
}
540
576
 
541
 
static int prepare_create_table(Session *session,
542
 
                                HA_CREATE_INFO *create_info,
543
 
                                message::Table &create_proto,
544
 
                                AlterInfo *alter_info,
545
 
                                bool tmp_table,
546
 
                                uint32_t *db_options,
547
 
                                KeyInfo **key_info_buffer,
548
 
                                uint32_t *key_count,
549
 
                                int select_field_count)
 
577
static int mysql_prepare_create_table(Session *session,
 
578
                                      HA_CREATE_INFO *create_info,
 
579
                                      message::Table &create_proto,
 
580
                                      AlterInfo *alter_info,
 
581
                                      bool tmp_table,
 
582
                                      uint32_t *db_options,
 
583
                                      KeyInfo **key_info_buffer,
 
584
                                      uint32_t *key_count,
 
585
                                      int select_field_count)
550
586
{
551
587
  const char    *key_name;
552
588
  CreateField   *sql_field,*dup_field;
555
591
  KeyInfo               *key_info;
556
592
  KeyPartInfo *key_part_info;
557
593
  int           timestamps= 0, timestamps_with_niladic= 0;
558
 
  int           dup_no;
 
594
  int           field_no,dup_no;
559
595
  int           select_field_pos,auto_increment=0;
560
 
  List<CreateField>::iterator it(alter_info->create_list.begin());
561
 
  List<CreateField>::iterator it2(alter_info->create_list.begin());
 
596
  List_iterator<CreateField> it(alter_info->create_list);
 
597
  List_iterator<CreateField> it2(alter_info->create_list);
562
598
  uint32_t total_uneven_bit_length= 0;
563
599
 
564
600
  plugin::StorageEngine *engine= plugin::StorageEngine::findByName(create_proto.engine().name());
567
603
  null_fields=blob_columns=0;
568
604
  max_key_length= engine->max_key_length();
569
605
 
570
 
  for (int32_t field_no=0; (sql_field=it++) ; field_no++)
 
606
  for (field_no=0; (sql_field=it++) ; field_no++)
571
607
  {
572
608
    const CHARSET_INFO *save_cs;
573
609
 
577
613
      executing a prepared statement for the second time.
578
614
    */
579
615
    sql_field->length= sql_field->char_length;
580
 
 
581
616
    if (!sql_field->charset)
582
617
      sql_field->charset= create_info->default_table_charset;
583
 
 
584
618
    /*
585
619
      table_charset is set in ALTER Table if we want change character set
586
620
      for all varchar/char columns.
633
667
 
634
668
    if (sql_field->sql_type == DRIZZLE_TYPE_ENUM)
635
669
    {
636
 
      size_t dummy;
 
670
      uint32_t dummy;
637
671
      const CHARSET_INFO * const cs= sql_field->charset;
638
672
      TYPELIB *interval= sql_field->interval;
639
673
 
652
686
        interval= sql_field->interval= typelib(session->mem_root,
653
687
                                               sql_field->interval_list);
654
688
 
655
 
        List<String>::iterator int_it(sql_field->interval_list.begin());
 
689
        List_iterator<String> int_it(sql_field->interval_list);
656
690
        String conv, *tmp;
657
691
        char comma_buf[4];
658
692
        int comma_length= cs->cset->wc_mb(cs, ',', (unsigned char*) comma_buf,
666
700
          if (String::needs_conversion(tmp->length(), tmp->charset(),
667
701
                                       cs, &dummy))
668
702
          {
669
 
            size_t cnv_errs;
 
703
            uint32_t cnv_errs;
670
704
            conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
671
705
            interval->type_names[i]= session->mem_root->strmake_root(conv.ptr(), conv.length());
672
706
            interval->type_lengths[i]= conv.length();
678
712
          interval->type_lengths[i]= lengthsp;
679
713
          ((unsigned char *)interval->type_names[i])[lengthsp]= '\0';
680
714
        }
681
 
        sql_field->interval_list.clear(); // Don't need interval_list anymore
 
715
        sql_field->interval_list.empty(); // Don't need interval_list anymore
682
716
      }
683
717
 
684
718
      /* DRIZZLE_TYPE_ENUM */
701
735
          else /* not NULL */
702
736
          {
703
737
            def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
704
 
            if (interval->find_type2(def->ptr(), def->length(), cs) == 0) /* not found */
 
738
            if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
705
739
            {
706
740
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
707
741
              return(true);
708
742
            }
709
743
          }
710
744
        }
711
 
        uint32_t new_dummy;
712
 
        calculate_interval_lengths(cs, interval, &field_length, &new_dummy);
 
745
        calculate_interval_lengths(cs, interval, &field_length, &dummy);
713
746
        sql_field->length= field_length;
714
747
      }
715
748
      set_if_smaller(sql_field->length, (uint32_t)MAX_FIELD_WIDTH-1);
777
810
    /** @todo Get rid of this MyISAM-specific crap. */
778
811
    if (not create_proto.engine().name().compare("MyISAM") &&
779
812
        ((sql_field->flags & BLOB_FLAG) ||
780
 
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
781
 
    {
 
813
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED)))
782
814
      (*db_options)|= HA_OPTION_PACK_RECORD;
783
 
    }
784
 
 
785
 
    it2= alter_info->create_list.begin();
 
815
    it2.rewind();
786
816
  }
787
817
 
788
818
  /* record_offset will be increased with 'length-of-null-bits' later */
789
819
  record_offset= 0;
790
820
  null_fields+= total_uneven_bit_length;
791
821
 
792
 
  it= alter_info->create_list.begin();
 
822
  it.rewind();
793
823
  while ((sql_field=it++))
794
824
  {
795
825
    assert(sql_field->charset != 0);
829
859
 
830
860
  /* Create keys */
831
861
 
832
 
  List<Key>::iterator key_iterator(alter_info->key_list.begin());
833
 
  List<Key>::iterator key_iterator2(alter_info->key_list.begin());
 
862
  List_iterator<Key> key_iterator(alter_info->key_list);
 
863
  List_iterator<Key> key_iterator2(alter_info->key_list);
834
864
  uint32_t key_parts=0, fk_key_count=0;
835
865
  bool primary_key=0,unique_key=0;
836
866
  Key *key, *key2;
848
878
      fk_key_count++;
849
879
      if (((Foreign_key *)key)->validate(alter_info->create_list))
850
880
        return true;
851
 
 
852
881
      Foreign_key *fk_key= (Foreign_key*) key;
853
 
 
854
 
      add_foreign_key_to_table_message(&create_proto,
855
 
                                       fk_key->name.str,
856
 
                                       fk_key->columns,
857
 
                                       fk_key->ref_table,
858
 
                                       fk_key->ref_columns,
859
 
                                       fk_key->delete_opt,
860
 
                                       fk_key->update_opt,
861
 
                                       fk_key->match_opt);
862
 
 
863
882
      if (fk_key->ref_columns.elements &&
864
883
          fk_key->ref_columns.elements != fk_key->columns.elements)
865
884
      {
880
899
    }
881
900
    if (check_identifier_name(&key->name, ER_TOO_LONG_IDENT))
882
901
      return(true);
883
 
    key_iterator2= alter_info->key_list.begin();
 
902
    key_iterator2.rewind ();
884
903
    if (key->type != Key::FOREIGN_KEY)
885
904
    {
886
905
      while ((key2 = key_iterator2++) != key)
894
913
             key2->name.str != ignore_key &&
895
914
             !foreign_key_prefix(key, key2)))
896
915
        {
897
 
          /* @todo issue warning message */
 
916
          /* TODO: issue warning message */
898
917
          /* mark that the generated key should be ignored */
899
918
          if (!key2->generated ||
900
919
              (key->generated && key->columns.elements <
933
952
  if (!*key_info_buffer || ! key_part_info)
934
953
    return(true);                               // Out of memory
935
954
 
936
 
  key_iterator= alter_info->key_list.begin();
 
955
  key_iterator.rewind();
937
956
  key_number=0;
938
957
  for (; (key=key_iterator++) ; key_number++)
939
958
  {
992
1011
 
993
1012
    message::Table::Field *protofield= NULL;
994
1013
 
995
 
    List<Key_part_spec>::iterator cols(key->columns.begin());
996
 
    List<Key_part_spec>::iterator cols2(key->columns.begin());
 
1014
    List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
997
1015
    for (uint32_t column_nr=0 ; (column=cols++) ; column_nr++)
998
1016
    {
999
1017
      uint32_t length;
1000
1018
      Key_part_spec *dup_column;
1001
1019
      int proto_field_nr= 0;
1002
1020
 
1003
 
      it= alter_info->create_list.begin();
 
1021
      it.rewind();
1004
1022
      field=0;
1005
1023
      while ((sql_field=it++) && ++proto_field_nr &&
1006
1024
             my_strcasecmp(system_charset_info,
1007
1025
                           column->field_name.str,
1008
1026
                           sql_field->field_name))
1009
 
      {
1010
1027
        field++;
1011
 
      }
1012
 
 
1013
1028
      if (!sql_field)
1014
1029
      {
1015
1030
        my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
1016
1031
        return(true);
1017
1032
      }
1018
 
 
1019
1033
      while ((dup_column= cols2++) != column)
1020
1034
      {
1021
1035
        if (!my_strcasecmp(system_charset_info,
1027
1041
          return(true);
1028
1042
        }
1029
1043
      }
1030
 
      cols2= key->columns.begin();
 
1044
      cols2.rewind();
1031
1045
 
1032
1046
      if (create_proto.field_size() > 0)
1033
1047
        protofield= create_proto.mutable_field(proto_field_nr - 1);
1048
1062
            return true;
1049
1063
          }
1050
1064
        }
1051
 
 
1052
1065
        if (! (sql_field->flags & NOT_NULL_FLAG))
1053
1066
        {
1054
1067
          if (key->type == Key::PRIMARY)
1061
1074
            {
1062
1075
              message::Table::Field::FieldConstraints *constraints;
1063
1076
              constraints= protofield->mutable_constraints();
1064
 
              constraints->set_is_notnull(true);
 
1077
              constraints->set_is_nullable(false);
1065
1078
            }
1066
1079
 
1067
1080
          }
1075
1088
            }
1076
1089
          }
1077
1090
        }
1078
 
 
1079
1091
        if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
1080
1092
        {
1081
1093
          if (column_nr == 0 || (engine->check_flag(HTON_BIT_AUTO_PART_KEY)))
1200
1212
        key_info->name=(char*) key_name;
1201
1213
      }
1202
1214
    }
1203
 
 
1204
1215
    if (!key_info->name || check_column_name(key_info->name))
1205
1216
    {
1206
1217
      my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
1207
1218
      return(true);
1208
1219
    }
1209
 
 
1210
1220
    if (!(key_info->flags & HA_NULL_PART_KEY))
1211
 
    {
1212
1221
      unique_key=1;
1213
 
    }
1214
 
 
1215
1222
    key_info->key_length=(uint16_t) key_length;
1216
 
 
1217
1223
    if (key_length > max_key_length)
1218
1224
    {
1219
1225
      my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
1220
1226
      return(true);
1221
1227
    }
1222
 
 
1223
1228
    key_info++;
1224
1229
  }
1225
 
 
1226
1230
  if (!unique_key && !primary_key &&
1227
1231
      (engine->check_flag(HTON_BIT_REQUIRE_PRIMARY_KEY)))
1228
1232
  {
1229
1233
    my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
1230
1234
    return(true);
1231
1235
  }
1232
 
 
1233
1236
  if (auto_increment > 0)
1234
1237
  {
1235
1238
    my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
1240
1243
                     (qsort_cmp) sort_keys);
1241
1244
 
1242
1245
  /* Check fields. */
1243
 
  it= alter_info->create_list.begin();
 
1246
  it.rewind();
1244
1247
  while ((sql_field=it++))
1245
1248
  {
1246
1249
    Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
1247
1250
 
1248
1251
    if (session->variables.sql_mode & MODE_NO_ZERO_DATE &&
1249
1252
        !sql_field->def &&
1250
 
        (sql_field->sql_type == DRIZZLE_TYPE_TIMESTAMP  or sql_field->sql_type == DRIZZLE_TYPE_MICROTIME) &&
 
1253
        sql_field->sql_type == DRIZZLE_TYPE_TIMESTAMP &&
1251
1254
        (sql_field->flags & NOT_NULL_FLAG) &&
1252
1255
        (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
1253
1256
    {
1311
1314
}
1312
1315
 
1313
1316
static bool locked_create_event(Session *session,
1314
 
                                const identifier::Table &identifier,
 
1317
                                TableIdentifier &identifier,
1315
1318
                                HA_CREATE_INFO *create_info,
1316
1319
                                message::Table &table_proto,
1317
1320
                                AlterInfo *alter_info,
1346
1349
        return error;
1347
1350
      }
1348
1351
 
1349
 
      my_error(ER_TABLE_EXISTS_ERROR, identifier);
1350
 
 
 
1352
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1351
1353
      return error;
1352
1354
    }
1353
1355
 
1364
1366
      /*
1365
1367
        @todo improve this error condition.
1366
1368
      */
1367
 
      if (definition::Cache::singleton().find(identifier.getKey()))
 
1369
      if (TableShare::getShare(identifier))
1368
1370
      {
1369
 
        my_error(ER_TABLE_EXISTS_ERROR, identifier);
1370
 
 
 
1371
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1371
1372
        return error;
1372
1373
      }
1373
1374
    }
1405
1406
  if (table_proto.type() == message::Table::STANDARD && not internal_tmp_table)
1406
1407
  {
1407
1408
    TransactionServices &transaction_services= TransactionServices::singleton();
1408
 
    transaction_services.createTable(*session, table_proto);
 
1409
    transaction_services.createTable(session, table_proto);
1409
1410
  }
1410
1411
 
1411
1412
  return false;
1418
1419
  Create a table
1419
1420
 
1420
1421
  SYNOPSIS
1421
 
    create_table_no_lock()
 
1422
    mysql_create_table_no_lock()
1422
1423
    session                     Thread object
1423
1424
    db                  Database
1424
1425
    table_name          Table name
1434
1435
 
1435
1436
    Note that this function assumes that caller already have taken
1436
1437
    name-lock on table being created or used some other way to ensure
1437
 
    that concurrent operations won't intervene. create_table()
 
1438
    that concurrent operations won't intervene. mysql_create_table()
1438
1439
    is a wrapper that can be used for this.
1439
1440
 
1440
1441
  RETURN VALUES
1442
1443
    true  error
1443
1444
*/
1444
1445
 
1445
 
bool create_table_no_lock(Session *session,
1446
 
                                const identifier::Table &identifier,
 
1446
bool mysql_create_table_no_lock(Session *session,
 
1447
                                TableIdentifier &identifier,
1447
1448
                                HA_CREATE_INFO *create_info,
1448
1449
                                message::Table &table_proto,
1449
1450
                                AlterInfo *alter_info,
1465
1466
  assert(identifier.getTableName() == table_proto.name());
1466
1467
  db_options= create_info->table_options;
1467
1468
 
 
1469
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
 
1470
    db_options|=HA_OPTION_PACK_RECORD;
 
1471
 
1468
1472
  set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1469
1473
 
1470
1474
  /* Build a Table object to pass down to the engine, and the do the actual create. */
1471
 
  if (not prepare_create_table(session, create_info, table_proto, alter_info,
1472
 
                               internal_tmp_table,
1473
 
                               &db_options,
1474
 
                               &key_info_buffer, &key_count,
1475
 
                               select_field_count))
 
1475
  if (not mysql_prepare_create_table(session, create_info, table_proto, alter_info,
 
1476
                                 internal_tmp_table,
 
1477
                                 &db_options,
 
1478
                                 &key_info_buffer, &key_count,
 
1479
                                 select_field_count))
1476
1480
  {
1477
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* CREATE TABLE (some confussion on naming, double check) */
 
1481
    pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1478
1482
    error= locked_create_event(session,
1479
1483
                               identifier,
1480
1484
                               create_info,
1484
1488
                               internal_tmp_table,
1485
1489
                               db_options, key_count,
1486
1490
                               key_info_buffer);
 
1491
    pthread_mutex_unlock(&LOCK_open);
1487
1492
  }
1488
1493
 
1489
1494
  session->set_proc_info("After create");
1495
1500
  @note the following two methods implement create [temporary] table.
1496
1501
*/
1497
1502
static bool drizzle_create_table(Session *session,
1498
 
                                 const identifier::Table &identifier,
 
1503
                                 TableIdentifier &identifier,
1499
1504
                                 HA_CREATE_INFO *create_info,
1500
1505
                                 message::Table &table_proto,
1501
1506
                                 AlterInfo *alter_info,
1522
1527
    }
1523
1528
    else
1524
1529
    {
1525
 
      my_error(ER_TABLE_EXISTS_ERROR, identifier);
 
1530
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1526
1531
      result= true;
1527
1532
    }
1528
1533
  }
1529
1534
  else
1530
1535
  {
1531
 
    result= create_table_no_lock(session,
 
1536
    result= mysql_create_table_no_lock(session,
1532
1537
                                       identifier,
1533
1538
                                       create_info,
1534
1539
                                       table_proto,
1540
1545
 
1541
1546
  if (name_lock)
1542
1547
  {
1543
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* Lock for removing name_lock during table create */
 
1548
    pthread_mutex_lock(&LOCK_open); /* Lock for removing name_lock during table create */
1544
1549
    session->unlink_open_table(name_lock);
 
1550
    pthread_mutex_unlock(&LOCK_open);
1545
1551
  }
1546
1552
 
1547
1553
  return(result);
1549
1555
 
1550
1556
 
1551
1557
/*
1552
 
  Database locking aware wrapper for create_table_no_lock(),
 
1558
  Database locking aware wrapper for mysql_create_table_no_lock(),
1553
1559
*/
1554
 
bool create_table(Session *session,
1555
 
                        const identifier::Table &identifier,
 
1560
bool mysql_create_table(Session *session,
 
1561
                        TableIdentifier &identifier,
1556
1562
                        HA_CREATE_INFO *create_info,
1557
1563
                        message::Table &table_proto,
1558
1564
                        AlterInfo *alter_info,
1562
1568
{
1563
1569
  if (identifier.isTmp())
1564
1570
  {
1565
 
    return create_table_no_lock(session,
 
1571
    return mysql_create_table_no_lock(session,
1566
1572
                                      identifier,
1567
1573
                                      create_info,
1568
1574
                                      table_proto,
1632
1638
  Rename a table.
1633
1639
 
1634
1640
  SYNOPSIS
1635
 
    rename_table()
 
1641
    mysql_rename_table()
1636
1642
      session
1637
1643
      base                      The plugin::StorageEngine handle.
1638
1644
      old_db                    The old database name.
1646
1652
*/
1647
1653
 
1648
1654
bool
1649
 
rename_table(Session &session,
 
1655
mysql_rename_table(Session &session,
1650
1656
                   plugin::StorageEngine *base,
1651
 
                   const identifier::Table &from,
1652
 
                   const identifier::Table &to)
 
1657
                   TableIdentifier &from,
 
1658
                   TableIdentifier &to)
1653
1659
{
1654
1660
  int error= 0;
1655
1661
 
1669
1675
  }
1670
1676
  else if (error)
1671
1677
  {
1672
 
    std::string from_path;
1673
 
    std::string to_path;
1674
 
 
1675
 
    from.getSQLPath(from_path);
1676
 
    to.getSQLPath(to_path);
1677
 
 
1678
 
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from_path.c_str();
1679
 
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to_path.c_str();
 
1678
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from.getSQLPath().c_str();
 
1679
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to.getSQLPath().c_str();
1680
1680
 
1681
1681
    my_error(ER_ERROR_ON_RENAME, MYF(0), from_identifier, to_identifier, error);
1682
1682
  }
1700
1700
   the table is closed.
1701
1701
 
1702
1702
  PREREQUISITES
1703
 
    Lock on table::Cache::singleton().mutex()
 
1703
    Lock on LOCK_open
1704
1704
    Win32 clients must also have a WRITE LOCK on the table !
1705
1705
*/
1706
1706
 
1708
1708
                              enum ha_extra_function function)
1709
1709
{
1710
1710
 
1711
 
  safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
 
1711
  safe_mutex_assert_owner(&LOCK_open);
1712
1712
 
1713
1713
  table->cursor->extra(function);
1714
1714
  /* Mark all tables that are in use as 'old' */
1715
 
  session->abortLock(table);    /* end threads waiting on lock */
 
1715
  mysql_lock_abort(session, table);     /* end threads waiting on lock */
1716
1716
 
1717
1717
  /* Wait until all there are no other threads that has this table open */
1718
 
  identifier::Table identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName());
1719
 
  table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
 
1718
  TableIdentifier identifier(table->getMutableShare()->getSchemaName(), table->getMutableShare()->getTableName());
 
1719
  remove_table_from_cache(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
1720
1720
}
1721
1721
 
1722
1722
/*
1732
1732
    reopen the table.
1733
1733
 
1734
1734
  PREREQUISITES
1735
 
    Lock on table::Cache::singleton().mutex()
 
1735
    Lock on LOCK_open
1736
1736
    Win32 clients must also have a WRITE LOCK on the table !
1737
1737
*/
1738
1738
 
1743
1743
  /* Close lock if this is not got with LOCK TABLES */
1744
1744
  if (lock)
1745
1745
  {
1746
 
    unlockTables(lock);
 
1746
    mysql_unlock_tables(this, lock);
1747
1747
    lock= NULL;                 // Start locked threads
1748
1748
  }
1749
1749
  /* Close all copies of 'table'.  This also frees all LOCK TABLES lock */
1750
1750
  unlink_open_table(table);
1751
1751
 
1752
 
  /* When lock on table::Cache::singleton().mutex() is freed other threads can continue */
1753
 
  locking::broadcast_refresh();
 
1752
  /* When lock on LOCK_open is freed other threads can continue */
 
1753
  broadcast_refresh();
1754
1754
}
1755
1755
 
1756
1756
/*
1759
1759
    true  Message should be sent by caller
1760
1760
          (admin operation or network communication failed)
1761
1761
*/
1762
 
static bool admin_table(Session* session, TableList* tables,
 
1762
static bool mysql_admin_table(Session* session, TableList* tables,
1763
1763
                              HA_CHECK_OPT* check_opt,
1764
1764
                              const char *operator_name,
1765
1765
                              thr_lock_type lock_type,
1768
1768
                                                            HA_CHECK_OPT *))
1769
1769
{
1770
1770
  TableList *table;
1771
 
  Select_Lex *select= &session->getLex()->select_lex;
 
1771
  Select_Lex *select= &session->lex->select_lex;
1772
1772
  List<Item> field_list;
1773
1773
  Item *item;
 
1774
  LEX *lex= session->lex;
1774
1775
  int result_code= 0;
1775
1776
  TransactionServices &transaction_services= TransactionServices::singleton();
1776
1777
  const CHARSET_INFO * const cs= system_charset_info;
1777
1778
 
1778
1779
  if (! session->endActiveTransaction())
1779
1780
    return 1;
1780
 
 
1781
1781
  field_list.push_back(item = new Item_empty_string("Table",
1782
1782
                                                    NAME_CHAR_LEN * 2,
1783
1783
                                                    cs));
1788
1788
  item->maybe_null = 1;
1789
1789
  field_list.push_back(item = new Item_empty_string("Msg_text", 255, cs));
1790
1790
  item->maybe_null = 1;
1791
 
  if (session->getClient()->sendFields(&field_list))
 
1791
  if (session->client->sendFields(&field_list))
1792
1792
    return true;
1793
1793
 
1794
1794
  for (table= tables; table; table= table->next_local)
1795
1795
  {
1796
 
    identifier::Table table_identifier(table->getSchemaName(), table->getTableName());
1797
 
    std::string table_name;
 
1796
    char table_name[NAME_LEN*2+2];
 
1797
    char* db = table->db;
1798
1798
    bool fatal_error=0;
1799
1799
 
1800
 
    table_identifier.getSQLPath(table_name);
1801
 
 
 
1800
    snprintf(table_name, sizeof(table_name), "%s.%s",db,table->table_name);
1802
1801
    table->lock_type= lock_type;
1803
1802
    /* open only one table from local list of command */
1804
1803
    {
1811
1810
      /*
1812
1811
        Time zone tables and SP tables can be add to lex->query_tables list,
1813
1812
        so it have to be prepared.
1814
 
        @todo Investigate if we can put extra tables into argument instead of using lex->query_tables
 
1813
        TODO: Investigate if we can put extra tables into argument instead of
 
1814
        using lex->query_tables
1815
1815
      */
1816
 
      session->getLex()->query_tables= table;
1817
 
      session->getLex()->query_tables_last= &table->next_global;
1818
 
      session->getLex()->query_tables_own_last= 0;
 
1816
      lex->query_tables= table;
 
1817
      lex->query_tables_last= &table->next_global;
 
1818
      lex->query_tables_own_last= 0;
1819
1819
      session->no_warnings_for_error= 0;
1820
1820
 
1821
1821
      session->openTablesLock(table);
1845
1845
    {
1846
1846
      char buff[FN_REFLEN + DRIZZLE_ERRMSG_SIZE];
1847
1847
      uint32_t length;
1848
 
      session->getClient()->store(table_name.c_str());
1849
 
      session->getClient()->store(operator_name);
1850
 
      session->getClient()->store(STRING_WITH_LEN("error"));
 
1848
      session->client->store(table_name);
 
1849
      session->client->store(operator_name);
 
1850
      session->client->store(STRING_WITH_LEN("error"));
1851
1851
      length= snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
1852
 
                       table_name.c_str());
1853
 
      session->getClient()->store(buff, length);
1854
 
      transaction_services.autocommitOrRollback(*session, false);
 
1852
                       table_name);
 
1853
      session->client->store(buff, length);
 
1854
      transaction_services.autocommitOrRollback(session, false);
1855
1855
      session->endTransaction(COMMIT);
1856
1856
      session->close_thread_tables();
1857
 
      session->getLex()->reset_query_tables_list(false);
 
1857
      lex->reset_query_tables_list(false);
1858
1858
      table->table=0;                           // For query cache
1859
 
      if (session->getClient()->flush())
 
1859
      if (session->client->flush())
1860
1860
        goto err;
1861
1861
      continue;
1862
1862
    }
1864
1864
    /* Close all instances of the table to allow repair to rename files */
1865
1865
    if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
1866
1866
    {
1867
 
      table::Cache::singleton().mutex().lock(); /* Lock type is TL_WRITE and we lock to repair the table */
1868
 
      const char *old_message=session->enter_cond(COND_refresh, table::Cache::singleton().mutex(),
1869
 
                                                  "Waiting to get writelock");
1870
 
      session->abortLock(table->table);
1871
 
      identifier::Table identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1872
 
      table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG);
 
1867
      pthread_mutex_lock(&LOCK_open); /* Lock type is TL_WRITE and we lock to repair the table */
 
1868
      const char *old_message=session->enter_cond(&COND_refresh, &LOCK_open,
 
1869
                                              "Waiting to get writelock");
 
1870
      mysql_lock_abort(session,table->table);
 
1871
      TableIdentifier identifier(table->table->getMutableShare()->getSchemaName(), table->table->getMutableShare()->getTableName());
 
1872
      remove_table_from_cache(session, identifier,
 
1873
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
1874
                              RTFC_CHECK_KILLED_FLAG);
1873
1875
      session->exit_cond(old_message);
1874
 
      if (session->getKilled())
 
1876
      if (session->killed)
1875
1877
        goto err;
1876
1878
      open_for_modify= 0;
1877
1879
    }
1880
1882
 
1881
1883
send_result:
1882
1884
 
1883
 
    session->getLex()->cleanup_after_one_table_open();
 
1885
    lex->cleanup_after_one_table_open();
1884
1886
    session->clear_error();  // these errors shouldn't get client
1885
1887
    {
1886
 
      List<DRIZZLE_ERROR>::iterator it(session->warn_list.begin());
 
1888
      List_iterator_fast<DRIZZLE_ERROR> it(session->warn_list);
1887
1889
      DRIZZLE_ERROR *err;
1888
1890
      while ((err= it++))
1889
1891
      {
1890
 
        session->getClient()->store(table_name.c_str());
1891
 
        session->getClient()->store(operator_name);
1892
 
        session->getClient()->store(warning_level_names[err->level].str,
 
1892
        session->client->store(table_name);
 
1893
        session->client->store(operator_name);
 
1894
        session->client->store(warning_level_names[err->level].str,
1893
1895
                               warning_level_names[err->level].length);
1894
 
        session->getClient()->store(err->msg);
1895
 
        if (session->getClient()->flush())
 
1896
        session->client->store(err->msg);
 
1897
        if (session->client->flush())
1896
1898
          goto err;
1897
1899
      }
1898
1900
      drizzle_reset_errors(session, true);
1899
1901
    }
1900
 
    session->getClient()->store(table_name.c_str());
1901
 
    session->getClient()->store(operator_name);
 
1902
    session->client->store(table_name);
 
1903
    session->client->store(operator_name);
1902
1904
 
1903
1905
    switch (result_code) {
1904
1906
    case HA_ADMIN_NOT_IMPLEMENTED:
1906
1908
        char buf[ERRMSGSIZE+20];
1907
1909
        uint32_t length=snprintf(buf, ERRMSGSIZE,
1908
1910
                             ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
1909
 
        session->getClient()->store(STRING_WITH_LEN("note"));
1910
 
        session->getClient()->store(buf, length);
 
1911
        session->client->store(STRING_WITH_LEN("note"));
 
1912
        session->client->store(buf, length);
1911
1913
      }
1912
1914
      break;
1913
1915
 
1914
1916
    case HA_ADMIN_OK:
1915
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1916
 
      session->getClient()->store(STRING_WITH_LEN("OK"));
 
1917
      session->client->store(STRING_WITH_LEN("status"));
 
1918
      session->client->store(STRING_WITH_LEN("OK"));
1917
1919
      break;
1918
1920
 
1919
1921
    case HA_ADMIN_FAILED:
1920
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1921
 
      session->getClient()->store(STRING_WITH_LEN("Operation failed"));
 
1922
      session->client->store(STRING_WITH_LEN("status"));
 
1923
      session->client->store(STRING_WITH_LEN("Operation failed"));
1922
1924
      break;
1923
1925
 
1924
1926
    case HA_ADMIN_REJECT:
1925
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1926
 
      session->getClient()->store(STRING_WITH_LEN("Operation need committed state"));
 
1927
      session->client->store(STRING_WITH_LEN("status"));
 
1928
      session->client->store(STRING_WITH_LEN("Operation need committed state"));
1927
1929
      open_for_modify= false;
1928
1930
      break;
1929
1931
 
1930
1932
    case HA_ADMIN_ALREADY_DONE:
1931
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1932
 
      session->getClient()->store(STRING_WITH_LEN("Table is already up to date"));
 
1933
      session->client->store(STRING_WITH_LEN("status"));
 
1934
      session->client->store(STRING_WITH_LEN("Table is already up to date"));
1933
1935
      break;
1934
1936
 
1935
1937
    case HA_ADMIN_CORRUPT:
1936
 
      session->getClient()->store(STRING_WITH_LEN("error"));
1937
 
      session->getClient()->store(STRING_WITH_LEN("Corrupt"));
 
1938
      session->client->store(STRING_WITH_LEN("error"));
 
1939
      session->client->store(STRING_WITH_LEN("Corrupt"));
1938
1940
      fatal_error=1;
1939
1941
      break;
1940
1942
 
1941
1943
    case HA_ADMIN_INVALID:
1942
 
      session->getClient()->store(STRING_WITH_LEN("error"));
1943
 
      session->getClient()->store(STRING_WITH_LEN("Invalid argument"));
 
1944
      session->client->store(STRING_WITH_LEN("error"));
 
1945
      session->client->store(STRING_WITH_LEN("Invalid argument"));
1944
1946
      break;
1945
1947
 
1946
1948
    default:                            // Probably HA_ADMIN_INTERNAL_ERROR
1949
1951
        uint32_t length=snprintf(buf, ERRMSGSIZE,
1950
1952
                             _("Unknown - internal error %d during operation"),
1951
1953
                             result_code);
1952
 
        session->getClient()->store(STRING_WITH_LEN("error"));
1953
 
        session->getClient()->store(buf, length);
 
1954
        session->client->store(STRING_WITH_LEN("error"));
 
1955
        session->client->store(buf, length);
1954
1956
        fatal_error=1;
1955
1957
        break;
1956
1958
      }
1969
1971
        }
1970
1972
        else
1971
1973
        {
1972
 
          boost::unique_lock<boost::mutex> lock(table::Cache::singleton().mutex());
1973
 
          identifier::Table identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1974
 
          table::Cache::singleton().removeTable(session, identifier, RTFC_NO_FLAG);
 
1974
          pthread_mutex_lock(&LOCK_open);
 
1975
          TableIdentifier identifier(table->table->getMutableShare()->getSchemaName(), table->table->getMutableShare()->getTableName());
 
1976
          remove_table_from_cache(session, identifier, RTFC_NO_FLAG);
 
1977
          pthread_mutex_unlock(&LOCK_open);
1975
1978
        }
1976
1979
      }
1977
1980
    }
1978
 
    transaction_services.autocommitOrRollback(*session, false);
 
1981
    transaction_services.autocommitOrRollback(session, false);
1979
1982
    session->endTransaction(COMMIT);
1980
1983
    session->close_thread_tables();
1981
1984
    table->table=0;                             // For query cache
1982
 
    if (session->getClient()->flush())
 
1985
    if (session->client->flush())
1983
1986
      goto err;
1984
1987
  }
1985
1988
 
1987
1990
  return(false);
1988
1991
 
1989
1992
err:
1990
 
  transaction_services.autocommitOrRollback(*session, true);
 
1993
  transaction_services.autocommitOrRollback(session, true);
1991
1994
  session->endTransaction(ROLLBACK);
1992
1995
  session->close_thread_tables();                       // Shouldn't be needed
1993
1996
  if (table)
2001
2004
    Altough exclusive name-lock on target table protects us from concurrent
2002
2005
    DML and DDL operations on it we still want to wrap .FRM creation and call
2003
2006
    to plugin::StorageEngine::createTable() in critical section protected by
2004
 
    table::Cache::singleton().mutex() in order to provide minimal atomicity against operations which
 
2007
    LOCK_open in order to provide minimal atomicity against operations which
2005
2008
    disregard name-locks, like I_S implementation, for example. This is a
2006
2009
    temporary and should not be copied. Instead we should fix our code to
2007
2010
    always honor name-locks.
2008
2011
 
2009
 
    Also some engines (e.g. NDB cluster) require that table::Cache::singleton().mutex() should be held
 
2012
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
2010
2013
    during the call to plugin::StorageEngine::createTable().
2011
2014
    See bug #28614 for more info.
2012
2015
  */
2013
 
static bool create_table_wrapper(Session &session,
2014
 
                                 const message::Table& create_table_proto,
2015
 
                                 identifier::Table::const_reference destination_identifier,
2016
 
                                 identifier::Table::const_reference source_identifier,
 
2016
static bool create_table_wrapper(Session &session, const message::Table& create_table_proto,
 
2017
                                 TableIdentifier &destination_identifier,
 
2018
                                 TableIdentifier &src_table,
2017
2019
                                 bool is_engine_set)
2018
2020
{
2019
 
  // We require an additional table message because during parsing we used
2020
 
  // a "new" message and it will not have all of the information that the
2021
 
  // source table message would have.
2022
 
  message::Table new_table_message;
2023
 
 
2024
 
  message::table::shared_ptr source_table_message= plugin::StorageEngine::getTableMessage(session, source_identifier);
2025
 
 
2026
 
  if (not source_table_message)
2027
 
  {
2028
 
    my_error(ER_TABLE_UNKNOWN, source_identifier);
2029
 
    return false;
2030
 
  }
2031
 
 
2032
 
  new_table_message.CopyFrom(*source_table_message);
 
2021
  int protoerr= EEXIST;
 
2022
  message::Table new_proto;
 
2023
  message::Table src_proto;
 
2024
 
 
2025
  protoerr= plugin::StorageEngine::getTableDefinition(session,
 
2026
                                                      src_table,
 
2027
                                                      src_proto);
 
2028
  new_proto.CopyFrom(src_proto);
2033
2029
 
2034
2030
  if (destination_identifier.isTmp())
2035
2031
  {
2036
 
    new_table_message.set_type(message::Table::TEMPORARY);
 
2032
    new_proto.set_type(message::Table::TEMPORARY);
2037
2033
  }
2038
2034
  else
2039
2035
  {
2040
 
    new_table_message.set_type(message::Table::STANDARD);
 
2036
    new_proto.set_type(message::Table::STANDARD);
2041
2037
  }
2042
2038
 
2043
2039
  if (is_engine_set)
2044
2040
  {
2045
 
    new_table_message.mutable_engine()->set_name(create_table_proto.engine().name());
 
2041
    new_proto.mutable_engine()->set_name(create_table_proto.engine().name());
2046
2042
  }
2047
2043
 
2048
2044
  { // We now do a selective copy of elements on to the new table.
2049
 
    new_table_message.set_name(create_table_proto.name());
2050
 
    new_table_message.set_schema(create_table_proto.schema());
2051
 
    new_table_message.set_catalog(create_table_proto.catalog());
 
2045
    new_proto.set_name(create_table_proto.name());
 
2046
    new_proto.set_schema(create_table_proto.schema());
 
2047
    new_proto.set_catalog(create_table_proto.catalog());
2052
2048
  }
2053
2049
 
2054
 
  /* Fix names of foreign keys being added */
2055
 
  for (int32_t j= 0; j < new_table_message.fk_constraint_size(); j++)
 
2050
  if (protoerr && protoerr != EEXIST)
2056
2051
  {
2057
 
    if (new_table_message.fk_constraint(j).has_name())
2058
 
    {
2059
 
      std::string name(new_table_message.name());
2060
 
      char number[20];
2061
 
 
2062
 
      name.append("_ibfk_");
2063
 
      snprintf(number, sizeof(number), "%d", j+1);
2064
 
      name.append(number);
2065
 
 
2066
 
      message::Table::ForeignKeyConstraint *pfkey= new_table_message.mutable_fk_constraint(j);
2067
 
      pfkey->set_name(name);
2068
 
    }
 
2052
    if (errno == ENOENT)
 
2053
      my_error(ER_BAD_DB_ERROR,MYF(0), destination_identifier.getSchemaName().c_str());
 
2054
    else
 
2055
      my_error(ER_CANT_CREATE_FILE, MYF(0), destination_identifier.getPath().c_str(), errno);
 
2056
 
 
2057
    return false;
2069
2058
  }
2070
2059
 
2071
2060
  /*
2072
2061
    As mysql_truncate don't work on a new table at this stage of
2073
 
    creation, instead create the table directly (for both normal and temporary tables).
 
2062
    creation, instead create the table directly (for both normal
 
2063
    and temporary tables).
2074
2064
  */
2075
 
  bool success= plugin::StorageEngine::createTable(session,
2076
 
                                                   destination_identifier,
2077
 
                                                   new_table_message);
 
2065
  int err= plugin::StorageEngine::createTable(session,
 
2066
                                              destination_identifier,
 
2067
                                              new_proto);
2078
2068
 
2079
 
  if (success && not destination_identifier.isTmp())
 
2069
  if (err == false && not destination_identifier.isTmp())
2080
2070
  {
2081
2071
    TransactionServices &transaction_services= TransactionServices::singleton();
2082
 
    transaction_services.createTable(session, new_table_message);
 
2072
    transaction_services.createTable(&session, new_proto);
2083
2073
  }
2084
2074
 
2085
 
  return success;
 
2075
  return err ? false : true;
2086
2076
}
2087
2077
 
2088
2078
/*
2089
2079
  Create a table identical to the specified table
2090
2080
 
2091
2081
  SYNOPSIS
2092
 
    create_like_table()
 
2082
    mysql_create_like_table()
2093
2083
    session             Thread object
2094
2084
    table       Table list element for target table
2095
2085
    src_table   Table list element for source table
2100
2090
    true  error
2101
2091
*/
2102
2092
 
2103
 
bool create_like_table(Session* session,
2104
 
                       identifier::Table::const_reference destination_identifier,
2105
 
                       identifier::Table::const_reference source_identifier,
2106
 
                       message::Table &create_table_proto,
2107
 
                       bool is_if_not_exists,
2108
 
                       bool is_engine_set)
 
2093
bool mysql_create_like_table(Session* session,
 
2094
                             TableIdentifier &destination_identifier,
 
2095
                             TableList* table, TableList* src_table,
 
2096
                             message::Table &create_table_proto,
 
2097
                             bool is_if_not_exists,
 
2098
                             bool is_engine_set)
2109
2099
{
 
2100
  char *db= table->db;
 
2101
  char *table_name= table->table_name;
2110
2102
  bool res= true;
2111
 
  bool table_exists= false;
 
2103
  uint32_t not_used;
 
2104
 
 
2105
  /*
 
2106
    By opening source table we guarantee that it exists and no concurrent
 
2107
    DDL operation will mess with it. Later we also take an exclusive
 
2108
    name-lock on target table name, which makes copying of .frm cursor,
 
2109
    call to plugin::StorageEngine::createTable() and binlogging atomic
 
2110
    against concurrent DML and DDL operations on target table.
 
2111
    Thus by holding both these "locks" we ensure that our statement is
 
2112
    properly isolated from all concurrent operations which matter.
 
2113
  */
 
2114
  if (session->open_tables_from_list(&src_table, &not_used))
 
2115
    return true;
 
2116
 
 
2117
  TableIdentifier src_identifier(src_table->table->getMutableShare()->getSchemaName(),
 
2118
                                 src_table->table->getMutableShare()->getTableName(), src_table->table->getMutableShare()->getType());
 
2119
 
 
2120
 
2112
2121
 
2113
2122
  /*
2114
2123
    Check that destination tables does not exist. Note that its name
2116
2125
 
2117
2126
    For temporary tables we don't aim to grab locks.
2118
2127
  */
 
2128
  bool table_exists= false;
2119
2129
  if (destination_identifier.isTmp())
2120
2130
  {
2121
 
    if (session->find_temporary_table(destination_identifier))
 
2131
    if (session->find_temporary_table(db, table_name))
2122
2132
    {
2123
2133
      table_exists= true;
2124
2134
    }
2125
2135
    else
2126
2136
    {
2127
 
      bool was_created= create_table_wrapper(*session,
2128
 
                                             create_table_proto,
2129
 
                                             destination_identifier,
2130
 
                                             source_identifier,
2131
 
                                             is_engine_set);
 
2137
      bool was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
 
2138
                                             src_identifier, is_engine_set);
2132
2139
      if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2133
2140
      {
2134
2141
        (void) session->rm_temporary_table(destination_identifier, true);
2148
2155
  {
2149
2156
    Table *name_lock= 0;
2150
2157
 
2151
 
    if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
 
2158
    if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
2152
2159
    {
2153
2160
      if (name_lock)
2154
2161
      {
2155
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
 
2162
        pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2156
2163
        session->unlink_open_table(name_lock);
 
2164
        pthread_mutex_unlock(&LOCK_open);
2157
2165
      }
2158
2166
 
2159
2167
      return res;
2169
2177
    }
2170
2178
    else // Otherwise we create the table
2171
2179
    {
2172
 
      bool was_created;
2173
 
      {
2174
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
2175
 
        was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2176
 
                                          source_identifier, is_engine_set);
2177
 
      }
 
2180
      pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
 
2181
      bool was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
 
2182
                                             src_identifier, is_engine_set);
 
2183
      pthread_mutex_unlock(&LOCK_open);
2178
2184
 
2179
2185
      // So we blew the creation of the table, and we scramble to clean up
2180
2186
      // anything that might have been created (read... it is a hack)
2181
2187
      if (not was_created)
2182
2188
      {
2183
 
        plugin::StorageEngine::dropTable(*session, destination_identifier);
 
2189
        quick_rm_table(*session, destination_identifier);
2184
2190
      } 
2185
2191
      else
2186
2192
      {
2190
2196
 
2191
2197
    if (name_lock)
2192
2198
    {
2193
 
      boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
 
2199
      pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2194
2200
      session->unlink_open_table(name_lock);
 
2201
      pthread_mutex_unlock(&LOCK_open);
2195
2202
    }
2196
2203
  }
2197
2204
 
2201
2208
    {
2202
2209
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
2203
2210
      snprintf(warn_buff, sizeof(warn_buff),
2204
 
               ER(ER_TABLE_EXISTS_ERROR), destination_identifier.getTableName().c_str());
 
2211
               ER(ER_TABLE_EXISTS_ERROR), table_name);
2205
2212
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2206
 
                   ER_TABLE_EXISTS_ERROR, warn_buff);
2207
 
      return false;
2208
 
    }
2209
 
 
2210
 
    my_error(ER_TABLE_EXISTS_ERROR, destination_identifier);
2211
 
 
2212
 
    return true;
 
2213
                   ER_TABLE_EXISTS_ERROR,warn_buff);
 
2214
      res= false;
 
2215
    }
 
2216
    else
 
2217
    {
 
2218
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
2219
    }
2213
2220
  }
2214
2221
 
2215
 
  return res;
 
2222
  return(res);
2216
2223
}
2217
2224
 
2218
2225
 
2219
 
bool analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
 
2226
bool mysql_analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
2220
2227
{
2221
2228
  thr_lock_type lock_type = TL_READ_NO_INSERT;
2222
2229
 
2223
 
  return(admin_table(session, tables, check_opt,
 
2230
  return(mysql_admin_table(session, tables, check_opt,
2224
2231
                                "analyze", lock_type, true,
2225
2232
                                &Cursor::ha_analyze));
2226
2233
}
2227
2234
 
2228
2235
 
2229
 
bool check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
 
2236
bool mysql_check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
2230
2237
{
2231
2238
  thr_lock_type lock_type = TL_READ_NO_INSERT;
2232
2239
 
2233
 
  return(admin_table(session, tables, check_opt,
 
2240
  return(mysql_admin_table(session, tables, check_opt,
2234
2241
                                "check", lock_type,
2235
2242
                                false,
2236
2243
                                &Cursor::ha_check));