~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

  • Committer: Stewart Smith
  • Date: 2010-04-07 02:08:20 UTC
  • mto: (1283.38.1)
  • mto: This revision was merged to the branch mainline in revision 1536.
  • Revision ID: stewart@flamingspork.com-20100407020820-4elzp2uuorw5vv89
add basic_create_select test that currently causes a crash due to https://bugs.launchpad.net/drizzle/+bug/556978

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
 
#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>
 
39
#include <drizzled/table_identifier.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>
53
51
 
54
 
#include <boost/unordered_set.hpp>
55
 
 
56
52
using namespace std;
57
53
 
58
54
namespace drizzled
59
55
{
60
56
 
61
 
bool is_primary_key(KeyInfo *key_info)
 
57
extern plugin::StorageEngine *myisam_engine;
 
58
extern pid_t current_pid;
 
59
 
 
60
bool is_primary_key(KEY *key_info)
62
61
{
63
62
  static const char * primary_key_name="PRIMARY";
64
63
  return (strcmp(key_info->name, primary_key_name)==0);
73
72
    return NULL;
74
73
}
75
74
 
76
 
static bool check_if_keyname_exists(const char *name,KeyInfo *start, KeyInfo *end);
77
 
static char *make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end);
 
75
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
 
76
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
78
77
 
79
78
static bool prepare_blob_field(Session *session, CreateField *sql_field);
80
79
 
85
84
    let's fetch the database default character set and
86
85
    apply it to the table.
87
86
  */
88
 
  identifier::Schema identifier(db);
 
87
  SchemaIdentifier identifier(db);
89
88
  if (create_info->default_table_charset == NULL)
90
89
    create_info->default_table_charset= plugin::StorageEngine::getSchemaCollation(identifier);
91
90
}
105
104
    cursor
106
105
*/
107
106
 
108
 
void write_bin_log(Session *session, const std::string &query)
109
 
{
110
 
  TransactionServices &transaction_services= TransactionServices::singleton();
111
 
  transaction_services.rawStatement(*session, query);
 
107
void write_bin_log(Session *session,
 
108
                   char const *query)
 
109
{
 
110
  TransactionServices &transaction_services= TransactionServices::singleton();
 
111
  transaction_services.rawStatement(session, query);
 
112
}
 
113
 
 
114
 
 
115
/* Should should be refactored to go away */
 
116
void write_bin_log_drop_table(Session *session, bool if_exists, const char *db_name, const char *table_name)
 
117
{
 
118
  TransactionServices &transaction_services= TransactionServices::singleton();
 
119
  string built_query;
 
120
 
 
121
  if (if_exists)
 
122
    built_query.append("DROP TABLE IF EXISTS ");
 
123
  else
 
124
    built_query.append("DROP TABLE ");
 
125
 
 
126
  built_query.append("`");
 
127
  if (session->db.empty() || strcmp(db_name, session->db.c_str()) != 0)
 
128
  {
 
129
    built_query.append(db_name);
 
130
    built_query.append("`.`");
 
131
  }
 
132
 
 
133
  built_query.append(table_name);
 
134
  built_query.append("`");
 
135
  transaction_services.rawStatement(session, built_query);
112
136
}
113
137
 
114
138
/*
115
139
  Execute the drop of a normal or temporary table
116
140
 
117
141
  SYNOPSIS
118
 
    rm_table_part2()
 
142
    mysql_rm_table_part2()
119
143
    session                     Thread Cursor
120
144
    tables              Tables to drop
121
145
    if_exists           If set, don't give an error if table doesn't exists.
122
146
                        In this case we give an warning of level 'NOTE'
123
147
    drop_temporary      Only drop temporary tables
124
148
 
125
 
  @todo
 
149
  TODO:
126
150
    When logging to the binary log, we should log
127
151
    tmp_tables and transactional tables as separate statements if we
128
152
    are in a transaction;  This is needed to get these tables into the
138
162
   -1   Thread was killed
139
163
*/
140
164
 
141
 
int rm_table_part2(Session *session, TableList *tables, bool if_exists,
142
 
                   bool drop_temporary)
 
165
int mysql_rm_table_part2(Session *session, TableList *tables, bool if_exists,
 
166
                         bool drop_temporary)
143
167
{
144
168
  TableList *table;
145
 
  util::string::vector wrong_tables;
 
169
  String wrong_tables;
146
170
  int error= 0;
147
171
  bool foreign_key_error= false;
148
172
 
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:
 
173
  pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
 
174
 
 
175
  /*
 
176
    If we have the table in the definition cache, we don't have to check the
 
177
    .frm cursor to find if the table is a normal table (not view) and what
 
178
    engine to use.
 
179
  */
 
180
 
 
181
  for (table= tables; table; table= table->next_local)
 
182
  {
 
183
    TableIdentifier identifier(table->db, table->table_name);
 
184
    TableShare *share;
 
185
    table->db_type= NULL;
 
186
 
 
187
    if ((share= TableShare::getShare(identifier)))
 
188
    {
 
189
      table->db_type= share->db_type();
 
190
    }
 
191
  }
 
192
 
 
193
  if (not drop_temporary && lock_table_names_exclusively(session, tables))
 
194
  {
 
195
    pthread_mutex_unlock(&LOCK_open);
 
196
    return 1;
 
197
  }
 
198
 
 
199
  /* Don't give warnings for not found errors, as we already generate notes */
 
200
  session->no_warnings_for_error= 1;
 
201
 
 
202
  for (table= tables; table; table= table->next_local)
 
203
  {
 
204
    char *db=table->db;
 
205
 
 
206
    error= session->drop_temporary_table(table);
 
207
 
 
208
    switch (error) {
 
209
    case  0:
 
210
      // removed temporary table
 
211
      continue;
 
212
    case -1:
 
213
      error= 1;
 
214
      goto err_with_placeholders;
 
215
    default:
 
216
      // temporary table not found
 
217
      error= 0;
 
218
    }
 
219
 
 
220
    if (drop_temporary == false)
 
221
    {
 
222
      Table *locked_table;
 
223
      abort_locked_tables(session, db, table->table_name);
 
224
      remove_table_from_cache(session, db, table->table_name,
 
225
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
226
                              RTFC_CHECK_KILLED_FLAG);
 
227
      /*
 
228
        If the table was used in lock tables, remember it so that
 
229
        unlock_table_names can free it
 
230
      */
 
231
      if ((locked_table= drop_locked_tables(session, db, table->table_name)))
 
232
        table->table= locked_table;
 
233
 
 
234
      if (session->killed)
 
235
      {
 
236
        error= -1;
 
237
        goto err_with_placeholders;
 
238
      }
 
239
    }
 
240
    TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? message::Table::INTERNAL : message::Table::STANDARD);
 
241
 
 
242
    if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
 
243
    {
 
244
      // Table was not found on disk and table can't be created from engine
 
245
      if (if_exists)
 
246
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
247
                            ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 
248
                            table->table_name);
 
249
      else
172
250
        error= 1;
173
 
        break;
174
 
      default:
175
 
        // temporary table not found
 
251
    }
 
252
    else
 
253
    {
 
254
      error= plugin::StorageEngine::dropTable(*session, identifier);
 
255
 
 
256
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
 
257
      {
176
258
        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())
 
259
        session->clear_error();
 
260
      }
 
261
 
 
262
      if (error == HA_ERR_ROW_IS_REFERENCED)
 
263
      {
 
264
        /* the table is referenced by a foreign key constraint */
 
265
        foreign_key_error= true;
 
266
      }
 
267
    }
 
268
 
 
269
    if (error == 0 || (if_exists && foreign_key_error == false))
 
270
    {
 
271
      TransactionServices &transaction_services= TransactionServices::singleton();
 
272
      transaction_services.dropTable(session, string(db), string(table->table_name), if_exists);
 
273
    }
 
274
 
 
275
    if (error)
 
276
    {
 
277
      if (wrong_tables.length())
 
278
        wrong_tables.append(',');
 
279
      wrong_tables.append(String(table->table_name,system_charset_info));
 
280
    }
 
281
  }
 
282
  /*
 
283
    It's safe to unlock LOCK_open: we have an exclusive lock
 
284
    on the table name.
 
285
  */
 
286
  pthread_mutex_unlock(&LOCK_open);
 
287
  error= 0;
 
288
 
 
289
  if (wrong_tables.length())
258
290
  {
259
291
    if (not foreign_key_error)
260
292
    {
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
293
      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
273
 
                      table_error.c_str());
 
294
                      wrong_tables.c_ptr());
274
295
    }
275
296
    else
276
297
    {
279
300
    error= 1;
280
301
  }
281
302
 
 
303
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
 
304
 
 
305
err_with_placeholders:
 
306
  unlock_table_names(tables, NULL);
 
307
  pthread_mutex_unlock(&LOCK_open);
282
308
  session->no_warnings_for_error= 0;
283
309
 
284
310
  return error;
285
311
}
286
312
 
 
313
 
 
314
/*
 
315
  Quickly remove a table.
 
316
 
 
317
  SYNOPSIS
 
318
    quick_rm_table()
 
319
      base                      The plugin::StorageEngine handle.
 
320
      db                        The database name.
 
321
      table_name                The table name.
 
322
      is_tmp                    If the table is temp.
 
323
 
 
324
  RETURN
 
325
    0           OK
 
326
    != 0        Error
 
327
*/
 
328
bool quick_rm_table(Session& session,
 
329
                    TableIdentifier &identifier)
 
330
{
 
331
  return (plugin::StorageEngine::dropTable(session, identifier));
 
332
}
 
333
 
287
334
/*
288
335
  Sort keys in the following order:
289
336
  - PRIMARY KEY
297
344
  PRIMARY keys are prioritized.
298
345
*/
299
346
 
300
 
static int sort_keys(KeyInfo *a, KeyInfo *b)
 
347
static int sort_keys(KEY *a, KEY *b)
301
348
{
302
349
  ulong a_flags= a->flags, b_flags= b->flags;
303
350
 
349
396
    1             Error
350
397
*/
351
398
 
352
 
class typelib_set_member
353
 
{
354
 
public:
355
 
  string s;
356
 
  const CHARSET_INFO * const cs;
357
 
 
358
 
  typelib_set_member(const char* value, unsigned int length,
359
 
                     const CHARSET_INFO * const charset)
360
 
    : s(value, length),
361
 
      cs(charset)
362
 
  {}
363
 
};
364
 
 
365
 
static bool operator==(typelib_set_member const& a, typelib_set_member const& b)
366
 
{
367
 
  return (my_strnncoll(a.cs,
368
 
                       (const unsigned char*)a.s.c_str(), a.s.length(),
369
 
                       (const unsigned char*)b.s.c_str(), b.s.length())==0);
370
 
}
371
 
 
372
 
 
373
 
namespace
374
 
{
375
 
class typelib_set_member_hasher
376
 
{
377
 
  boost::hash<string> hasher;
378
 
public:
379
 
  std::size_t operator()(const typelib_set_member& t) const
380
 
  {
381
 
    return hasher(t.s);
382
 
  }
383
 
};
384
 
}
385
 
 
386
399
static bool check_duplicates_in_interval(const char *set_or_name,
387
400
                                         const char *name, TYPELIB *typelib,
388
401
                                         const CHARSET_INFO * const cs,
393
406
  unsigned int *cur_length= typelib->type_lengths;
394
407
  *dup_val_count= 0;
395
408
 
396
 
  boost::unordered_set<typelib_set_member, typelib_set_member_hasher> interval_set;
397
 
 
398
 
  for ( ; tmp.count > 0; cur_value++, cur_length++)
 
409
  for ( ; tmp.count > 1; cur_value++, cur_length++)
399
410
  {
400
411
    tmp.type_names++;
401
412
    tmp.type_lengths++;
402
413
    tmp.count--;
403
 
    if (interval_set.find(typelib_set_member(*cur_value, *cur_length, cs)) != interval_set.end())
 
414
    if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
404
415
    {
405
416
      my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
406
417
               name,*cur_value,set_or_name);
407
418
      return 1;
408
419
    }
409
 
    else
410
 
      interval_set.insert(typelib_set_member(*cur_value, *cur_length, cs));
411
420
  }
412
421
  return 0;
413
422
}
480
489
 
481
490
  switch (sql_field->sql_type) {
482
491
  case DRIZZLE_TYPE_BLOB:
 
492
    sql_field->pack_flag= pack_length_to_packflag(sql_field->pack_length - portable_sizeof_char_ptr);
483
493
    sql_field->length= 8; // Unireg field length
484
494
    (*blob_columns)++;
485
495
    break;
486
 
 
 
496
  case DRIZZLE_TYPE_VARCHAR:
 
497
    sql_field->pack_flag=0;
 
498
    break;
487
499
  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:
 
500
    sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length);
 
501
    if (check_duplicates_in_interval("ENUM",
 
502
                                     sql_field->field_name,
 
503
                                     sql_field->interval,
 
504
                                     sql_field->charset,
 
505
                                     &dup_val_count))
 
506
      return 1;
 
507
    break;
 
508
  case DRIZZLE_TYPE_DATE:  // Rest of string types
 
509
  case DRIZZLE_TYPE_DATETIME:
 
510
  case DRIZZLE_TYPE_NULL:
 
511
    sql_field->pack_flag=f_settype((uint32_t) sql_field->sql_type);
 
512
    break;
 
513
  case DRIZZLE_TYPE_DECIMAL:
 
514
    sql_field->pack_flag= 0;
 
515
    break;
501
516
  case DRIZZLE_TYPE_TIMESTAMP:
502
517
    /* We should replace old TIMESTAMP fields with their newer analogs */
503
518
    if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
508
523
        (*timestamps_with_niladic)++;
509
524
      }
510
525
      else
511
 
      {
512
526
        sql_field->unireg_check= Field::NONE;
513
 
      }
514
527
    }
515
528
    else if (sql_field->unireg_check != Field::NONE)
516
 
    {
517
529
      (*timestamps_with_niladic)++;
518
 
    }
519
530
 
520
531
    (*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:
 
532
    /* fall-through */
 
533
  default:
 
534
    sql_field->pack_flag=(0 |
 
535
                          f_settype((uint32_t) sql_field->sql_type));
535
536
    break;
536
537
  }
537
 
 
538
538
  return 0;
539
539
}
540
540
 
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)
 
541
static int mysql_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
                                      KEY **key_info_buffer,
 
548
                                      uint32_t *key_count,
 
549
                                      int select_field_count)
550
550
{
551
551
  const char    *key_name;
552
552
  CreateField   *sql_field,*dup_field;
553
553
  uint          field,null_fields,blob_columns,max_key_length;
554
554
  ulong         record_offset= 0;
555
 
  KeyInfo               *key_info;
556
 
  KeyPartInfo *key_part_info;
 
555
  KEY           *key_info;
 
556
  KEY_PART_INFO *key_part_info;
557
557
  int           timestamps= 0, timestamps_with_niladic= 0;
558
 
  int           dup_no;
 
558
  int           field_no,dup_no;
559
559
  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());
 
560
  List_iterator<CreateField> it(alter_info->create_list);
 
561
  List_iterator<CreateField> it2(alter_info->create_list);
562
562
  uint32_t total_uneven_bit_length= 0;
563
563
 
564
564
  plugin::StorageEngine *engine= plugin::StorageEngine::findByName(create_proto.engine().name());
567
567
  null_fields=blob_columns=0;
568
568
  max_key_length= engine->max_key_length();
569
569
 
570
 
  for (int32_t field_no=0; (sql_field=it++) ; field_no++)
 
570
  for (field_no=0; (sql_field=it++) ; field_no++)
571
571
  {
572
572
    const CHARSET_INFO *save_cs;
573
573
 
577
577
      executing a prepared statement for the second time.
578
578
    */
579
579
    sql_field->length= sql_field->char_length;
580
 
 
581
580
    if (!sql_field->charset)
582
581
      sql_field->charset= create_info->default_table_charset;
583
 
 
584
582
    /*
585
583
      table_charset is set in ALTER Table if we want change character set
586
584
      for all varchar/char columns.
633
631
 
634
632
    if (sql_field->sql_type == DRIZZLE_TYPE_ENUM)
635
633
    {
636
 
      size_t dummy;
 
634
      uint32_t dummy;
637
635
      const CHARSET_INFO * const cs= sql_field->charset;
638
636
      TYPELIB *interval= sql_field->interval;
639
637
 
652
650
        interval= sql_field->interval= typelib(session->mem_root,
653
651
                                               sql_field->interval_list);
654
652
 
655
 
        List<String>::iterator int_it(sql_field->interval_list.begin());
 
653
        List_iterator<String> int_it(sql_field->interval_list);
656
654
        String conv, *tmp;
657
655
        char comma_buf[4];
658
656
        int comma_length= cs->cset->wc_mb(cs, ',', (unsigned char*) comma_buf,
666
664
          if (String::needs_conversion(tmp->length(), tmp->charset(),
667
665
                                       cs, &dummy))
668
666
          {
669
 
            size_t cnv_errs;
 
667
            uint32_t cnv_errs;
670
668
            conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
671
 
            interval->type_names[i]= session->mem_root->strmake_root(conv.ptr(), conv.length());
 
669
            interval->type_names[i]= strmake_root(session->mem_root, conv.ptr(),
 
670
                                                  conv.length());
672
671
            interval->type_lengths[i]= conv.length();
673
672
          }
674
673
 
678
677
          interval->type_lengths[i]= lengthsp;
679
678
          ((unsigned char *)interval->type_names[i])[lengthsp]= '\0';
680
679
        }
681
 
        sql_field->interval_list.clear(); // Don't need interval_list anymore
 
680
        sql_field->interval_list.empty(); // Don't need interval_list anymore
682
681
      }
683
682
 
684
683
      /* DRIZZLE_TYPE_ENUM */
701
700
          else /* not NULL */
702
701
          {
703
702
            def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
704
 
            if (interval->find_type2(def->ptr(), def->length(), cs) == 0) /* not found */
 
703
            if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
705
704
            {
706
705
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
707
706
              return(true);
708
707
            }
709
708
          }
710
709
        }
711
 
        uint32_t new_dummy;
712
 
        calculate_interval_lengths(cs, interval, &field_length, &new_dummy);
 
710
        calculate_interval_lengths(cs, interval, &field_length, &dummy);
713
711
        sql_field->length= field_length;
714
712
      }
715
713
      set_if_smaller(sql_field->length, (uint32_t)MAX_FIELD_WIDTH-1);
777
775
    /** @todo Get rid of this MyISAM-specific crap. */
778
776
    if (not create_proto.engine().name().compare("MyISAM") &&
779
777
        ((sql_field->flags & BLOB_FLAG) ||
780
 
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
781
 
    {
 
778
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED)))
782
779
      (*db_options)|= HA_OPTION_PACK_RECORD;
783
 
    }
784
 
 
785
 
    it2= alter_info->create_list.begin();
 
780
    it2.rewind();
786
781
  }
787
782
 
788
783
  /* record_offset will be increased with 'length-of-null-bits' later */
789
784
  record_offset= 0;
790
785
  null_fields+= total_uneven_bit_length;
791
786
 
792
 
  it= alter_info->create_list.begin();
 
787
  it.rewind();
793
788
  while ((sql_field=it++))
794
789
  {
795
790
    assert(sql_field->charset != 0);
829
824
 
830
825
  /* Create keys */
831
826
 
832
 
  List<Key>::iterator key_iterator(alter_info->key_list.begin());
833
 
  List<Key>::iterator key_iterator2(alter_info->key_list.begin());
 
827
  List_iterator<Key> key_iterator(alter_info->key_list);
 
828
  List_iterator<Key> key_iterator2(alter_info->key_list);
834
829
  uint32_t key_parts=0, fk_key_count=0;
835
830
  bool primary_key=0,unique_key=0;
836
831
  Key *key, *key2;
848
843
      fk_key_count++;
849
844
      if (((Foreign_key *)key)->validate(alter_info->create_list))
850
845
        return true;
851
 
 
852
846
      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
847
      if (fk_key->ref_columns.elements &&
864
848
          fk_key->ref_columns.elements != fk_key->columns.elements)
865
849
      {
880
864
    }
881
865
    if (check_identifier_name(&key->name, ER_TOO_LONG_IDENT))
882
866
      return(true);
883
 
    key_iterator2= alter_info->key_list.begin();
 
867
    key_iterator2.rewind ();
884
868
    if (key->type != Key::FOREIGN_KEY)
885
869
    {
886
870
      while ((key2 = key_iterator2++) != key)
894
878
             key2->name.str != ignore_key &&
895
879
             !foreign_key_prefix(key, key2)))
896
880
        {
897
 
          /* @todo issue warning message */
 
881
          /* TODO: issue warning message */
898
882
          /* mark that the generated key should be ignored */
899
883
          if (!key2->generated ||
900
884
              (key->generated && key->columns.elements <
928
912
    return(true);
929
913
  }
930
914
 
931
 
  (*key_info_buffer)= key_info= (KeyInfo*) memory::sql_calloc(sizeof(KeyInfo) * (*key_count));
932
 
  key_part_info=(KeyPartInfo*) memory::sql_calloc(sizeof(KeyPartInfo)*key_parts);
 
915
  (*key_info_buffer)= key_info= (KEY*) memory::sql_calloc(sizeof(KEY) * (*key_count));
 
916
  key_part_info=(KEY_PART_INFO*) memory::sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
933
917
  if (!*key_info_buffer || ! key_part_info)
934
918
    return(true);                               // Out of memory
935
919
 
936
 
  key_iterator= alter_info->key_list.begin();
 
920
  key_iterator.rewind();
937
921
  key_number=0;
938
922
  for (; (key=key_iterator++) ; key_number++)
939
923
  {
969
953
    key_info->usable_key_parts= key_number;
970
954
    key_info->algorithm= key->key_create_info.algorithm;
971
955
 
 
956
    /* Take block size from key part or table part */
 
957
    /*
 
958
      TODO: Add warning if block size changes. We can't do it here, as
 
959
      this may depend on the size of the key
 
960
    */
 
961
    key_info->block_size= (key->key_create_info.block_size ?
 
962
                           key->key_create_info.block_size :
 
963
                           create_proto.options().key_block_size());
 
964
 
 
965
    if (key_info->block_size)
 
966
      key_info->flags|= HA_USES_BLOCK_SIZE;
 
967
 
972
968
    uint32_t tmp_len= system_charset_info->cset->charpos(system_charset_info,
973
969
                                           key->key_create_info.comment.str,
974
970
                                           key->key_create_info.comment.str +
992
988
 
993
989
    message::Table::Field *protofield= NULL;
994
990
 
995
 
    List<Key_part_spec>::iterator cols(key->columns.begin());
996
 
    List<Key_part_spec>::iterator cols2(key->columns.begin());
 
991
    List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
997
992
    for (uint32_t column_nr=0 ; (column=cols++) ; column_nr++)
998
993
    {
999
994
      uint32_t length;
1000
995
      Key_part_spec *dup_column;
1001
996
      int proto_field_nr= 0;
1002
997
 
1003
 
      it= alter_info->create_list.begin();
 
998
      it.rewind();
1004
999
      field=0;
1005
1000
      while ((sql_field=it++) && ++proto_field_nr &&
1006
1001
             my_strcasecmp(system_charset_info,
1007
1002
                           column->field_name.str,
1008
1003
                           sql_field->field_name))
1009
 
      {
1010
1004
        field++;
1011
 
      }
1012
 
 
1013
1005
      if (!sql_field)
1014
1006
      {
1015
1007
        my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
1016
1008
        return(true);
1017
1009
      }
1018
 
 
1019
1010
      while ((dup_column= cols2++) != column)
1020
1011
      {
1021
1012
        if (!my_strcasecmp(system_charset_info,
1027
1018
          return(true);
1028
1019
        }
1029
1020
      }
1030
 
      cols2= key->columns.begin();
 
1021
      cols2.rewind();
1031
1022
 
1032
1023
      if (create_proto.field_size() > 0)
1033
1024
        protofield= create_proto.mutable_field(proto_field_nr - 1);
1048
1039
            return true;
1049
1040
          }
1050
1041
        }
1051
 
 
1052
1042
        if (! (sql_field->flags & NOT_NULL_FLAG))
1053
1043
        {
1054
1044
          if (key->type == Key::PRIMARY)
1061
1051
            {
1062
1052
              message::Table::Field::FieldConstraints *constraints;
1063
1053
              constraints= protofield->mutable_constraints();
1064
 
              constraints->set_is_notnull(true);
 
1054
              constraints->set_is_nullable(false);
1065
1055
            }
1066
1056
 
1067
1057
          }
1075
1065
            }
1076
1066
          }
1077
1067
        }
1078
 
 
1079
1068
        if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
1080
1069
        {
1081
1070
          if (column_nr == 0 || (engine->check_flag(HTON_BIT_AUTO_PART_KEY)))
1085
1074
 
1086
1075
      key_part_info->fieldnr= field;
1087
1076
      key_part_info->offset=  (uint16_t) sql_field->offset;
1088
 
      key_part_info->key_type= 0;
 
1077
      key_part_info->key_type=sql_field->pack_flag;
1089
1078
      length= sql_field->key_length;
1090
1079
 
1091
1080
      if (column->length)
1153
1142
      key_part_info->length=(uint16_t) length;
1154
1143
      /* Use packed keys for long strings on the first column */
1155
1144
      if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
1156
 
          (length >= KEY_DEFAULT_PACK_LENGTH &&
1157
 
           (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
1158
 
            sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
 
1145
          (length >= KEY_DEFAULT_PACK_LENGTH &&
 
1146
           (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
 
1147
      sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
1159
1148
      {
1160
1149
        if ((column_nr == 0 && sql_field->sql_type == DRIZZLE_TYPE_BLOB) ||
1161
1150
            sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)
1162
 
        {
1163
1151
          key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
1164
 
        }
1165
1152
        else
1166
 
        {
1167
1153
          key_info->flags|= HA_PACK_KEY;
1168
 
        }
1169
1154
      }
1170
1155
      /* Check if the key segment is partial, set the key flag accordingly */
1171
1156
      if (length != sql_field->key_length)
1200
1185
        key_info->name=(char*) key_name;
1201
1186
      }
1202
1187
    }
1203
 
 
1204
1188
    if (!key_info->name || check_column_name(key_info->name))
1205
1189
    {
1206
1190
      my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
1207
1191
      return(true);
1208
1192
    }
1209
 
 
1210
1193
    if (!(key_info->flags & HA_NULL_PART_KEY))
1211
 
    {
1212
1194
      unique_key=1;
1213
 
    }
1214
 
 
1215
1195
    key_info->key_length=(uint16_t) key_length;
1216
 
 
1217
1196
    if (key_length > max_key_length)
1218
1197
    {
1219
1198
      my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
1220
1199
      return(true);
1221
1200
    }
1222
 
 
1223
1201
    key_info++;
1224
1202
  }
1225
 
 
1226
1203
  if (!unique_key && !primary_key &&
1227
1204
      (engine->check_flag(HTON_BIT_REQUIRE_PRIMARY_KEY)))
1228
1205
  {
1229
1206
    my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
1230
1207
    return(true);
1231
1208
  }
1232
 
 
1233
1209
  if (auto_increment > 0)
1234
1210
  {
1235
1211
    my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
1236
1212
    return(true);
1237
1213
  }
1238
1214
  /* Sort keys in optimized order */
1239
 
  internal::my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KeyInfo),
 
1215
  internal::my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KEY),
1240
1216
                     (qsort_cmp) sort_keys);
1241
1217
 
1242
1218
  /* Check fields. */
1243
 
  it= alter_info->create_list.begin();
 
1219
  it.rewind();
1244
1220
  while ((sql_field=it++))
1245
1221
  {
1246
1222
    Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
1247
1223
 
1248
1224
    if (session->variables.sql_mode & MODE_NO_ZERO_DATE &&
1249
1225
        !sql_field->def &&
1250
 
        (sql_field->sql_type == DRIZZLE_TYPE_TIMESTAMP  or sql_field->sql_type == DRIZZLE_TYPE_MICROTIME) &&
 
1226
        sql_field->sql_type == DRIZZLE_TYPE_TIMESTAMP &&
1251
1227
        (sql_field->flags & NOT_NULL_FLAG) &&
1252
1228
        (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
1253
1229
    {
1311
1287
}
1312
1288
 
1313
1289
static bool locked_create_event(Session *session,
1314
 
                                const identifier::Table &identifier,
 
1290
                                TableIdentifier &identifier,
1315
1291
                                HA_CREATE_INFO *create_info,
1316
1292
                                message::Table &table_proto,
1317
1293
                                AlterInfo *alter_info,
1319
1295
                                bool internal_tmp_table,
1320
1296
                                uint db_options,
1321
1297
                                uint key_count,
1322
 
                                KeyInfo *key_info_buffer)
 
1298
                                KEY *key_info_buffer)
1323
1299
{
1324
1300
  bool error= true;
1325
1301
 
1346
1322
        return error;
1347
1323
      }
1348
1324
 
1349
 
      my_error(ER_TABLE_EXISTS_ERROR, identifier);
1350
 
 
 
1325
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1351
1326
      return error;
1352
1327
    }
1353
1328
 
1364
1339
      /*
1365
1340
        @todo improve this error condition.
1366
1341
      */
1367
 
      if (definition::Cache::singleton().find(identifier.getKey()))
 
1342
      if (TableShare::getShare(identifier))
1368
1343
      {
1369
 
        my_error(ER_TABLE_EXISTS_ERROR, identifier);
1370
 
 
 
1344
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1371
1345
        return error;
1372
1346
      }
1373
1347
    }
1405
1379
  if (table_proto.type() == message::Table::STANDARD && not internal_tmp_table)
1406
1380
  {
1407
1381
    TransactionServices &transaction_services= TransactionServices::singleton();
1408
 
    transaction_services.createTable(*session, table_proto);
 
1382
    transaction_services.createTable(session, table_proto);
1409
1383
  }
1410
1384
 
1411
1385
  return false;
1418
1392
  Create a table
1419
1393
 
1420
1394
  SYNOPSIS
1421
 
    create_table_no_lock()
 
1395
    mysql_create_table_no_lock()
1422
1396
    session                     Thread object
1423
1397
    db                  Database
1424
1398
    table_name          Table name
1434
1408
 
1435
1409
    Note that this function assumes that caller already have taken
1436
1410
    name-lock on table being created or used some other way to ensure
1437
 
    that concurrent operations won't intervene. create_table()
 
1411
    that concurrent operations won't intervene. mysql_create_table()
1438
1412
    is a wrapper that can be used for this.
1439
1413
 
1440
1414
  RETURN VALUES
1442
1416
    true  error
1443
1417
*/
1444
1418
 
1445
 
bool create_table_no_lock(Session *session,
1446
 
                                const identifier::Table &identifier,
 
1419
bool mysql_create_table_no_lock(Session *session,
 
1420
                                TableIdentifier &identifier,
1447
1421
                                HA_CREATE_INFO *create_info,
1448
1422
                                message::Table &table_proto,
1449
1423
                                AlterInfo *alter_info,
1452
1426
                                bool is_if_not_exists)
1453
1427
{
1454
1428
  uint          db_options, key_count;
1455
 
  KeyInfo               *key_info_buffer;
 
1429
  KEY           *key_info_buffer;
1456
1430
  bool          error= true;
 
1431
  TableShare share;
1457
1432
 
1458
1433
  /* Check for duplicate fields and check type of table to create */
1459
1434
  if (not alter_info->create_list.elements)
1465
1440
  assert(identifier.getTableName() == table_proto.name());
1466
1441
  db_options= create_info->table_options;
1467
1442
 
 
1443
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
 
1444
    db_options|=HA_OPTION_PACK_RECORD;
 
1445
 
1468
1446
  set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1469
1447
 
1470
1448
  /* 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))
 
1449
  if (not mysql_prepare_create_table(session, create_info, table_proto, alter_info,
 
1450
                                 internal_tmp_table,
 
1451
                                 &db_options,
 
1452
                                 &key_info_buffer, &key_count,
 
1453
                                 select_field_count))
1476
1454
  {
1477
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* CREATE TABLE (some confussion on naming, double check) */
 
1455
    pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1478
1456
    error= locked_create_event(session,
1479
1457
                               identifier,
1480
1458
                               create_info,
1484
1462
                               internal_tmp_table,
1485
1463
                               db_options, key_count,
1486
1464
                               key_info_buffer);
 
1465
    pthread_mutex_unlock(&LOCK_open);
1487
1466
  }
1488
1467
 
1489
1468
  session->set_proc_info("After create");
1495
1474
  @note the following two methods implement create [temporary] table.
1496
1475
*/
1497
1476
static bool drizzle_create_table(Session *session,
1498
 
                                 const identifier::Table &identifier,
 
1477
                                 TableIdentifier &identifier,
1499
1478
                                 HA_CREATE_INFO *create_info,
1500
1479
                                 message::Table &table_proto,
1501
1480
                                 AlterInfo *alter_info,
1522
1501
    }
1523
1502
    else
1524
1503
    {
1525
 
      my_error(ER_TABLE_EXISTS_ERROR, identifier);
 
1504
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1526
1505
      result= true;
1527
1506
    }
1528
1507
  }
1529
1508
  else
1530
1509
  {
1531
 
    result= create_table_no_lock(session,
 
1510
    result= mysql_create_table_no_lock(session,
1532
1511
                                       identifier,
1533
1512
                                       create_info,
1534
1513
                                       table_proto,
1540
1519
 
1541
1520
  if (name_lock)
1542
1521
  {
1543
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* Lock for removing name_lock during table create */
 
1522
    pthread_mutex_lock(&LOCK_open); /* Lock for removing name_lock during table create */
1544
1523
    session->unlink_open_table(name_lock);
 
1524
    pthread_mutex_unlock(&LOCK_open);
1545
1525
  }
1546
1526
 
1547
1527
  return(result);
1549
1529
 
1550
1530
 
1551
1531
/*
1552
 
  Database locking aware wrapper for create_table_no_lock(),
 
1532
  Database locking aware wrapper for mysql_create_table_no_lock(),
1553
1533
*/
1554
 
bool create_table(Session *session,
1555
 
                        const identifier::Table &identifier,
 
1534
bool mysql_create_table(Session *session,
 
1535
                        TableIdentifier &identifier,
1556
1536
                        HA_CREATE_INFO *create_info,
1557
1537
                        message::Table &table_proto,
1558
1538
                        AlterInfo *alter_info,
1562
1542
{
1563
1543
  if (identifier.isTmp())
1564
1544
  {
1565
 
    return create_table_no_lock(session,
 
1545
    return mysql_create_table_no_lock(session,
1566
1546
                                      identifier,
1567
1547
                                      create_info,
1568
1548
                                      table_proto,
1588
1568
**/
1589
1569
 
1590
1570
static bool
1591
 
check_if_keyname_exists(const char *name, KeyInfo *start, KeyInfo *end)
 
1571
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
1592
1572
{
1593
 
  for (KeyInfo *key=start ; key != end ; key++)
 
1573
  for (KEY *key=start ; key != end ; key++)
1594
1574
    if (!my_strcasecmp(system_charset_info,name,key->name))
1595
1575
      return 1;
1596
1576
  return 0;
1598
1578
 
1599
1579
 
1600
1580
static char *
1601
 
make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end)
 
1581
make_unique_key_name(const char *field_name,KEY *start,KEY *end)
1602
1582
{
1603
1583
  char buff[MAX_FIELD_NAME],*buff_end;
1604
1584
 
1632
1612
  Rename a table.
1633
1613
 
1634
1614
  SYNOPSIS
1635
 
    rename_table()
1636
 
      session
 
1615
    mysql_rename_table()
1637
1616
      base                      The plugin::StorageEngine handle.
1638
1617
      old_db                    The old database name.
1639
1618
      old_name                  The old table name.
1640
1619
      new_db                    The new database name.
1641
1620
      new_name                  The new table name.
 
1621
      flags                     flags for build_table_filename().
 
1622
                                FN_FROM_IS_TMP old_name is temporary.
 
1623
                                FN_TO_IS_TMP   new_name is temporary.
1642
1624
 
1643
1625
  RETURN
1644
1626
    false   OK
1646
1628
*/
1647
1629
 
1648
1630
bool
1649
 
rename_table(Session &session,
1650
 
                   plugin::StorageEngine *base,
1651
 
                   const identifier::Table &from,
1652
 
                   const identifier::Table &to)
 
1631
mysql_rename_table(plugin::StorageEngine *base,
 
1632
                   TableIdentifier &from,
 
1633
                   TableIdentifier &to,
 
1634
                   uint32_t )
1653
1635
{
 
1636
  Session *session= current_session;
1654
1637
  int error= 0;
1655
1638
 
1656
1639
  assert(base);
1661
1644
    return true;
1662
1645
  }
1663
1646
 
1664
 
  error= base->renameTable(session, from, to);
 
1647
  error= base->renameTable(*session, from, to);
1665
1648
 
1666
1649
  if (error == HA_ERR_WRONG_COMMAND)
1667
1650
  {
1669
1652
  }
1670
1653
  else if (error)
1671
1654
  {
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();
 
1655
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from.getSQLPath().c_str();
 
1656
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to.getSQLPath().c_str();
1680
1657
 
1681
1658
    my_error(ER_ERROR_ON_RENAME, MYF(0), from_identifier, to_identifier, error);
1682
1659
  }
1700
1677
   the table is closed.
1701
1678
 
1702
1679
  PREREQUISITES
1703
 
    Lock on table::Cache::singleton().mutex()
 
1680
    Lock on LOCK_open
1704
1681
    Win32 clients must also have a WRITE LOCK on the table !
1705
1682
*/
1706
1683
 
1708
1685
                              enum ha_extra_function function)
1709
1686
{
1710
1687
 
1711
 
  safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
 
1688
  safe_mutex_assert_owner(&LOCK_open);
1712
1689
 
1713
1690
  table->cursor->extra(function);
1714
1691
  /* Mark all tables that are in use as 'old' */
1715
 
  session->abortLock(table);    /* end threads waiting on lock */
 
1692
  mysql_lock_abort(session, table);     /* end threads waiting on lock */
1716
1693
 
1717
1694
  /* 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);
 
1695
  remove_table_from_cache(session, table->s->getSchemaName(),
 
1696
                          table->s->table_name.str,
 
1697
                          RTFC_WAIT_OTHER_THREAD_FLAG);
1720
1698
}
1721
1699
 
1722
1700
/*
1732
1710
    reopen the table.
1733
1711
 
1734
1712
  PREREQUISITES
1735
 
    Lock on table::Cache::singleton().mutex()
 
1713
    Lock on LOCK_open
1736
1714
    Win32 clients must also have a WRITE LOCK on the table !
1737
1715
*/
1738
1716
 
1743
1721
  /* Close lock if this is not got with LOCK TABLES */
1744
1722
  if (lock)
1745
1723
  {
1746
 
    unlockTables(lock);
 
1724
    mysql_unlock_tables(this, lock);
1747
1725
    lock= NULL;                 // Start locked threads
1748
1726
  }
1749
1727
  /* Close all copies of 'table'.  This also frees all LOCK TABLES lock */
1750
1728
  unlink_open_table(table);
1751
1729
 
1752
 
  /* When lock on table::Cache::singleton().mutex() is freed other threads can continue */
1753
 
  locking::broadcast_refresh();
 
1730
  /* When lock on LOCK_open is freed other threads can continue */
 
1731
  broadcast_refresh();
1754
1732
}
1755
1733
 
1756
1734
/*
1759
1737
    true  Message should be sent by caller
1760
1738
          (admin operation or network communication failed)
1761
1739
*/
1762
 
static bool admin_table(Session* session, TableList* tables,
 
1740
static bool mysql_admin_table(Session* session, TableList* tables,
1763
1741
                              HA_CHECK_OPT* check_opt,
1764
1742
                              const char *operator_name,
1765
1743
                              thr_lock_type lock_type,
1768
1746
                                                            HA_CHECK_OPT *))
1769
1747
{
1770
1748
  TableList *table;
1771
 
  Select_Lex *select= &session->getLex()->select_lex;
 
1749
  Select_Lex *select= &session->lex->select_lex;
1772
1750
  List<Item> field_list;
1773
1751
  Item *item;
 
1752
  LEX *lex= session->lex;
1774
1753
  int result_code= 0;
1775
1754
  TransactionServices &transaction_services= TransactionServices::singleton();
1776
1755
  const CHARSET_INFO * const cs= system_charset_info;
1777
1756
 
1778
1757
  if (! session->endActiveTransaction())
1779
1758
    return 1;
1780
 
 
1781
1759
  field_list.push_back(item = new Item_empty_string("Table",
1782
1760
                                                    NAME_CHAR_LEN * 2,
1783
1761
                                                    cs));
1788
1766
  item->maybe_null = 1;
1789
1767
  field_list.push_back(item = new Item_empty_string("Msg_text", 255, cs));
1790
1768
  item->maybe_null = 1;
1791
 
  if (session->getClient()->sendFields(&field_list))
 
1769
  if (session->client->sendFields(&field_list))
1792
1770
    return true;
1793
1771
 
1794
1772
  for (table= tables; table; table= table->next_local)
1795
1773
  {
1796
 
    identifier::Table table_identifier(table->getSchemaName(), table->getTableName());
1797
 
    std::string table_name;
 
1774
    char table_name[NAME_LEN*2+2];
 
1775
    char* db = table->db;
1798
1776
    bool fatal_error=0;
1799
1777
 
1800
 
    table_identifier.getSQLPath(table_name);
1801
 
 
 
1778
    snprintf(table_name, sizeof(table_name), "%s.%s",db,table->table_name);
1802
1779
    table->lock_type= lock_type;
1803
1780
    /* open only one table from local list of command */
1804
1781
    {
1811
1788
      /*
1812
1789
        Time zone tables and SP tables can be add to lex->query_tables list,
1813
1790
        so it have to be prepared.
1814
 
        @todo Investigate if we can put extra tables into argument instead of using lex->query_tables
 
1791
        TODO: Investigate if we can put extra tables into argument instead of
 
1792
        using lex->query_tables
1815
1793
      */
1816
 
      session->getLex()->query_tables= table;
1817
 
      session->getLex()->query_tables_last= &table->next_global;
1818
 
      session->getLex()->query_tables_own_last= 0;
 
1794
      lex->query_tables= table;
 
1795
      lex->query_tables_last= &table->next_global;
 
1796
      lex->query_tables_own_last= 0;
1819
1797
      session->no_warnings_for_error= 0;
1820
1798
 
1821
1799
      session->openTablesLock(table);
1845
1823
    {
1846
1824
      char buff[FN_REFLEN + DRIZZLE_ERRMSG_SIZE];
1847
1825
      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"));
 
1826
      session->client->store(table_name);
 
1827
      session->client->store(operator_name);
 
1828
      session->client->store(STRING_WITH_LEN("error"));
1851
1829
      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);
 
1830
                       table_name);
 
1831
      session->client->store(buff, length);
 
1832
      transaction_services.ha_autocommit_or_rollback(session, false);
1855
1833
      session->endTransaction(COMMIT);
1856
1834
      session->close_thread_tables();
1857
 
      session->getLex()->reset_query_tables_list(false);
 
1835
      lex->reset_query_tables_list(false);
1858
1836
      table->table=0;                           // For query cache
1859
 
      if (session->getClient()->flush())
 
1837
      if (session->client->flush())
1860
1838
        goto err;
1861
1839
      continue;
1862
1840
    }
1863
1841
 
1864
1842
    /* Close all instances of the table to allow repair to rename files */
1865
 
    if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
 
1843
    if (lock_type == TL_WRITE && table->table->s->version)
1866
1844
    {
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);
 
1845
      pthread_mutex_lock(&LOCK_open); /* Lock type is TL_WRITE and we lock to repair the table */
 
1846
      const char *old_message=session->enter_cond(&COND_refresh, &LOCK_open,
 
1847
                                              "Waiting to get writelock");
 
1848
      mysql_lock_abort(session,table->table);
 
1849
      remove_table_from_cache(session, table->table->s->getSchemaName(),
 
1850
                              table->table->s->table_name.str,
 
1851
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
1852
                              RTFC_CHECK_KILLED_FLAG);
1873
1853
      session->exit_cond(old_message);
1874
 
      if (session->getKilled())
 
1854
      if (session->killed)
1875
1855
        goto err;
1876
1856
      open_for_modify= 0;
1877
1857
    }
1880
1860
 
1881
1861
send_result:
1882
1862
 
1883
 
    session->getLex()->cleanup_after_one_table_open();
 
1863
    lex->cleanup_after_one_table_open();
1884
1864
    session->clear_error();  // these errors shouldn't get client
1885
1865
    {
1886
 
      List<DRIZZLE_ERROR>::iterator it(session->warn_list.begin());
 
1866
      List_iterator_fast<DRIZZLE_ERROR> it(session->warn_list);
1887
1867
      DRIZZLE_ERROR *err;
1888
1868
      while ((err= it++))
1889
1869
      {
1890
 
        session->getClient()->store(table_name.c_str());
1891
 
        session->getClient()->store(operator_name);
1892
 
        session->getClient()->store(warning_level_names[err->level].str,
 
1870
        session->client->store(table_name);
 
1871
        session->client->store(operator_name);
 
1872
        session->client->store(warning_level_names[err->level].str,
1893
1873
                               warning_level_names[err->level].length);
1894
 
        session->getClient()->store(err->msg);
1895
 
        if (session->getClient()->flush())
 
1874
        session->client->store(err->msg);
 
1875
        if (session->client->flush())
1896
1876
          goto err;
1897
1877
      }
1898
1878
      drizzle_reset_errors(session, true);
1899
1879
    }
1900
 
    session->getClient()->store(table_name.c_str());
1901
 
    session->getClient()->store(operator_name);
 
1880
    session->client->store(table_name);
 
1881
    session->client->store(operator_name);
1902
1882
 
1903
1883
    switch (result_code) {
1904
1884
    case HA_ADMIN_NOT_IMPLEMENTED:
1906
1886
        char buf[ERRMSGSIZE+20];
1907
1887
        uint32_t length=snprintf(buf, ERRMSGSIZE,
1908
1888
                             ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
1909
 
        session->getClient()->store(STRING_WITH_LEN("note"));
1910
 
        session->getClient()->store(buf, length);
 
1889
        session->client->store(STRING_WITH_LEN("note"));
 
1890
        session->client->store(buf, length);
1911
1891
      }
1912
1892
      break;
1913
1893
 
1914
1894
    case HA_ADMIN_OK:
1915
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1916
 
      session->getClient()->store(STRING_WITH_LEN("OK"));
 
1895
      session->client->store(STRING_WITH_LEN("status"));
 
1896
      session->client->store(STRING_WITH_LEN("OK"));
1917
1897
      break;
1918
1898
 
1919
1899
    case HA_ADMIN_FAILED:
1920
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1921
 
      session->getClient()->store(STRING_WITH_LEN("Operation failed"));
 
1900
      session->client->store(STRING_WITH_LEN("status"));
 
1901
      session->client->store(STRING_WITH_LEN("Operation failed"));
1922
1902
      break;
1923
1903
 
1924
1904
    case HA_ADMIN_REJECT:
1925
 
      session->getClient()->store(STRING_WITH_LEN("status"));
1926
 
      session->getClient()->store(STRING_WITH_LEN("Operation need committed state"));
 
1905
      session->client->store(STRING_WITH_LEN("status"));
 
1906
      session->client->store(STRING_WITH_LEN("Operation need committed state"));
1927
1907
      open_for_modify= false;
1928
1908
      break;
1929
1909
 
1930
1910
    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"));
 
1911
      session->client->store(STRING_WITH_LEN("status"));
 
1912
      session->client->store(STRING_WITH_LEN("Table is already up to date"));
1933
1913
      break;
1934
1914
 
1935
1915
    case HA_ADMIN_CORRUPT:
1936
 
      session->getClient()->store(STRING_WITH_LEN("error"));
1937
 
      session->getClient()->store(STRING_WITH_LEN("Corrupt"));
 
1916
      session->client->store(STRING_WITH_LEN("error"));
 
1917
      session->client->store(STRING_WITH_LEN("Corrupt"));
1938
1918
      fatal_error=1;
1939
1919
      break;
1940
1920
 
1941
1921
    case HA_ADMIN_INVALID:
1942
 
      session->getClient()->store(STRING_WITH_LEN("error"));
1943
 
      session->getClient()->store(STRING_WITH_LEN("Invalid argument"));
 
1922
      session->client->store(STRING_WITH_LEN("error"));
 
1923
      session->client->store(STRING_WITH_LEN("Invalid argument"));
1944
1924
      break;
1945
1925
 
1946
1926
    default:                            // Probably HA_ADMIN_INTERNAL_ERROR
1949
1929
        uint32_t length=snprintf(buf, ERRMSGSIZE,
1950
1930
                             _("Unknown - internal error %d during operation"),
1951
1931
                             result_code);
1952
 
        session->getClient()->store(STRING_WITH_LEN("error"));
1953
 
        session->getClient()->store(buf, length);
 
1932
        session->client->store(STRING_WITH_LEN("error"));
 
1933
        session->client->store(buf, length);
1954
1934
        fatal_error=1;
1955
1935
        break;
1956
1936
      }
1958
1938
    if (table->table)
1959
1939
    {
1960
1940
      if (fatal_error)
1961
 
      {
1962
 
        table->table->getMutableShare()->resetVersion();               // Force close of table
1963
 
      }
 
1941
        table->table->s->version=0;               // Force close of table
1964
1942
      else if (open_for_modify)
1965
1943
      {
1966
 
        if (table->table->getShare()->getType())
1967
 
        {
 
1944
        if (table->table->s->tmp_table)
1968
1945
          table->table->cursor->info(HA_STATUS_CONST);
1969
 
        }
1970
1946
        else
1971
1947
        {
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);
 
1948
          pthread_mutex_lock(&LOCK_open);
 
1949
          remove_table_from_cache(session, table->table->s->getSchemaName(),
 
1950
                                  table->table->s->table_name.str, RTFC_NO_FLAG);
 
1951
          pthread_mutex_unlock(&LOCK_open);
1975
1952
        }
1976
1953
      }
1977
1954
    }
1978
 
    transaction_services.autocommitOrRollback(*session, false);
 
1955
    transaction_services.ha_autocommit_or_rollback(session, false);
1979
1956
    session->endTransaction(COMMIT);
1980
1957
    session->close_thread_tables();
1981
1958
    table->table=0;                             // For query cache
1982
 
    if (session->getClient()->flush())
 
1959
    if (session->client->flush())
1983
1960
      goto err;
1984
1961
  }
1985
1962
 
1987
1964
  return(false);
1988
1965
 
1989
1966
err:
1990
 
  transaction_services.autocommitOrRollback(*session, true);
 
1967
  transaction_services.ha_autocommit_or_rollback(session, true);
1991
1968
  session->endTransaction(ROLLBACK);
1992
1969
  session->close_thread_tables();                       // Shouldn't be needed
1993
1970
  if (table)
1995
1972
  return(true);
1996
1973
}
1997
1974
 
 
1975
/*
 
1976
  We have to write the query before we unlock the named table.
 
1977
 
 
1978
  Since temporary tables are not replicated under row-based
 
1979
  replication, CREATE TABLE ... LIKE ... needs special
 
1980
  treatement.  We have four cases to consider, according to the
 
1981
  following decision table:
 
1982
 
 
1983
  ==== ========= ========= ==============================
 
1984
  Case    Target    Source Write to binary log
 
1985
  ==== ========= ========= ==============================
 
1986
  1       normal    normal Original statement
 
1987
  2       normal temporary Generated statement
 
1988
  3    temporary    normal Nothing
 
1989
  4    temporary temporary Nothing
 
1990
  ==== ========= ========= ==============================
 
1991
*/
 
1992
static bool replicateCreateTableLike(Session *session, TableList *table, Table *name_lock,
 
1993
                                     bool is_src_table_tmp, bool is_if_not_exists)
 
1994
{
 
1995
  if (is_src_table_tmp)
 
1996
  {
 
1997
    char buf[2048];
 
1998
    String query(buf, sizeof(buf), system_charset_info);
 
1999
    query.length(0);  // Have to zero it since constructor doesn't
 
2000
 
 
2001
 
 
2002
    /*
 
2003
      Here we open the destination table, on which we already have
 
2004
      name-lock. This is needed for store_create_info() to work.
 
2005
      The table will be closed by unlink_open_table() at the end
 
2006
      of this function.
 
2007
    */
 
2008
    table->table= name_lock;
 
2009
    pthread_mutex_lock(&LOCK_open); /* Open new table we have just acquired */
 
2010
    if (session->reopen_name_locked_table(table, false))
 
2011
    {
 
2012
      pthread_mutex_unlock(&LOCK_open);
 
2013
      return false;
 
2014
    }
 
2015
    pthread_mutex_unlock(&LOCK_open);
 
2016
 
 
2017
    int result= store_create_info(table, &query, is_if_not_exists);
 
2018
 
 
2019
    assert(result == 0); // store_create_info() always return 0
 
2020
    write_bin_log(session, query.ptr());
 
2021
  }
 
2022
  else                                      // Case 1
 
2023
  {
 
2024
    write_bin_log(session, session->query.c_str());
 
2025
  }
 
2026
 
 
2027
  return true;
 
2028
}
 
2029
 
1998
2030
  /*
1999
2031
    Create a new table by copying from source table
2000
2032
 
2001
2033
    Altough exclusive name-lock on target table protects us from concurrent
2002
2034
    DML and DDL operations on it we still want to wrap .FRM creation and call
2003
2035
    to plugin::StorageEngine::createTable() in critical section protected by
2004
 
    table::Cache::singleton().mutex() in order to provide minimal atomicity against operations which
 
2036
    LOCK_open in order to provide minimal atomicity against operations which
2005
2037
    disregard name-locks, like I_S implementation, for example. This is a
2006
2038
    temporary and should not be copied. Instead we should fix our code to
2007
2039
    always honor name-locks.
2008
2040
 
2009
 
    Also some engines (e.g. NDB cluster) require that table::Cache::singleton().mutex() should be held
 
2041
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
2010
2042
    during the call to plugin::StorageEngine::createTable().
2011
2043
    See bug #28614 for more info.
2012
2044
  */
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,
 
2045
static bool create_table_wrapper(Session &session, const message::Table& create_table_proto,
 
2046
                                 TableIdentifier &destination_identifier,
 
2047
                                 TableIdentifier &src_table,
2017
2048
                                 bool is_engine_set)
2018
2049
{
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);
 
2050
  int protoerr= EEXIST;
 
2051
  message::Table new_proto;
 
2052
  message::Table src_proto;
 
2053
 
 
2054
  protoerr= plugin::StorageEngine::getTableDefinition(session,
 
2055
                                                      src_table,
 
2056
                                                      src_proto);
 
2057
  new_proto.CopyFrom(src_proto);
2033
2058
 
2034
2059
  if (destination_identifier.isTmp())
2035
2060
  {
2036
 
    new_table_message.set_type(message::Table::TEMPORARY);
 
2061
    new_proto.set_type(message::Table::TEMPORARY);
2037
2062
  }
2038
2063
  else
2039
2064
  {
2040
 
    new_table_message.set_type(message::Table::STANDARD);
 
2065
    new_proto.set_type(message::Table::STANDARD);
2041
2066
  }
2042
2067
 
2043
2068
  if (is_engine_set)
2044
2069
  {
2045
 
    new_table_message.mutable_engine()->set_name(create_table_proto.engine().name());
 
2070
    message::Table::StorageEngine *protoengine;
 
2071
 
 
2072
    protoengine= new_proto.mutable_engine();
 
2073
    protoengine->set_name(create_table_proto.engine().name());
2046
2074
  }
2047
2075
 
2048
2076
  { // 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());
 
2077
    new_proto.set_name(create_table_proto.name());
 
2078
    new_proto.set_schema(create_table_proto.schema());
 
2079
    new_proto.set_catalog(create_table_proto.catalog());
2052
2080
  }
2053
2081
 
2054
 
  /* Fix names of foreign keys being added */
2055
 
  for (int32_t j= 0; j < new_table_message.fk_constraint_size(); j++)
 
2082
  if (protoerr && protoerr != EEXIST)
2056
2083
  {
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
 
    }
 
2084
    if (errno == ENOENT)
 
2085
      my_error(ER_BAD_DB_ERROR,MYF(0), destination_identifier.getSchemaName().c_str());
 
2086
    else
 
2087
      my_error(ER_CANT_CREATE_FILE, MYF(0), destination_identifier.getPath().c_str(), errno);
 
2088
 
 
2089
    return false;
2069
2090
  }
2070
2091
 
2071
2092
  /*
2072
2093
    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).
 
2094
    creation, instead create the table directly (for both normal
 
2095
    and temporary tables).
2074
2096
  */
2075
 
  bool success= plugin::StorageEngine::createTable(session,
2076
 
                                                   destination_identifier,
2077
 
                                                   new_table_message);
2078
 
 
2079
 
  if (success && not destination_identifier.isTmp())
2080
 
  {
2081
 
    TransactionServices &transaction_services= TransactionServices::singleton();
2082
 
    transaction_services.createTable(session, new_table_message);
2083
 
  }
2084
 
 
2085
 
  return success;
 
2097
  int err= plugin::StorageEngine::createTable(session,
 
2098
                                              destination_identifier,
 
2099
                                              true, new_proto);
 
2100
 
 
2101
  return err ? false : true;
2086
2102
}
2087
2103
 
2088
2104
/*
2089
2105
  Create a table identical to the specified table
2090
2106
 
2091
2107
  SYNOPSIS
2092
 
    create_like_table()
 
2108
    mysql_create_like_table()
2093
2109
    session             Thread object
2094
2110
    table       Table list element for target table
2095
2111
    src_table   Table list element for source table
2100
2116
    true  error
2101
2117
*/
2102
2118
 
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)
 
2119
bool mysql_create_like_table(Session* session,
 
2120
                             TableIdentifier &destination_identifier,
 
2121
                             TableList* table, TableList* src_table,
 
2122
                             message::Table &create_table_proto,
 
2123
                             bool is_if_not_exists,
 
2124
                             bool is_engine_set)
2109
2125
{
 
2126
  Table *name_lock= 0;
 
2127
  char *db= table->db;
 
2128
  char *table_name= table->table_name;
2110
2129
  bool res= true;
2111
 
  bool table_exists= false;
 
2130
  uint32_t not_used;
 
2131
  bool was_created;
 
2132
 
 
2133
  /*
 
2134
    By opening source table we guarantee that it exists and no concurrent
 
2135
    DDL operation will mess with it. Later we also take an exclusive
 
2136
    name-lock on target table name, which makes copying of .frm cursor,
 
2137
    call to plugin::StorageEngine::createTable() and binlogging atomic
 
2138
    against concurrent DML and DDL operations on target table.
 
2139
    Thus by holding both these "locks" we ensure that our statement is
 
2140
    properly isolated from all concurrent operations which matter.
 
2141
  */
 
2142
  if (session->open_tables_from_list(&src_table, &not_used))
 
2143
    return true;
 
2144
 
 
2145
  TableIdentifier src_identifier(src_table->table->s->getSchemaName(),
 
2146
                                 src_table->table->s->table_name.str, src_table->table->s->tmp_table);
 
2147
 
 
2148
 
2112
2149
 
2113
2150
  /*
2114
2151
    Check that destination tables does not exist. Note that its name
2115
2152
    was already checked when it was added to the table list.
2116
 
 
2117
 
    For temporary tables we don't aim to grab locks.
2118
2153
  */
 
2154
  bool table_exists= false;
2119
2155
  if (destination_identifier.isTmp())
2120
2156
  {
2121
 
    if (session->find_temporary_table(destination_identifier))
 
2157
    if (session->find_temporary_table(db, table_name))
2122
2158
    {
2123
2159
      table_exists= true;
2124
2160
    }
2125
 
    else
2126
 
    {
2127
 
      bool was_created= create_table_wrapper(*session,
2128
 
                                             create_table_proto,
2129
 
                                             destination_identifier,
2130
 
                                             source_identifier,
2131
 
                                             is_engine_set);
2132
 
      if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2133
 
      {
2134
 
        (void) session->rm_temporary_table(destination_identifier, true);
2135
 
      }
2136
 
      else if (not session->open_temporary_table(destination_identifier))
2137
 
      {
2138
 
        // We created, but we can't open... also, a hack.
2139
 
        (void) session->rm_temporary_table(destination_identifier, true);
2140
 
      }
2141
 
      else
2142
 
      {
2143
 
        res= false;
2144
 
      }
2145
 
    }
2146
2161
  }
2147
 
  else // Standard table which will require locks.
 
2162
  else
2148
2163
  {
2149
 
    Table *name_lock= 0;
2150
 
 
2151
 
    if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
 
2164
    if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
2152
2165
    {
2153
2166
      if (name_lock)
2154
2167
      {
2155
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
 
2168
        pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2156
2169
        session->unlink_open_table(name_lock);
 
2170
        pthread_mutex_unlock(&LOCK_open);
2157
2171
      }
2158
2172
 
2159
2173
      return res;
2167
2181
    {
2168
2182
      table_exists= true;
2169
2183
    }
2170
 
    else // Otherwise we create the table
2171
 
    {
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
 
      }
2178
 
 
2179
 
      // So we blew the creation of the table, and we scramble to clean up
2180
 
      // anything that might have been created (read... it is a hack)
2181
 
      if (not was_created)
2182
 
      {
2183
 
        plugin::StorageEngine::dropTable(*session, destination_identifier);
2184
 
      } 
2185
 
      else
2186
 
      {
2187
 
        res= false;
2188
 
      }
2189
 
    }
2190
 
 
2191
 
    if (name_lock)
2192
 
    {
2193
 
      boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2194
 
      session->unlink_open_table(name_lock);
2195
 
    }
2196
2184
  }
2197
2185
 
2198
2186
  if (table_exists)
2201
2189
    {
2202
2190
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
2203
2191
      snprintf(warn_buff, sizeof(warn_buff),
2204
 
               ER(ER_TABLE_EXISTS_ERROR), destination_identifier.getTableName().c_str());
 
2192
               ER(ER_TABLE_EXISTS_ERROR), table_name);
2205
2193
      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
 
  }
2214
 
 
2215
 
  return res;
 
2194
                   ER_TABLE_EXISTS_ERROR,warn_buff);
 
2195
      res= false;
 
2196
    }
 
2197
    else
 
2198
    {
 
2199
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
2200
    }
 
2201
  }
 
2202
  else // Otherwise we create the table
 
2203
  {
 
2204
    pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
 
2205
    was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
 
2206
                                      src_identifier, is_engine_set);
 
2207
    pthread_mutex_unlock(&LOCK_open);
 
2208
 
 
2209
    // So we blew the creation of the table, and we scramble to clean up
 
2210
    // anything that might have been created (read... it is a hack)
 
2211
    if (not was_created)
 
2212
    {
 
2213
      if (destination_identifier.isTmp())
 
2214
      {
 
2215
        (void) session->rm_temporary_table(destination_identifier);
 
2216
      }
 
2217
      else
 
2218
      {
 
2219
        quick_rm_table(*session, destination_identifier);
 
2220
      }
 
2221
    } 
 
2222
    else if (destination_identifier.isTmp() && not session->open_temporary_table(destination_identifier))
 
2223
    {
 
2224
      // We created, but we can't open... also, a hack.
 
2225
      (void) session->rm_temporary_table(destination_identifier);
 
2226
    }
 
2227
    else
 
2228
    {
 
2229
      if (not destination_identifier.isTmp())
 
2230
      {
 
2231
        bool rc= replicateCreateTableLike(session, table, name_lock, (src_table->table->s->tmp_table), is_if_not_exists);
 
2232
        (void)rc;
 
2233
      }
 
2234
 
 
2235
      res= false;
 
2236
    }
 
2237
  }
 
2238
 
 
2239
  if (name_lock)
 
2240
  {
 
2241
    pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
 
2242
    session->unlink_open_table(name_lock);
 
2243
    pthread_mutex_unlock(&LOCK_open);
 
2244
  }
 
2245
 
 
2246
  return(res);
2216
2247
}
2217
2248
 
2218
2249
 
2219
 
bool analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
 
2250
bool mysql_analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
2220
2251
{
2221
2252
  thr_lock_type lock_type = TL_READ_NO_INSERT;
2222
2253
 
2223
 
  return(admin_table(session, tables, check_opt,
 
2254
  return(mysql_admin_table(session, tables, check_opt,
2224
2255
                                "analyze", lock_type, true,
2225
2256
                                &Cursor::ha_analyze));
2226
2257
}
2227
2258
 
2228
2259
 
2229
 
bool check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
 
2260
bool mysql_check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
2230
2261
{
2231
2262
  thr_lock_type lock_type = TL_READ_NO_INSERT;
2232
2263
 
2233
 
  return(admin_table(session, tables, check_opt,
 
2264
  return(mysql_admin_table(session, tables, check_opt,
2234
2265
                                "check", lock_type,
2235
2266
                                false,
2236
2267
                                &Cursor::ha_check));
2237
2268
}
2238
2269
 
 
2270
 
 
2271
bool mysql_checksum_table(Session *session, TableList *tables,
 
2272
                          HA_CHECK_OPT *)
 
2273
{
 
2274
  TableList *table;
 
2275
  List<Item> field_list;
 
2276
  Item *item;
 
2277
 
 
2278
  field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
 
2279
  item->maybe_null= 1;
 
2280
  field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
 
2281
                                          MY_INT64_NUM_DECIMAL_DIGITS));
 
2282
  item->maybe_null= 1;
 
2283
  if (session->client->sendFields(&field_list))
 
2284
    return true;
 
2285
 
 
2286
  /* Open one table after the other to keep lock time as short as possible. */
 
2287
  for (table= tables; table; table= table->next_local)
 
2288
  {
 
2289
    char table_name[NAME_LEN*2+2];
 
2290
    Table *t;
 
2291
 
 
2292
    snprintf(table_name, sizeof(table_name), "%s.%s",table->db,table->table_name);
 
2293
 
 
2294
    t= table->table= session->openTableLock(table, TL_READ);
 
2295
    session->clear_error();                     // these errors shouldn't get client
 
2296
 
 
2297
    session->client->store(table_name);
 
2298
 
 
2299
    if (!t)
 
2300
    {
 
2301
      /* Table didn't exist */
 
2302
      session->client->store();
 
2303
      session->clear_error();
 
2304
    }
 
2305
    else
 
2306
    {
 
2307
      /**
 
2308
        @note if the engine keeps a checksum then we return the checksum, otherwise we calculate
 
2309
      */
 
2310
      if (t->cursor->getEngine()->check_flag(HTON_BIT_HAS_CHECKSUM))
 
2311
      {
 
2312
        session->client->store((uint64_t)t->cursor->checksum());
 
2313
      }
 
2314
      else
 
2315
      {
 
2316
        /* calculating table's checksum */
 
2317
        internal::ha_checksum crc= 0;
 
2318
        unsigned char null_mask=256 -  (1 << t->s->last_null_bit_pos);
 
2319
 
 
2320
        t->use_all_columns();
 
2321
 
 
2322
        if (t->cursor->ha_rnd_init(1))
 
2323
          session->client->store();
 
2324
        else
 
2325
        {
 
2326
          for (;;)
 
2327
          {
 
2328
            internal::ha_checksum row_crc= 0;
 
2329
            int error= t->cursor->rnd_next(t->record[0]);
 
2330
            if (unlikely(error))
 
2331
            {
 
2332
              if (error == HA_ERR_RECORD_DELETED)
 
2333
                continue;
 
2334
              break;
 
2335
            }
 
2336
            if (t->s->null_bytes)
 
2337
            {
 
2338
              /* fix undefined null bits */
 
2339
              t->record[0][t->s->null_bytes-1] |= null_mask;
 
2340
              if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
 
2341
                t->record[0][0] |= 1;
 
2342
 
 
2343
              row_crc= internal::my_checksum(row_crc, t->record[0], t->s->null_bytes);
 
2344
            }
 
2345
 
 
2346
            for (uint32_t i= 0; i < t->s->fields; i++ )
 
2347
            {
 
2348
              Field *f= t->field[i];
 
2349
              if ((f->type() == DRIZZLE_TYPE_BLOB) ||
 
2350
                  (f->type() == DRIZZLE_TYPE_VARCHAR))
 
2351
              {
 
2352
                String tmp;
 
2353
                f->val_str(&tmp);
 
2354
                row_crc= internal::my_checksum(row_crc, (unsigned char*) tmp.ptr(), tmp.length());
 
2355
              }
 
2356
              else
 
2357
                row_crc= internal::my_checksum(row_crc, f->ptr,
 
2358
                                     f->pack_length());
 
2359
            }
 
2360
 
 
2361
            crc+= row_crc;
 
2362
          }
 
2363
          session->client->store((uint64_t)crc);
 
2364
          t->cursor->ha_rnd_end();
 
2365
        }
 
2366
      }
 
2367
      session->clear_error();
 
2368
      session->close_thread_tables();
 
2369
      table->table=0;                           // For query cache
 
2370
    }
 
2371
    if (session->client->flush())
 
2372
      goto err;
 
2373
  }
 
2374
 
 
2375
  session->my_eof();
 
2376
  return(false);
 
2377
 
 
2378
 err:
 
2379
  session->close_thread_tables();                       // Shouldn't be needed
 
2380
  if (table)
 
2381
    table->table=0;
 
2382
  return(true);
 
2383
}
 
2384
 
2239
2385
} /* namespace drizzled */