~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

  • Committer: Padraig O'Sullivan
  • Date: 2009-11-28 22:02:19 UTC
  • mfrom: (1228 push)
  • mto: (1228.4.1 push)
  • mto: This revision was merged to the branch mainline in revision 1234.
  • Revision ID: osullivan.padraig@gmail.com-20091128220219-m3x28m8q2unbirke
MergeĀ fromĀ trunk.

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 <drizzled/server_includes.h>
19
19
#include <plugin/myisam/myisam.h>
20
20
#include <drizzled/show.h>
21
21
#include <drizzled/error.h>
22
22
#include <drizzled/gettext.h>
23
23
#include <drizzled/data_home.h>
24
24
#include <drizzled/sql_parse.h>
25
 
#include <drizzled/my_hash.h>
 
25
#include <mysys/hash.h>
26
26
#include <drizzled/sql_lex.h>
27
27
#include <drizzled/session.h>
28
28
#include <drizzled/sql_base.h>
29
 
#include "drizzled/strfunc.h"
30
29
#include <drizzled/db.h>
31
30
#include <drizzled/lock.h>
32
31
#include <drizzled/unireg.h>
33
32
#include <drizzled/item/int.h>
34
33
#include <drizzled/item/empty_string.h>
35
 
#include <drizzled/transaction_services.h>
36
 
#include "drizzled/transaction_services.h"
 
34
#include <drizzled/replication_services.h>
37
35
#include <drizzled/table_proto.h>
38
36
#include <drizzled/plugin/client.h>
39
 
#include <drizzled/identifier.h>
40
 
#include "drizzled/internal/m_string.h"
41
 
#include "drizzled/global_charset_info.h"
42
 
#include "drizzled/charset.h"
43
 
 
44
 
#include "drizzled/definition/cache.h"
45
 
 
 
37
#include <drizzled/table_identifier.h>
46
38
 
47
39
#include "drizzled/statement/alter_table.h"
48
 
#include "drizzled/sql_table.h"
49
 
#include "drizzled/pthread_globals.h"
 
40
#include "drizzled/plugin/info_schema_table.h"
50
41
 
51
42
#include <algorithm>
52
 
#include <sstream>
53
 
 
54
 
#include <boost/unordered_set.hpp>
55
43
 
56
44
using namespace std;
57
 
 
58
 
namespace drizzled
59
 
{
60
 
 
61
 
extern pid_t current_pid;
62
 
 
63
 
bool is_primary_key(KeyInfo *key_info)
 
45
using namespace drizzled;
 
46
 
 
47
static const char hexchars[]= "0123456789abcdef";
 
48
bool is_primary_key(KEY *key_info)
64
49
{
65
50
  static const char * primary_key_name="PRIMARY";
66
51
  return (strcmp(key_info->name, primary_key_name)==0);
75
60
    return NULL;
76
61
}
77
62
 
78
 
static bool check_if_keyname_exists(const char *name,KeyInfo *start, KeyInfo *end);
79
 
static char *make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end);
 
63
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
 
64
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
80
65
 
81
66
static bool prepare_blob_field(Session *session, CreateField *sql_field);
82
67
 
87
72
    let's fetch the database default character set and
88
73
    apply it to the table.
89
74
  */
90
 
  SchemaIdentifier identifier(db);
91
75
  if (create_info->default_table_charset == NULL)
92
 
    create_info->default_table_charset= plugin::StorageEngine::getSchemaCollation(identifier);
 
76
    create_info->default_table_charset= get_default_db_collation(db);
 
77
}
 
78
 
 
79
/*
 
80
  Translate a cursor name to a table name (WL #1324).
 
81
 
 
82
  SYNOPSIS
 
83
    filename_to_tablename()
 
84
      from                      The cursor name
 
85
      to                OUT     The table name
 
86
      to_length                 The size of the table name buffer.
 
87
 
 
88
  RETURN
 
89
    Table name length.
 
90
*/
 
91
uint32_t filename_to_tablename(const char *from, char *to, uint32_t to_length)
 
92
{
 
93
  uint32_t length= 0;
 
94
 
 
95
  if (!memcmp(from, TMP_FILE_PREFIX, TMP_FILE_PREFIX_LENGTH))
 
96
  {
 
97
    /* Temporary table name. */
 
98
    length= strlen(strncpy(to, from, to_length));
 
99
  }
 
100
  else
 
101
  {
 
102
    for (; *from  && length < to_length; length++, from++)
 
103
    {
 
104
      if (*from != '@')
 
105
      {
 
106
        to[length]= *from;
 
107
        continue;
 
108
      }
 
109
      /* We've found an escaped char - skip the @ */
 
110
      from++;
 
111
      to[length]= 0;
 
112
      /* There will be a two-position hex-char version of the char */
 
113
      for (int x=1; x >= 0; x--)
 
114
      {
 
115
        if (*from >= '0' && *from <= '9')
 
116
          to[length] += ((*from++ - '0') << (4 * x));
 
117
        else if (*from >= 'a' && *from <= 'f')
 
118
          to[length] += ((*from++ - 'a' + 10) << (4 * x));
 
119
      }
 
120
      /* Backup because we advanced extra in the inner loop */
 
121
      from--;
 
122
    } 
 
123
  }
 
124
 
 
125
  return length;
 
126
}
 
127
 
 
128
 
 
129
/*
 
130
  Translate a table name to a cursor name (WL #1324).
 
131
 
 
132
  SYNOPSIS
 
133
    tablename_to_filename()
 
134
      from                      The table name
 
135
      to                OUT     The cursor name
 
136
      to_length                 The size of the cursor name buffer.
 
137
 
 
138
  RETURN
 
139
    true if errors happen. false on success.
 
140
*/
 
141
bool tablename_to_filename(const char *from, char *to, size_t to_length)
 
142
{
 
143
  
 
144
  size_t length= 0;
 
145
  for (; *from  && length < to_length; length++, from++)
 
146
  {
 
147
    if ((*from >= '0' && *from <= '9') ||
 
148
        (*from >= 'A' && *from <= 'Z') ||
 
149
        (*from >= 'a' && *from <= 'z') ||
 
150
/* OSX defines an extra set of high-bit and multi-byte characters
 
151
   that cannot be used on the filesystem. Instead of trying to sort
 
152
   those out, we'll just escape encode all high-bit-set chars on OSX.
 
153
   It won't really hurt anything - it'll just make some filenames ugly. */
 
154
#if !defined(TARGET_OS_OSX)
 
155
        ((unsigned char)*from >= 128) ||
 
156
#endif
 
157
        (*from == '_') ||
 
158
        (*from == ' ') ||
 
159
        (*from == '-'))
 
160
    {
 
161
      to[length]= *from;
 
162
      continue;
 
163
    }
 
164
   
 
165
    if (length + 3 >= to_length)
 
166
      return true;
 
167
 
 
168
    /* We need to escape this char in a way that can be reversed */
 
169
    to[length++]= '@';
 
170
    to[length++]= hexchars[(*from >> 4) & 15];
 
171
    to[length]= hexchars[(*from) & 15];
 
172
  }
 
173
 
 
174
  if (check_if_legal_tablename(to) &&
 
175
      length + 4 < to_length)
 
176
  {
 
177
    memcpy(to + length, "@@@", 4);
 
178
    length+= 3;
 
179
  }
 
180
  return false;
 
181
}
 
182
 
 
183
 
 
184
/*
 
185
  Creates path to a cursor: drizzle_data_dir/db/table.ext
 
186
 
 
187
  SYNOPSIS
 
188
   build_table_filename()
 
189
     buff                       Where to write result
 
190
                                This may be the same as table_name.
 
191
     bufflen                    buff size
 
192
     db                         Database name
 
193
     table_name                 Table name
 
194
     ext                        File extension.
 
195
     flags                      FN_FROM_IS_TMP or FN_TO_IS_TMP
 
196
                                table_name is temporary, do not change.
 
197
 
 
198
  NOTES
 
199
 
 
200
    Uses database and table name, and extension to create
 
201
    a cursor name in drizzle_data_dir. Database and table
 
202
    names are converted from system_charset_info into "fscs".
 
203
    Unless flags indicate a temporary table name.
 
204
    'db' is always converted.
 
205
    'ext' is not converted.
 
206
 
 
207
    The conversion suppression is required for ALTER Table. This
 
208
    statement creates intermediate tables. These are regular
 
209
    (non-temporary) tables with a temporary name. Their path names must
 
210
    be derivable from the table name. So we cannot use
 
211
    build_tmptable_filename() for them.
 
212
 
 
213
  RETURN
 
214
    path length on success, 0 on failure
 
215
*/
 
216
 
 
217
size_t build_table_filename(char *buff, size_t bufflen, const char *db, const char *table_name, bool is_tmp)
 
218
{
 
219
  char dbbuff[FN_REFLEN];
 
220
  char tbbuff[FN_REFLEN];
 
221
  bool conversion_error= false;
 
222
 
 
223
  memset(tbbuff, 0, sizeof(tbbuff));
 
224
  if (is_tmp) // FN_FROM_IS_TMP | FN_TO_IS_TMP
 
225
    strncpy(tbbuff, table_name, sizeof(tbbuff));
 
226
  else
 
227
  {
 
228
    conversion_error= tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
 
229
    if (conversion_error)
 
230
    {
 
231
      errmsg_printf(ERRMSG_LVL_ERROR,
 
232
                    _("Table name cannot be encoded and fit within filesystem "
 
233
                      "name length restrictions."));
 
234
      return 0;
 
235
    }
 
236
  }
 
237
  memset(dbbuff, 0, sizeof(dbbuff));
 
238
  conversion_error= tablename_to_filename(db, dbbuff, sizeof(dbbuff));
 
239
  if (conversion_error)
 
240
  {
 
241
    errmsg_printf(ERRMSG_LVL_ERROR,
 
242
                  _("Schema name cannot be encoded and fit within filesystem "
 
243
                    "name length restrictions."));
 
244
    return 0;
 
245
  }
 
246
   
 
247
 
 
248
  int rootdir_len= strlen(FN_ROOTDIR);
 
249
  string table_path(drizzle_data_home);
 
250
  int without_rootdir= table_path.length()-rootdir_len;
 
251
 
 
252
  /* Don't add FN_ROOTDIR if dirzzle_data_home already includes it */
 
253
  if (without_rootdir >= 0)
 
254
  {
 
255
    const char *tmp= table_path.c_str()+without_rootdir;
 
256
    if (memcmp(tmp, FN_ROOTDIR, rootdir_len) != 0)
 
257
      table_path.append(FN_ROOTDIR);
 
258
  }
 
259
 
 
260
  table_path.append(dbbuff);
 
261
  table_path.append(FN_ROOTDIR);
 
262
  table_path.append(tbbuff);
 
263
 
 
264
  if (bufflen < table_path.length())
 
265
    return 0;
 
266
 
 
267
  strcpy(buff, table_path.c_str());
 
268
 
 
269
  return table_path.length();
 
270
}
 
271
 
 
272
 
 
273
/*
 
274
  Creates path to a cursor: drizzle_tmpdir/#sql1234_12_1.ext
 
275
 
 
276
  SYNOPSIS
 
277
   build_tmptable_filename()
 
278
     session                    The thread handle.
 
279
     buff                       Where to write result
 
280
     bufflen                    buff size
 
281
 
 
282
  NOTES
 
283
 
 
284
    Uses current_pid, thread_id, and tmp_table counter to create
 
285
    a cursor name in drizzle_tmpdir.
 
286
 
 
287
  RETURN
 
288
    path length on success, 0 on failure
 
289
*/
 
290
 
 
291
size_t build_tmptable_filename(char *buff, size_t bufflen)
 
292
{
 
293
  size_t length;
 
294
  ostringstream path_str, post_tmpdir_str;
 
295
  string tmp;
 
296
 
 
297
  Session *session= current_session;
 
298
 
 
299
  path_str << drizzle_tmpdir;
 
300
  post_tmpdir_str << "/" << TMP_FILE_PREFIX << current_pid;
 
301
  post_tmpdir_str << session->thread_id << session->tmp_table++;
 
302
  tmp= post_tmpdir_str.str();
 
303
 
 
304
  transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
 
305
 
 
306
  path_str << tmp;
 
307
 
 
308
  if (bufflen < path_str.str().length())
 
309
    length= 0;
 
310
  else
 
311
    length= unpack_filename(buff, path_str.str().c_str());
 
312
 
 
313
  return length;
93
314
}
94
315
 
95
316
/*
107
328
    cursor
108
329
*/
109
330
 
110
 
void write_bin_log(Session *session, const std::string &query)
111
 
{
112
 
  TransactionServices &transaction_services= TransactionServices::singleton();
113
 
  transaction_services.rawStatement(session, query);
 
331
void write_bin_log(Session *session,
 
332
                   char const *query, size_t query_length)
 
333
{
 
334
  ReplicationServices &replication_services= ReplicationServices::singleton();
 
335
  replication_services.rawStatement(session, query, query_length);
 
336
}
 
337
 
 
338
 
 
339
/* Should should be refactored to go away */
 
340
void write_bin_log_drop_table(Session *session, bool if_exists, const char *db_name, const char *table_name)
 
341
{
 
342
  ReplicationServices &replication_services= ReplicationServices::singleton();
 
343
  string built_query;
 
344
 
 
345
  if (if_exists)
 
346
    built_query.append("DROP TABLE IF EXISTS ");
 
347
  else
 
348
    built_query.append("DROP TABLE ");
 
349
 
 
350
  built_query.append("`");
 
351
  if (session->db.empty() || strcmp(db_name, session->db.c_str()) != 0)
 
352
  {
 
353
    built_query.append(db_name);
 
354
    built_query.append("`.`");
 
355
  }
 
356
 
 
357
  built_query.append(table_name);
 
358
  built_query.append("`");
 
359
  replication_services.rawStatement(session, built_query.c_str(), built_query.length());
114
360
}
115
361
 
116
362
/*
124
370
                        In this case we give an warning of level 'NOTE'
125
371
    drop_temporary      Only drop temporary tables
126
372
 
127
 
  @todo
 
373
  TODO:
128
374
    When logging to the binary log, we should log
129
375
    tmp_tables and transactional tables as separate statements if we
130
376
    are in a transaction;  This is needed to get these tables into the
144
390
                         bool drop_temporary)
145
391
{
146
392
  TableList *table;
 
393
  char path[FN_REFLEN];
 
394
  uint32_t path_length= 0;
147
395
  String wrong_tables;
148
396
  int error= 0;
149
397
  bool foreign_key_error= false;
150
398
 
151
 
  {
152
 
    table::Cache::singleton().mutex().lock(); /* Part 2 of rm a table */
153
 
 
154
 
    if (not drop_temporary && session->lock_table_names_exclusively(tables))
155
 
    {
156
 
      table::Cache::singleton().mutex().unlock();
157
 
      return 1;
158
 
    }
159
 
 
160
 
    /* Don't give warnings for not found errors, as we already generate notes */
161
 
    session->no_warnings_for_error= 1;
162
 
 
163
 
    for (table= tables; table; table= table->next_local)
164
 
    {
165
 
      TableIdentifier tmp_identifier(table->getSchemaName(), table->getTableName());
166
 
 
167
 
      error= session->drop_temporary_table(tmp_identifier);
168
 
 
169
 
      switch (error) {
170
 
      case  0:
171
 
        // removed temporary table
172
 
        continue;
173
 
      case -1:
 
399
  pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
 
400
 
 
401
  /*
 
402
    If we have the table in the definition cache, we don't have to check the
 
403
    .frm cursor to find if the table is a normal table (not view) and what
 
404
    engine to use.
 
405
  */
 
406
 
 
407
  for (table= tables; table; table= table->next_local)
 
408
  {
 
409
    TableShare *share;
 
410
    table->db_type= NULL;
 
411
    if ((share= TableShare::getShare(table->db, table->table_name)))
 
412
      table->db_type= share->db_type();
 
413
  }
 
414
 
 
415
  if (!drop_temporary && lock_table_names_exclusively(session, tables))
 
416
  {
 
417
    pthread_mutex_unlock(&LOCK_open);
 
418
    return 1;
 
419
  }
 
420
 
 
421
  /* Don't give warnings for not found errors, as we already generate notes */
 
422
  session->no_warnings_for_error= 1;
 
423
 
 
424
  for (table= tables; table; table= table->next_local)
 
425
  {
 
426
    char *db=table->db;
 
427
    plugin::StorageEngine *table_type;
 
428
 
 
429
    error= session->drop_temporary_table(table);
 
430
 
 
431
    switch (error) {
 
432
    case  0:
 
433
      // removed temporary table
 
434
      continue;
 
435
    case -1:
 
436
      error= 1;
 
437
      goto err_with_placeholders;
 
438
    default:
 
439
      // temporary table not found
 
440
      error= 0;
 
441
    }
 
442
 
 
443
    table_type= table->db_type;
 
444
    if (drop_temporary == false)
 
445
    {
 
446
      Table *locked_table;
 
447
      abort_locked_tables(session, db, table->table_name);
 
448
      remove_table_from_cache(session, db, table->table_name,
 
449
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
450
                              RTFC_CHECK_KILLED_FLAG);
 
451
      /*
 
452
        If the table was used in lock tables, remember it so that
 
453
        unlock_table_names can free it
 
454
      */
 
455
      if ((locked_table= drop_locked_tables(session, db, table->table_name)))
 
456
        table->table= locked_table;
 
457
 
 
458
      if (session->killed)
 
459
      {
 
460
        error= -1;
 
461
        goto err_with_placeholders;
 
462
      }
 
463
      /* remove .frm cursor and engine files */
 
464
      path_length= build_table_filename(path, sizeof(path), db, table->table_name, table->internal_tmp_table);
 
465
    }
 
466
    TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? INTERNAL_TMP_TABLE : NO_TMP_TABLE);
 
467
 
 
468
    if (drop_temporary ||
 
469
        ((table_type == NULL
 
470
          && (plugin::StorageEngine::getTableDefinition(*session,
 
471
                                                        identifier) != EEXIST))))
 
472
    {
 
473
      // Table was not found on disk and table can't be created from engine
 
474
      if (if_exists)
 
475
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
476
                            ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 
477
                            table->table_name);
 
478
      else
174
479
        error= 1;
175
 
        goto err_with_placeholders;
176
 
      default:
177
 
        // temporary table not found
178
 
        error= 0;
179
 
      }
180
 
 
181
 
      if (drop_temporary == false)
182
 
      {
183
 
        Table *locked_table;
184
 
        abort_locked_tables(session, tmp_identifier);
185
 
        table::Cache::singleton().removeTable(session, tmp_identifier,
186
 
                                              RTFC_WAIT_OTHER_THREAD_FLAG |
187
 
                                              RTFC_CHECK_KILLED_FLAG);
188
 
        /*
189
 
          If the table was used in lock tables, remember it so that
190
 
          unlock_table_names can free it
191
 
        */
192
 
        if ((locked_table= drop_locked_tables(session, tmp_identifier)))
193
 
          table->table= locked_table;
194
 
 
195
 
        if (session->getKilled())
196
 
        {
197
 
          error= -1;
198
 
          goto err_with_placeholders;
199
 
        }
200
 
      }
201
 
      TableIdentifier identifier(table->getSchemaName(), table->getTableName(), table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
202
 
 
203
 
      if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
204
 
      {
205
 
        // Table was not found on disk and table can't be created from engine
206
 
        if (if_exists)
207
 
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
208
 
                              ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
209
 
                              table->getTableName());
210
 
        else
211
 
          error= 1;
212
 
      }
213
 
      else
214
 
      {
215
 
        error= plugin::StorageEngine::dropTable(*session, identifier);
216
 
 
217
 
        if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
218
 
        {
219
 
          error= 0;
220
 
          session->clear_error();
221
 
        }
222
 
 
223
 
        if (error == HA_ERR_ROW_IS_REFERENCED)
224
 
        {
225
 
          /* the table is referenced by a foreign key constraint */
226
 
          foreign_key_error= true;
227
 
        }
228
 
      }
229
 
 
230
 
      if (error == 0 || (if_exists && foreign_key_error == false))
231
 
      {
232
 
        TransactionServices &transaction_services= TransactionServices::singleton();
233
 
        transaction_services.dropTable(session, string(table->getSchemaName()), string(table->getTableName()), if_exists);
234
 
      }
235
 
 
236
 
      if (error)
237
 
      {
238
 
        if (wrong_tables.length())
239
 
          wrong_tables.append(',');
240
 
        wrong_tables.append(String(table->getTableName(), system_charset_info));
241
 
      }
242
 
    }
243
 
    /*
244
 
      It's safe to unlock table::Cache::singleton().mutex(): we have an exclusive lock
245
 
      on the table name.
246
 
    */
247
 
    table::Cache::singleton().mutex().unlock();
 
480
    }
 
481
    else
 
482
    {
 
483
      error= plugin::StorageEngine::dropTable(*session,
 
484
                                              identifier,
 
485
                                              true);
 
486
 
 
487
      if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
 
488
      {
 
489
        error= 0;
 
490
        session->clear_error();
 
491
      }
 
492
 
 
493
      if (error == HA_ERR_ROW_IS_REFERENCED)
 
494
      {
 
495
        /* the table is referenced by a foreign key constraint */
 
496
        foreign_key_error= true;
 
497
      }
 
498
    }
 
499
 
 
500
    if (error == 0 || (if_exists && foreign_key_error == false))
 
501
        write_bin_log_drop_table(session, if_exists, db, table->table_name);
 
502
 
 
503
    if (error)
 
504
    {
 
505
      if (wrong_tables.length())
 
506
        wrong_tables.append(',');
 
507
      wrong_tables.append(String(table->table_name,system_charset_info));
 
508
    }
248
509
  }
 
510
  /*
 
511
    It's safe to unlock LOCK_open: we have an exclusive lock
 
512
    on the table name.
 
513
  */
 
514
  pthread_mutex_unlock(&LOCK_open);
249
515
  error= 0;
250
 
 
251
516
  if (wrong_tables.length())
252
517
  {
253
 
    if (not foreign_key_error)
254
 
    {
 
518
    if (!foreign_key_error)
255
519
      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
256
520
                      wrong_tables.c_ptr());
257
 
    }
258
521
    else
259
522
    {
260
523
      my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
262
525
    error= 1;
263
526
  }
264
527
 
265
 
  table::Cache::singleton().mutex().lock(); /* final bit in rm table lock */
266
 
 
 
528
  pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
267
529
err_with_placeholders:
268
 
  tables->unlock_table_names();
269
 
  table::Cache::singleton().mutex().unlock();
 
530
  unlock_table_names(tables, NULL);
 
531
  pthread_mutex_unlock(&LOCK_open);
270
532
  session->no_warnings_for_error= 0;
271
533
 
272
 
  return error;
 
534
  return(error);
 
535
}
 
536
 
 
537
 
 
538
/*
 
539
  Quickly remove a table.
 
540
 
 
541
  SYNOPSIS
 
542
    quick_rm_table()
 
543
      base                      The plugin::StorageEngine handle.
 
544
      db                        The database name.
 
545
      table_name                The table name.
 
546
      is_tmp                    If the table is temp.
 
547
 
 
548
  RETURN
 
549
    0           OK
 
550
    != 0        Error
 
551
*/
 
552
 
 
553
bool quick_rm_table(Session& session, const char *db,
 
554
                    const char *table_name, bool is_tmp)
 
555
{
 
556
  bool error= 0;
 
557
 
 
558
  TableIdentifier identifier(db, table_name, is_tmp ? INTERNAL_TMP_TABLE : NO_TMP_TABLE);
 
559
 
 
560
  return (plugin::StorageEngine::dropTable(session, identifier, false)
 
561
          || error);
273
562
}
274
563
 
275
564
/*
285
574
  PRIMARY keys are prioritized.
286
575
*/
287
576
 
288
 
static int sort_keys(KeyInfo *a, KeyInfo *b)
 
577
static int sort_keys(KEY *a, KEY *b)
289
578
{
290
579
  ulong a_flags= a->flags, b_flags= b->flags;
291
580
 
337
626
    1             Error
338
627
*/
339
628
 
340
 
class typelib_set_member
341
 
{
342
 
public:
343
 
  string s;
344
 
  const CHARSET_INFO * const cs;
345
 
 
346
 
  typelib_set_member(const char* value, unsigned int length,
347
 
                     const CHARSET_INFO * const charset)
348
 
    : s(value, length),
349
 
      cs(charset)
350
 
  {}
351
 
};
352
 
 
353
 
static bool operator==(typelib_set_member const& a, typelib_set_member const& b)
354
 
{
355
 
  return (my_strnncoll(a.cs,
356
 
                       (const unsigned char*)a.s.c_str(), a.s.length(),
357
 
                       (const unsigned char*)b.s.c_str(), b.s.length())==0);
358
 
}
359
 
 
360
 
 
361
 
namespace
362
 
{
363
 
class typelib_set_member_hasher
364
 
{
365
 
  boost::hash<string> hasher;
366
 
public:
367
 
  std::size_t operator()(const typelib_set_member& t) const
368
 
  {
369
 
    return hasher(t.s);
370
 
  }
371
 
};
372
 
}
373
 
 
374
629
static bool check_duplicates_in_interval(const char *set_or_name,
375
630
                                         const char *name, TYPELIB *typelib,
376
631
                                         const CHARSET_INFO * const cs,
381
636
  unsigned int *cur_length= typelib->type_lengths;
382
637
  *dup_val_count= 0;
383
638
 
384
 
  boost::unordered_set<typelib_set_member, typelib_set_member_hasher> interval_set;
385
 
 
386
 
  for ( ; tmp.count > 0; cur_value++, cur_length++)
 
639
  for ( ; tmp.count > 1; cur_value++, cur_length++)
387
640
  {
388
641
    tmp.type_names++;
389
642
    tmp.type_lengths++;
390
643
    tmp.count--;
391
 
    if (interval_set.find(typelib_set_member(*cur_value, *cur_length, cs)) != interval_set.end())
 
644
    if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
392
645
    {
393
646
      my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
394
647
               name,*cur_value,set_or_name);
395
648
      return 1;
396
649
    }
397
 
    else
398
 
      interval_set.insert(typelib_set_member(*cur_value, *cur_length, cs));
399
650
  }
400
651
  return 0;
401
652
}
444
695
    sql_field     field to prepare for packing
445
696
    blob_columns  count for BLOBs
446
697
    timestamps    count for timestamps
 
698
    table_flags   table flags
447
699
 
448
700
  DESCRIPTION
449
701
    This function prepares a CreateField instance.
455
707
*/
456
708
int prepare_create_field(CreateField *sql_field,
457
709
                         uint32_t *blob_columns,
458
 
                         int *timestamps,
459
 
                         int *timestamps_with_niladic)
 
710
                         int *timestamps, int *timestamps_with_niladic,
 
711
                         int64_t )
460
712
{
461
713
  unsigned int dup_val_count;
462
714
 
468
720
 
469
721
  switch (sql_field->sql_type) {
470
722
  case DRIZZLE_TYPE_BLOB:
 
723
    sql_field->pack_flag= pack_length_to_packflag(sql_field->pack_length - portable_sizeof_char_ptr);
471
724
    sql_field->length= 8; // Unireg field length
472
725
    (*blob_columns)++;
473
726
    break;
474
727
  case DRIZZLE_TYPE_VARCHAR:
 
728
    sql_field->pack_flag=0;
475
729
    break;
476
730
  case DRIZZLE_TYPE_ENUM:
 
731
    sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length);
477
732
    if (check_duplicates_in_interval("ENUM",
478
733
                                     sql_field->field_name,
479
734
                                     sql_field->interval,
484
739
  case DRIZZLE_TYPE_DATE:  // Rest of string types
485
740
  case DRIZZLE_TYPE_DATETIME:
486
741
  case DRIZZLE_TYPE_NULL:
 
742
    sql_field->pack_flag=f_settype((uint32_t) sql_field->sql_type);
487
743
    break;
488
744
  case DRIZZLE_TYPE_DECIMAL:
 
745
    sql_field->pack_flag= 0;
489
746
    break;
490
747
  case DRIZZLE_TYPE_TIMESTAMP:
491
748
    /* We should replace old TIMESTAMP fields with their newer analogs */
497
754
        (*timestamps_with_niladic)++;
498
755
      }
499
756
      else
500
 
      {
501
757
        sql_field->unireg_check= Field::NONE;
502
 
      }
503
758
    }
504
759
    else if (sql_field->unireg_check != Field::NONE)
505
760
      (*timestamps_with_niladic)++;
507
762
    (*timestamps)++;
508
763
    /* fall-through */
509
764
  default:
 
765
    sql_field->pack_flag=(0 |
 
766
                          f_settype((uint32_t) sql_field->sql_type));
510
767
    break;
511
768
  }
512
 
 
513
769
  return 0;
514
770
}
515
771
 
516
 
static int mysql_prepare_create_table(Session *session,
517
 
                                      HA_CREATE_INFO *create_info,
518
 
                                      message::Table &create_proto,
519
 
                                      AlterInfo *alter_info,
520
 
                                      bool tmp_table,
521
 
                                      uint32_t *db_options,
522
 
                                      KeyInfo **key_info_buffer,
523
 
                                      uint32_t *key_count,
524
 
                                      int select_field_count)
 
772
int mysql_prepare_create_table(Session *session,
 
773
                               HA_CREATE_INFO *create_info,
 
774
                               message::Table *create_proto,
 
775
                               AlterInfo *alter_info,
 
776
                               bool tmp_table,
 
777
                               uint32_t *db_options,
 
778
                               Cursor *cursor,
 
779
                               KEY **key_info_buffer,
 
780
                               uint32_t *key_count,
 
781
                               int select_field_count)
525
782
{
526
783
  const char    *key_name;
527
784
  CreateField   *sql_field,*dup_field;
528
785
  uint          field,null_fields,blob_columns,max_key_length;
529
786
  ulong         record_offset= 0;
530
 
  KeyInfo               *key_info;
531
 
  KeyPartInfo *key_part_info;
 
787
  KEY           *key_info;
 
788
  KEY_PART_INFO *key_part_info;
532
789
  int           timestamps= 0, timestamps_with_niladic= 0;
533
790
  int           field_no,dup_no;
534
791
  int           select_field_pos,auto_increment=0;
536
793
  List_iterator<CreateField> it2(alter_info->create_list);
537
794
  uint32_t total_uneven_bit_length= 0;
538
795
 
539
 
  plugin::StorageEngine *engine= plugin::StorageEngine::findByName(create_proto.engine().name());
540
 
 
541
796
  select_field_pos= alter_info->create_list.elements - select_field_count;
542
797
  null_fields=blob_columns=0;
543
 
  max_key_length= engine->max_key_length();
 
798
  max_key_length= cursor->max_key_length();
544
799
 
545
800
  for (field_no=0; (sql_field=it++) ; field_no++)
546
801
  {
606
861
 
607
862
    if (sql_field->sql_type == DRIZZLE_TYPE_ENUM)
608
863
    {
609
 
      size_t dummy;
 
864
      uint32_t dummy;
610
865
      const CHARSET_INFO * const cs= sql_field->charset;
611
866
      TYPELIB *interval= sql_field->interval;
612
867
 
639
894
          if (String::needs_conversion(tmp->length(), tmp->charset(),
640
895
                                       cs, &dummy))
641
896
          {
642
 
            size_t cnv_errs;
 
897
            uint32_t cnv_errs;
643
898
            conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
644
 
            interval->type_names[i]= session->mem_root->strmake_root(conv.ptr(), conv.length());
 
899
            interval->type_names[i]= strmake_root(session->mem_root, conv.ptr(),
 
900
                                                  conv.length());
645
901
            interval->type_lengths[i]= conv.length();
646
902
          }
647
903
 
681
937
            }
682
938
          }
683
939
        }
684
 
        uint32_t new_dummy;
685
 
        calculate_interval_lengths(cs, interval, &field_length, &new_dummy);
 
940
        calculate_interval_lengths(cs, interval, &field_length, &dummy);
686
941
        sql_field->length= field_length;
687
942
      }
688
943
      set_if_smaller(sql_field->length, (uint32_t)MAX_FIELD_WIDTH-1);
746
1001
        }
747
1002
      }
748
1003
    }
749
 
 
750
 
    /** @todo Get rid of this MyISAM-specific crap. */
751
 
    if (not create_proto.engine().name().compare("MyISAM") &&
752
 
        ((sql_field->flags & BLOB_FLAG) ||
753
 
         (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
 
1004
    /* Don't pack rows in old tables if the user has requested this */
 
1005
    if ((sql_field->flags & BLOB_FLAG) ||
 
1006
        (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED))
754
1007
      (*db_options)|= HA_OPTION_PACK_RECORD;
755
1008
    it2.rewind();
756
1009
  }
765
1018
    assert(sql_field->charset != 0);
766
1019
 
767
1020
    if (prepare_create_field(sql_field, &blob_columns,
768
 
                             &timestamps, &timestamps_with_niladic))
 
1021
                             &timestamps, &timestamps_with_niladic,
 
1022
                             cursor->ha_table_flags()))
769
1023
      return(true);
770
1024
    sql_field->offset= record_offset;
771
1025
    if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
783
1037
    return(true);
784
1038
  }
785
1039
  if (auto_increment &&
786
 
      (engine->check_flag(HTON_BIT_NO_AUTO_INCREMENT)))
 
1040
      (cursor->ha_table_flags() & HA_NO_AUTO_INCREMENT))
787
1041
  {
788
1042
    my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
789
1043
               ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
790
1044
    return(true);
791
1045
  }
792
1046
 
793
 
  if (blob_columns && (engine->check_flag(HTON_BIT_NO_BLOBS)))
 
1047
  if (blob_columns && (cursor->ha_table_flags() & HA_NO_BLOBS))
794
1048
  {
795
1049
    my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
796
1050
               MYF(0));
818
1072
      fk_key_count++;
819
1073
      if (((Foreign_key *)key)->validate(alter_info->create_list))
820
1074
        return true;
821
 
 
822
1075
      Foreign_key *fk_key= (Foreign_key*) key;
823
 
 
824
 
      add_foreign_key_to_table_message(&create_proto,
825
 
                                       fk_key->name.str,
826
 
                                       fk_key->columns,
827
 
                                       fk_key->ref_table,
828
 
                                       fk_key->ref_columns,
829
 
                                       fk_key->delete_opt,
830
 
                                       fk_key->update_opt,
831
 
                                       fk_key->match_opt);
832
 
 
833
1076
      if (fk_key->ref_columns.elements &&
834
1077
          fk_key->ref_columns.elements != fk_key->columns.elements)
835
1078
      {
842
1085
      continue;
843
1086
    }
844
1087
    (*key_count)++;
845
 
    tmp= engine->max_key_parts();
 
1088
    tmp=cursor->max_key_parts();
846
1089
    if (key->columns.elements > tmp)
847
1090
    {
848
1091
      my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
864
1107
             key2->name.str != ignore_key &&
865
1108
             !foreign_key_prefix(key, key2)))
866
1109
        {
867
 
          /* @todo issue warning message */
 
1110
          /* TODO: issue warning message */
868
1111
          /* mark that the generated key should be ignored */
869
1112
          if (!key2->generated ||
870
1113
              (key->generated && key->columns.elements <
891
1134
      return(true);
892
1135
    }
893
1136
  }
894
 
  tmp= engine->max_keys();
 
1137
  tmp=cursor->max_keys();
895
1138
  if (*key_count > tmp)
896
1139
  {
897
1140
    my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
898
1141
    return(true);
899
1142
  }
900
1143
 
901
 
  (*key_info_buffer)= key_info= (KeyInfo*) memory::sql_calloc(sizeof(KeyInfo) * (*key_count));
902
 
  key_part_info=(KeyPartInfo*) memory::sql_calloc(sizeof(KeyPartInfo)*key_parts);
 
1144
  (*key_info_buffer)= key_info= (KEY*) sql_calloc(sizeof(KEY) * (*key_count));
 
1145
  key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
903
1146
  if (!*key_info_buffer || ! key_part_info)
904
1147
    return(true);                               // Out of memory
905
1148
 
939
1182
    key_info->usable_key_parts= key_number;
940
1183
    key_info->algorithm= key->key_create_info.algorithm;
941
1184
 
 
1185
    /* Take block size from key part or table part */
 
1186
    /*
 
1187
      TODO: Add warning if block size changes. We can't do it here, as
 
1188
      this may depend on the size of the key
 
1189
    */
 
1190
    key_info->block_size= (key->key_create_info.block_size ?
 
1191
                           key->key_create_info.block_size :
 
1192
                           create_proto->options().key_block_size());
 
1193
 
 
1194
    if (key_info->block_size)
 
1195
      key_info->flags|= HA_USES_BLOCK_SIZE;
 
1196
 
942
1197
    uint32_t tmp_len= system_charset_info->cset->charpos(system_charset_info,
943
1198
                                           key->key_create_info.comment.str,
944
1199
                                           key->key_create_info.comment.str +
984
1239
      while ((dup_column= cols2++) != column)
985
1240
      {
986
1241
        if (!my_strcasecmp(system_charset_info,
987
 
                           column->field_name.str, dup_column->field_name.str))
 
1242
                           column->field_name.str, dup_column->field_name.str))
988
1243
        {
989
1244
          my_printf_error(ER_DUP_FIELDNAME,
990
1245
                          ER(ER_DUP_FIELDNAME),MYF(0),
994
1249
      }
995
1250
      cols2.rewind();
996
1251
 
997
 
      if (create_proto.field_size() > 0)
998
 
        protofield= create_proto.mutable_field(proto_field_nr - 1);
 
1252
      if (create_proto->field_size() > 0)
 
1253
        protofield= create_proto->mutable_field(proto_field_nr - 1);
999
1254
 
1000
1255
      {
1001
1256
        column->length*= sql_field->charset->mbmaxlen;
1002
1257
 
1003
1258
        if (sql_field->sql_type == DRIZZLE_TYPE_BLOB)
1004
1259
        {
1005
 
          if (! (engine->check_flag(HTON_BIT_CAN_INDEX_BLOBS)))
 
1260
          if (! (cursor->ha_table_flags() & HA_CAN_INDEX_BLOBS))
1006
1261
          {
1007
1262
            my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str);
1008
1263
            return true;
1032
1287
          else
1033
1288
          {
1034
1289
            key_info->flags|= HA_NULL_PART_KEY;
1035
 
            if (! (engine->check_flag(HTON_BIT_NULL_IN_KEY)))
 
1290
            if (! (cursor->ha_table_flags() & HA_NULL_IN_KEY))
1036
1291
            {
1037
1292
              my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
1038
1293
              return true;
1041
1296
        }
1042
1297
        if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
1043
1298
        {
1044
 
          if (column_nr == 0 || (engine->check_flag(HTON_BIT_AUTO_PART_KEY)))
 
1299
          if (column_nr == 0 || (cursor->ha_table_flags() & HA_AUTO_PART_KEY))
1045
1300
            auto_increment--;                   // Field is used
1046
1301
        }
1047
1302
      }
1048
1303
 
1049
1304
      key_part_info->fieldnr= field;
1050
1305
      key_part_info->offset=  (uint16_t) sql_field->offset;
1051
 
      key_part_info->key_type= 0;
 
1306
      key_part_info->key_type=sql_field->pack_flag;
1052
1307
      length= sql_field->key_length;
1053
1308
 
1054
1309
      if (column->length)
1056
1311
        if (sql_field->sql_type == DRIZZLE_TYPE_BLOB)
1057
1312
        {
1058
1313
          if ((length=column->length) > max_key_length ||
1059
 
              length > engine->max_key_part_length())
 
1314
              length > cursor->max_key_part_length())
1060
1315
          {
1061
 
            length= min(max_key_length, engine->max_key_part_length());
 
1316
            length= min(max_key_length, cursor->max_key_part_length());
1062
1317
            if (key->type == Key::MULTIPLE)
1063
1318
            {
1064
1319
              /* not a critical problem */
1083
1338
          my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
1084
1339
          return(true);
1085
1340
        }
1086
 
        else if (! (engine->check_flag(HTON_BIT_NO_PREFIX_CHAR_KEYS)))
1087
 
        {
 
1341
        else if (!(cursor->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
1088
1342
          length=column->length;
1089
 
        }
1090
1343
      }
1091
1344
      else if (length == 0)
1092
1345
      {
1093
1346
        my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.str);
1094
1347
          return(true);
1095
1348
      }
1096
 
      if (length > engine->max_key_part_length())
 
1349
      if (length > cursor->max_key_part_length())
1097
1350
      {
1098
 
        length= engine->max_key_part_length();
 
1351
        length= cursor->max_key_part_length();
1099
1352
        if (key->type == Key::MULTIPLE)
1100
1353
        {
1101
1354
          /* not a critical problem */
1116
1369
      key_part_info->length=(uint16_t) length;
1117
1370
      /* Use packed keys for long strings on the first column */
1118
1371
      if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
1119
 
          (length >= KEY_DEFAULT_PACK_LENGTH &&
1120
 
           (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
1121
 
            sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
 
1372
          (length >= KEY_DEFAULT_PACK_LENGTH &&
 
1373
           (sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
 
1374
      sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
1122
1375
      {
1123
1376
        if ((column_nr == 0 && sql_field->sql_type == DRIZZLE_TYPE_BLOB) ||
1124
1377
            sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)
1125
 
        {
1126
1378
          key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
1127
 
        }
1128
1379
        else
1129
 
        {
1130
1380
          key_info->flags|= HA_PACK_KEY;
1131
 
        }
1132
1381
      }
1133
1382
      /* Check if the key segment is partial, set the key flag accordingly */
1134
1383
      if (length != sql_field->key_length)
1179
1428
    key_info++;
1180
1429
  }
1181
1430
  if (!unique_key && !primary_key &&
1182
 
      (engine->check_flag(HTON_BIT_REQUIRE_PRIMARY_KEY)))
 
1431
      (cursor->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
1183
1432
  {
1184
1433
    my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
1185
1434
    return(true);
1190
1439
    return(true);
1191
1440
  }
1192
1441
  /* Sort keys in optimized order */
1193
 
  internal::my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KeyInfo),
1194
 
                     (qsort_cmp) sort_keys);
 
1442
  my_qsort((unsigned char*) *key_info_buffer, *key_count, sizeof(KEY),
 
1443
           (qsort_cmp) sort_keys);
1195
1444
 
1196
1445
  /* Check fields. */
1197
1446
  it.rewind();
1264
1513
  return 0;
1265
1514
}
1266
1515
 
1267
 
static bool locked_create_event(Session *session,
1268
 
                                const TableIdentifier &identifier,
1269
 
                                HA_CREATE_INFO *create_info,
1270
 
                                message::Table &table_proto,
1271
 
                                AlterInfo *alter_info,
1272
 
                                bool is_if_not_exists,
1273
 
                                bool internal_tmp_table,
1274
 
                                uint db_options,
1275
 
                                uint key_count,
1276
 
                                KeyInfo *key_info_buffer)
1277
 
{
1278
 
  bool error= true;
1279
 
 
1280
 
  {
1281
 
 
1282
 
    /*
1283
 
      @note if we are building a temp table we need to check to see if a temp table
1284
 
      already exists, otherwise we just need to find out if a normal table exists (aka it is fine
1285
 
      to create a table under a temporary table.
1286
 
    */
1287
 
    bool exists= 
1288
 
      plugin::StorageEngine::doesTableExist(*session, identifier, 
1289
 
                                            identifier.getType() != message::Table::STANDARD );
1290
 
 
1291
 
    if (exists)
1292
 
    {
1293
 
      if (is_if_not_exists)
1294
 
      {
1295
 
        error= false;
1296
 
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1297
 
                            ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1298
 
                            identifier.getTableName().c_str());
1299
 
        create_info->table_existed= 1;          // Mark that table existed
1300
 
        return error;
1301
 
      }
1302
 
 
1303
 
      std::string path;
1304
 
      identifier.getSQLPath(path);
1305
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1306
 
 
1307
 
      return error;
1308
 
    }
1309
 
 
1310
 
    if (identifier.getType() == message::Table::STANDARD) // We have a real table
1311
 
    {
1312
 
      /*
1313
 
        We don't assert here, but check the result, because the table could be
1314
 
        in the table definition cache and in the same time the .frm could be
1315
 
        missing from the disk, in case of manual intervention which deletes
1316
 
        the .frm cursor. The user has to use FLUSH TABLES; to clear the cache.
1317
 
        Then she could create the table. This case is pretty obscure and
1318
 
        therefore we don't introduce a new error message only for it.
1319
 
      */
1320
 
      /*
1321
 
        @todo improve this error condition.
1322
 
      */
1323
 
      if (definition::Cache::singleton().find(identifier.getKey()))
1324
 
      {
1325
 
        std::string path;
1326
 
        identifier.getSQLPath(path);
1327
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1328
 
 
1329
 
        return error;
1330
 
      }
1331
 
    }
1332
 
  }
1333
 
 
1334
 
  session->set_proc_info("creating table");
1335
 
  create_info->table_existed= 0;                // Mark that table is created
1336
 
 
1337
 
  create_info->table_options= db_options;
1338
 
 
1339
 
  if (not rea_create_table(session, identifier,
1340
 
                           table_proto,
1341
 
                           create_info, alter_info->create_list,
1342
 
                           key_count, key_info_buffer))
1343
 
  {
1344
 
    return error;
1345
 
  }
1346
 
 
1347
 
  if (identifier.getType() == message::Table::TEMPORARY)
1348
 
  {
1349
 
    /* Open table and put in temporary table list */
1350
 
    if (not (session->open_temporary_table(identifier)))
1351
 
    {
1352
 
      (void) session->rm_temporary_table(identifier);
1353
 
      return error;
1354
 
    }
1355
 
  }
1356
 
 
1357
 
  /* 
1358
 
    We keep this behind the lock to make sure ordering is correct for a table.
1359
 
    This is a very unlikely problem where before we would write out to the
1360
 
    trans log, someone would do a delete/create operation.
1361
 
  */
1362
 
 
1363
 
  if (table_proto.type() == message::Table::STANDARD && not internal_tmp_table)
1364
 
  {
1365
 
    TransactionServices &transaction_services= TransactionServices::singleton();
1366
 
    transaction_services.createTable(session, table_proto);
1367
 
  }
1368
 
 
1369
 
  return false;
1370
 
}
1371
 
 
1372
1516
 
1373
1517
/*
1374
1518
  Ignore the name of this function... it locks :(
1401
1545
*/
1402
1546
 
1403
1547
bool mysql_create_table_no_lock(Session *session,
1404
 
                                const TableIdentifier &identifier,
 
1548
                                TableIdentifier &identifier,
1405
1549
                                HA_CREATE_INFO *create_info,
1406
 
                                message::Table &table_proto,
 
1550
                                message::Table *table_proto,
1407
1551
                                AlterInfo *alter_info,
1408
1552
                                bool internal_tmp_table,
1409
 
                                uint32_t select_field_count,
 
1553
                                uint32_t select_field_count, 
1410
1554
                                bool is_if_not_exists)
1411
1555
{
1412
1556
  uint          db_options, key_count;
1413
 
  KeyInfo               *key_info_buffer;
 
1557
  KEY           *key_info_buffer;
 
1558
  Cursor        *cursor;
1414
1559
  bool          error= true;
 
1560
  TableShare share;
 
1561
  bool lex_identified_temp_table= 
 
1562
    (table_proto->type() == drizzled::message::Table::TEMPORARY);
1415
1563
 
1416
1564
  /* Check for duplicate fields and check type of table to create */
1417
 
  if (not alter_info->create_list.elements)
 
1565
  if (!alter_info->create_list.elements)
1418
1566
  {
1419
1567
    my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
1420
1568
               MYF(0));
1421
1569
    return true;
1422
1570
  }
1423
 
  assert(identifier.getTableName() == table_proto.name());
 
1571
  assert(strcmp(identifier.getTableName(), table_proto->name().c_str())==0);
1424
1572
  db_options= create_info->table_options;
1425
 
 
1426
 
  set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1427
 
 
1428
 
  /* Build a Table object to pass down to the engine, and the do the actual create. */
1429
 
  if (not mysql_prepare_create_table(session, create_info, table_proto, alter_info,
1430
 
                                     internal_tmp_table,
1431
 
                                     &db_options,
1432
 
                                     &key_info_buffer, &key_count,
1433
 
                                     select_field_count))
1434
 
  {
1435
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* CREATE TABLE (some confussion on naming, double check) */
1436
 
    error= locked_create_event(session,
1437
 
                               identifier,
1438
 
                               create_info,
1439
 
                               table_proto,
1440
 
                               alter_info,
1441
 
                               is_if_not_exists,
1442
 
                               internal_tmp_table,
1443
 
                               db_options, key_count,
1444
 
                               key_info_buffer);
1445
 
  }
1446
 
 
1447
 
  session->set_proc_info("After create");
1448
 
 
1449
 
  return(error);
1450
 
}
1451
 
 
1452
 
/**
1453
 
  @note the following two methods implement create [temporary] table.
1454
 
*/
1455
 
static bool drizzle_create_table(Session *session,
1456
 
                                 const TableIdentifier &identifier,
1457
 
                                 HA_CREATE_INFO *create_info,
1458
 
                                 message::Table &table_proto,
1459
 
                                 AlterInfo *alter_info,
1460
 
                                 bool internal_tmp_table,
1461
 
                                 uint32_t select_field_count,
1462
 
                                 bool is_if_not_exists)
1463
 
{
1464
 
  Table *name_lock= NULL;
1465
 
  bool result;
1466
 
 
1467
 
  if (session->lock_table_name_if_not_cached(identifier, &name_lock))
1468
 
  {
1469
 
    result= true;
1470
 
  }
1471
 
  else if (name_lock == NULL)
 
1573
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
 
1574
    db_options|=HA_OPTION_PACK_RECORD;
 
1575
  if (!(cursor= create_info->db_type->getCursor(share, session->mem_root)))
 
1576
  {
 
1577
    my_error(ER_OUTOFMEMORY, MYF(0), sizeof(Cursor));
 
1578
    return true;
 
1579
  }
 
1580
 
 
1581
  set_table_default_charset(create_info, identifier.getDBName());
 
1582
 
 
1583
  /* Check if table exists */
 
1584
  if (mysql_prepare_create_table(session, create_info, table_proto, alter_info,
 
1585
                                 internal_tmp_table,
 
1586
                                 &db_options, cursor,
 
1587
                                 &key_info_buffer, &key_count,
 
1588
                                 select_field_count))
 
1589
    goto err;
 
1590
 
 
1591
  /* Check if table already exists */
 
1592
  if (lex_identified_temp_table &&
 
1593
      session->find_temporary_table(identifier.getDBName(), identifier.getTableName()))
1472
1594
  {
1473
1595
    if (is_if_not_exists)
1474
1596
    {
 
1597
      create_info->table_existed= 1;            // Mark that table existed
1475
1598
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1476
1599
                          ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1477
 
                          identifier.getTableName().c_str());
1478
 
      create_info->table_existed= 1;
1479
 
      result= false;
1480
 
    }
1481
 
    else
1482
 
    {
1483
 
      std::string path;
1484
 
      identifier.getSQLPath(path);
1485
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1486
 
      result= true;
1487
 
    }
1488
 
  }
1489
 
  else
1490
 
  {
1491
 
    result= mysql_create_table_no_lock(session,
1492
 
                                       identifier,
1493
 
                                       create_info,
1494
 
                                       table_proto,
1495
 
                                       alter_info,
1496
 
                                       internal_tmp_table,
1497
 
                                       select_field_count,
1498
 
                                       is_if_not_exists);
1499
 
  }
1500
 
 
1501
 
  if (name_lock)
1502
 
  {
1503
 
    boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* Lock for removing name_lock during table create */
1504
 
    session->unlink_open_table(name_lock);
1505
 
  }
1506
 
 
1507
 
  return(result);
 
1600
                          identifier.getTableName());
 
1601
      error= 0;
 
1602
      goto err;
 
1603
    }
 
1604
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getTableName());
 
1605
    goto err;
 
1606
  }
 
1607
 
 
1608
  pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
 
1609
  if (!internal_tmp_table && ! lex_identified_temp_table)
 
1610
  {
 
1611
    if (plugin::StorageEngine::getTableDefinition(*session,
 
1612
                                                  identifier)==EEXIST)
 
1613
    {
 
1614
      if (is_if_not_exists)
 
1615
      {
 
1616
        error= false;
 
1617
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
1618
                            ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
 
1619
                            identifier.getTableName());
 
1620
        create_info->table_existed= 1;          // Mark that table existed
 
1621
      }
 
1622
      else 
 
1623
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getTableName());
 
1624
 
 
1625
      goto unlock_and_end;
 
1626
    }
 
1627
    /*
 
1628
      We don't assert here, but check the result, because the table could be
 
1629
      in the table definition cache and in the same time the .frm could be
 
1630
      missing from the disk, in case of manual intervention which deletes
 
1631
      the .frm cursor. The user has to use FLUSH TABLES; to clear the cache.
 
1632
      Then she could create the table. This case is pretty obscure and
 
1633
      therefore we don't introduce a new error message only for it.
 
1634
    */
 
1635
    if (TableShare::getShare(identifier.getDBName(), identifier.getTableName()))
 
1636
    {
 
1637
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getTableName());
 
1638
      goto unlock_and_end;
 
1639
    }
 
1640
  }
 
1641
 
 
1642
  /*
 
1643
    Check that table with given name does not already
 
1644
    exist in any storage engine. In such a case it should
 
1645
    be discovered and the error ER_TABLE_EXISTS_ERROR be returned
 
1646
    unless user specified CREATE TABLE IF EXISTS
 
1647
    The LOCK_open mutex has been locked to make sure no
 
1648
    one else is attempting to discover the table. Since
 
1649
    it's not on disk as a frm cursor, no one could be using it!
 
1650
  */
 
1651
  if (! lex_identified_temp_table)
 
1652
  {
 
1653
    int retcode= plugin::StorageEngine::getTableDefinition(*session, identifier);
 
1654
 
 
1655
    switch (retcode)
 
1656
    {
 
1657
      case ENOENT:
 
1658
        /* Normal case, no table exists. we can go and create it */
 
1659
        break;
 
1660
      case EEXIST:
 
1661
        if (is_if_not_exists)
 
1662
        {
 
1663
          error= false;
 
1664
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
1665
                              ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
 
1666
                              identifier.getTableName());
 
1667
          create_info->table_existed= 1;                // Mark that table existed
 
1668
          goto unlock_and_end;
 
1669
        }
 
1670
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getTableName());
 
1671
        goto unlock_and_end;
 
1672
      default:
 
1673
        my_error(retcode, MYF(0), identifier.getTableName());
 
1674
        goto unlock_and_end;
 
1675
    }
 
1676
  }
 
1677
 
 
1678
  session->set_proc_info("creating table");
 
1679
  create_info->table_existed= 0;                // Mark that table is created
 
1680
 
 
1681
  create_info->table_options=db_options;
 
1682
 
 
1683
  if (rea_create_table(session, identifier,
 
1684
                       table_proto,
 
1685
                       create_info, alter_info->create_list,
 
1686
                       key_count, key_info_buffer))
 
1687
    goto unlock_and_end;
 
1688
 
 
1689
  if (lex_identified_temp_table)
 
1690
  {
 
1691
    /* Open table and put in temporary table list */
 
1692
    if (!(session->open_temporary_table(identifier)))
 
1693
    {
 
1694
      (void) session->rm_temporary_table(create_info->db_type, identifier);
 
1695
      goto unlock_and_end;
 
1696
    }
 
1697
  }
 
1698
 
 
1699
  /*
 
1700
    Don't write statement if:
 
1701
    - It is an internal temporary table,
 
1702
    - Row-based logging is used and it we are creating a temporary table, or
 
1703
    - The binary log is not open.
 
1704
    Otherwise, the statement shall be binlogged.
 
1705
   */
 
1706
  if (!internal_tmp_table && ! lex_identified_temp_table)
 
1707
    write_bin_log(session, session->query, session->query_length);
 
1708
  error= false;
 
1709
unlock_and_end:
 
1710
  pthread_mutex_unlock(&LOCK_open);
 
1711
 
 
1712
err:
 
1713
  session->set_proc_info("After create");
 
1714
  delete cursor;
 
1715
  return(error);
1508
1716
}
1509
1717
 
1510
1718
 
1511
1719
/*
1512
1720
  Database locking aware wrapper for mysql_create_table_no_lock(),
1513
1721
*/
 
1722
 
1514
1723
bool mysql_create_table(Session *session,
1515
 
                        const TableIdentifier &identifier,
 
1724
                        TableIdentifier &identifier,
1516
1725
                        HA_CREATE_INFO *create_info,
1517
 
                        message::Table &table_proto,
 
1726
                        message::Table *table_proto,
1518
1727
                        AlterInfo *alter_info,
1519
1728
                        bool internal_tmp_table,
1520
1729
                        uint32_t select_field_count,
1521
1730
                        bool is_if_not_exists)
1522
1731
{
1523
 
  if (identifier.isTmp())
1524
 
  {
1525
 
    return mysql_create_table_no_lock(session,
1526
 
                                      identifier,
1527
 
                                      create_info,
1528
 
                                      table_proto,
1529
 
                                      alter_info,
1530
 
                                      internal_tmp_table,
1531
 
                                      select_field_count,
1532
 
                                      is_if_not_exists);
1533
 
  }
1534
 
 
1535
 
  return drizzle_create_table(session,
1536
 
                              identifier,
1537
 
                              create_info,
1538
 
                              table_proto,
1539
 
                              alter_info,
1540
 
                              internal_tmp_table,
1541
 
                              select_field_count,
1542
 
                              is_if_not_exists);
 
1732
  Table *name_lock= NULL;
 
1733
  bool result;
 
1734
  bool lex_identified_temp_table=
 
1735
    (table_proto->type() == drizzled::message::Table::TEMPORARY);
 
1736
 
 
1737
  if (! lex_identified_temp_table)
 
1738
  {
 
1739
    if (session->lock_table_name_if_not_cached(identifier.getDBName(),
 
1740
                                               identifier.getTableName(),
 
1741
                                               &name_lock))
 
1742
    {
 
1743
      result= true;
 
1744
      goto unlock;
 
1745
    }
 
1746
    if (name_lock == NULL)
 
1747
    {
 
1748
      if (is_if_not_exists)
 
1749
      {
 
1750
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
1751
                            ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
 
1752
                            identifier.getTableName());
 
1753
        create_info->table_existed= 1;
 
1754
        result= false;
 
1755
      }
 
1756
      else
 
1757
      {
 
1758
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getTableName());
 
1759
        result= true;
 
1760
      }
 
1761
      goto unlock;
 
1762
    }
 
1763
  }
 
1764
 
 
1765
  result= mysql_create_table_no_lock(session,
 
1766
                                     identifier,
 
1767
                                     create_info,
 
1768
                                     table_proto,
 
1769
                                     alter_info,
 
1770
                                     internal_tmp_table,
 
1771
                                     select_field_count,
 
1772
                                     is_if_not_exists);
 
1773
 
 
1774
unlock:
 
1775
  if (name_lock)
 
1776
  {
 
1777
    pthread_mutex_lock(&LOCK_open); /* Lock for removing name_lock during table create */
 
1778
    session->unlink_open_table(name_lock);
 
1779
    pthread_mutex_unlock(&LOCK_open);
 
1780
  }
 
1781
 
 
1782
  return(result);
1543
1783
}
1544
1784
 
1545
1785
 
1548
1788
**/
1549
1789
 
1550
1790
static bool
1551
 
check_if_keyname_exists(const char *name, KeyInfo *start, KeyInfo *end)
 
1791
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
1552
1792
{
1553
 
  for (KeyInfo *key=start ; key != end ; key++)
 
1793
  for (KEY *key=start ; key != end ; key++)
1554
1794
    if (!my_strcasecmp(system_charset_info,name,key->name))
1555
1795
      return 1;
1556
1796
  return 0;
1558
1798
 
1559
1799
 
1560
1800
static char *
1561
 
make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end)
 
1801
make_unique_key_name(const char *field_name,KEY *start,KEY *end)
1562
1802
{
1563
1803
  char buff[MAX_FIELD_NAME],*buff_end;
1564
1804
 
1576
1816
  for (uint32_t i=2 ; i< 100; i++)
1577
1817
  {
1578
1818
    *buff_end= '_';
1579
 
    internal::int10_to_str(i, buff_end+1, 10);
 
1819
    int10_to_str(i, buff_end+1, 10);
1580
1820
    if (!check_if_keyname_exists(buff,start,end))
1581
 
      return memory::sql_strdup(buff);
 
1821
      return sql_strdup(buff);
1582
1822
  }
1583
1823
  return (char*) "not_specified";               // Should never happen
1584
1824
}
1593
1833
 
1594
1834
  SYNOPSIS
1595
1835
    mysql_rename_table()
1596
 
      session
1597
1836
      base                      The plugin::StorageEngine handle.
1598
1837
      old_db                    The old database name.
1599
1838
      old_name                  The old table name.
1600
1839
      new_db                    The new database name.
1601
1840
      new_name                  The new table name.
 
1841
      flags                     flags for build_table_filename().
 
1842
                                FN_FROM_IS_TMP old_name is temporary.
 
1843
                                FN_TO_IS_TMP   new_name is temporary.
1602
1844
 
1603
1845
  RETURN
1604
1846
    false   OK
1606
1848
*/
1607
1849
 
1608
1850
bool
1609
 
mysql_rename_table(Session &session,
1610
 
                   plugin::StorageEngine *base,
1611
 
                   const TableIdentifier &from,
1612
 
                   const TableIdentifier &to)
 
1851
mysql_rename_table(plugin::StorageEngine *base, const char *old_db,
 
1852
                   const char *old_name, const char *new_db,
 
1853
                   const char *new_name, uint32_t flags)
1613
1854
{
 
1855
  Session *session= current_session;
 
1856
  char from[FN_REFLEN], to[FN_REFLEN];
 
1857
  char *from_base= from, *to_base= to;
1614
1858
  int error= 0;
1615
1859
 
1616
1860
  assert(base);
1617
1861
 
1618
 
  if (not plugin::StorageEngine::doesSchemaExist(to))
 
1862
  build_table_filename(from, sizeof(from), old_db, old_name,
 
1863
                       flags & FN_FROM_IS_TMP);
 
1864
  build_table_filename(to, sizeof(to), new_db, new_name,
 
1865
                       flags & FN_TO_IS_TMP);
 
1866
 
 
1867
  if (!(error= base->renameTable(session, from_base, to_base)))
1619
1868
  {
1620
 
    my_error(ER_NO_DB_ERROR, MYF(0), to.getSchemaName().c_str());
1621
 
    return true;
 
1869
    if (base->check_flag(HTON_BIT_HAS_DATA_DICTIONARY) == 0
 
1870
       && rename_table_proto_file(from_base, to_base))
 
1871
    {
 
1872
      error= my_errno;
 
1873
      base->renameTable(session, to_base, from_base);
 
1874
    }
1622
1875
  }
1623
1876
 
1624
 
  error= base->renameTable(session, from, to);
1625
 
 
1626
1877
  if (error == HA_ERR_WRONG_COMMAND)
1627
 
  {
1628
1878
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER Table");
1629
 
  }
1630
1879
  else if (error)
1631
 
  {
1632
 
    std::string from_path;
1633
 
    std::string to_path;
1634
 
 
1635
 
    from.getSQLPath(from_path);
1636
 
    to.getSQLPath(to_path);
1637
 
 
1638
 
    const char *from_identifier= from.isTmp() ? "#sql-temporary" : from_path.c_str();
1639
 
    const char *to_identifier= to.isTmp() ? "#sql-temporary" : to_path.c_str();
1640
 
 
1641
 
    my_error(ER_ERROR_ON_RENAME, MYF(0), from_identifier, to_identifier, error);
1642
 
  }
1643
 
 
1644
 
  return error ? true : false; 
 
1880
    my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
 
1881
  return(error != 0);
1645
1882
}
1646
1883
 
1647
1884
 
1660
1897
   the table is closed.
1661
1898
 
1662
1899
  PREREQUISITES
1663
 
    Lock on table::Cache::singleton().mutex()
 
1900
    Lock on LOCK_open
1664
1901
    Win32 clients must also have a WRITE LOCK on the table !
1665
1902
*/
1666
1903
 
1668
1905
                              enum ha_extra_function function)
1669
1906
{
1670
1907
 
1671
 
  safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
 
1908
  safe_mutex_assert_owner(&LOCK_open);
1672
1909
 
1673
1910
  table->cursor->extra(function);
1674
1911
  /* Mark all tables that are in use as 'old' */
1675
 
  session->abortLock(table);    /* end threads waiting on lock */
 
1912
  mysql_lock_abort(session, table);     /* end threads waiting on lock */
1676
1913
 
1677
1914
  /* Wait until all there are no other threads that has this table open */
1678
 
  TableIdentifier identifier(table->getShare()->getSchemaName(), table->getShare()->getTableName());
1679
 
  table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
 
1915
  remove_table_from_cache(session, table->s->db.str,
 
1916
                          table->s->table_name.str,
 
1917
                          RTFC_WAIT_OTHER_THREAD_FLAG);
1680
1918
}
1681
1919
 
1682
1920
/*
1692
1930
    reopen the table.
1693
1931
 
1694
1932
  PREREQUISITES
1695
 
    Lock on table::Cache::singleton().mutex()
 
1933
    Lock on LOCK_open
1696
1934
    Win32 clients must also have a WRITE LOCK on the table !
1697
1935
*/
1698
1936
 
1703
1941
  /* Close lock if this is not got with LOCK TABLES */
1704
1942
  if (lock)
1705
1943
  {
1706
 
    unlockTables(lock);
 
1944
    mysql_unlock_tables(this, lock);
1707
1945
    lock= NULL;                 // Start locked threads
1708
1946
  }
1709
1947
  /* Close all copies of 'table'.  This also frees all LOCK TABLES lock */
1710
1948
  unlink_open_table(table);
1711
1949
 
1712
 
  /* When lock on table::Cache::singleton().mutex() is freed other threads can continue */
1713
 
  locking::broadcast_refresh();
 
1950
  /* When lock on LOCK_open is freed other threads can continue */
 
1951
  broadcast_refresh();
1714
1952
}
1715
1953
 
1716
1954
/*
1724
1962
                              const char *operator_name,
1725
1963
                              thr_lock_type lock_type,
1726
1964
                              bool open_for_modify,
 
1965
                              bool no_warnings_for_error,
 
1966
                              uint32_t extra_open_options,
 
1967
                              int (*prepare_func)(Session *, TableList *,
 
1968
                                                  HA_CHECK_OPT *),
1727
1969
                              int (Cursor::*operator_func)(Session *,
1728
1970
                                                            HA_CHECK_OPT *))
1729
1971
{
1733
1975
  Item *item;
1734
1976
  LEX *lex= session->lex;
1735
1977
  int result_code= 0;
1736
 
  TransactionServices &transaction_services= TransactionServices::singleton();
1737
1978
  const CHARSET_INFO * const cs= system_charset_info;
1738
1979
 
1739
1980
  if (! session->endActiveTransaction())
1754
1995
  for (table= tables; table; table= table->next_local)
1755
1996
  {
1756
1997
    char table_name[NAME_LEN*2+2];
 
1998
    char* db = table->db;
1757
1999
    bool fatal_error=0;
1758
2000
 
1759
 
    snprintf(table_name, sizeof(table_name), "%s.%s", table->getSchemaName(), table->getTableName());
 
2001
    sprintf(table_name,"%s.%s",db,table->table_name);
 
2002
    session->open_options|= extra_open_options;
1760
2003
    table->lock_type= lock_type;
1761
2004
    /* open only one table from local list of command */
1762
2005
    {
1769
2012
      /*
1770
2013
        Time zone tables and SP tables can be add to lex->query_tables list,
1771
2014
        so it have to be prepared.
1772
 
        @todo Investigate if we can put extra tables into argument instead of using lex->query_tables
 
2015
        TODO: Investigate if we can put extra tables into argument instead of
 
2016
        using lex->query_tables
1773
2017
      */
1774
2018
      lex->query_tables= table;
1775
2019
      lex->query_tables_last= &table->next_global;
1776
2020
      lex->query_tables_own_last= 0;
1777
 
      session->no_warnings_for_error= 0;
 
2021
      session->no_warnings_for_error= no_warnings_for_error;
1778
2022
 
1779
2023
      session->openTablesLock(table);
1780
2024
      session->no_warnings_for_error= 0;
1781
2025
      table->next_global= save_next_global;
1782
2026
      table->next_local= save_next_local;
 
2027
      session->open_options&= ~extra_open_options;
 
2028
    }
 
2029
 
 
2030
    if (prepare_func)
 
2031
    {
 
2032
      switch ((*prepare_func)(session, table, check_opt)) {
 
2033
      case  1:           // error, message written to net
 
2034
        ha_autocommit_or_rollback(session, 1);
 
2035
        session->endTransaction(ROLLBACK);
 
2036
        session->close_thread_tables();
 
2037
        continue;
 
2038
      case -1:           // error, message could be written to net
 
2039
        goto err;
 
2040
      default:           // should be 0 otherwise
 
2041
        ;
 
2042
      }
1783
2043
    }
1784
2044
 
1785
2045
    /*
1809
2069
      length= snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
1810
2070
                       table_name);
1811
2071
      session->client->store(buff, length);
1812
 
      transaction_services.autocommitOrRollback(session, false);
 
2072
      ha_autocommit_or_rollback(session, 0);
1813
2073
      session->endTransaction(COMMIT);
1814
2074
      session->close_thread_tables();
1815
2075
      lex->reset_query_tables_list(false);
1820
2080
    }
1821
2081
 
1822
2082
    /* Close all instances of the table to allow repair to rename files */
1823
 
    if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
 
2083
    if (lock_type == TL_WRITE && table->table->s->version)
1824
2084
    {
1825
 
      table::Cache::singleton().mutex().lock(); /* Lock type is TL_WRITE and we lock to repair the table */
1826
 
      const char *old_message=session->enter_cond(COND_refresh, table::Cache::singleton().mutex(),
1827
 
                                                  "Waiting to get writelock");
1828
 
      session->abortLock(table->table);
1829
 
      TableIdentifier identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1830
 
      table::Cache::singleton().removeTable(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG);
 
2085
      pthread_mutex_lock(&LOCK_open); /* Lock type is TL_WRITE and we lock to repair the table */
 
2086
      const char *old_message=session->enter_cond(&COND_refresh, &LOCK_open,
 
2087
                                              "Waiting to get writelock");
 
2088
      mysql_lock_abort(session,table->table);
 
2089
      remove_table_from_cache(session, table->table->s->db.str,
 
2090
                              table->table->s->table_name.str,
 
2091
                              RTFC_WAIT_OTHER_THREAD_FLAG |
 
2092
                              RTFC_CHECK_KILLED_FLAG);
1831
2093
      session->exit_cond(old_message);
1832
 
      if (session->getKilled())
 
2094
      if (session->killed)
1833
2095
        goto err;
1834
2096
      open_for_modify= 0;
1835
2097
    }
1836
2098
 
 
2099
    if (table->table->s->crashed && operator_func == &Cursor::ha_check)
 
2100
    {
 
2101
      session->client->store(table_name);
 
2102
      session->client->store(operator_name);
 
2103
      session->client->store(STRING_WITH_LEN("warning"));
 
2104
      session->client->store(STRING_WITH_LEN("Table is marked as crashed"));
 
2105
      if (session->client->flush())
 
2106
        goto err;
 
2107
    }
 
2108
 
1837
2109
    result_code = (table->table->cursor->*operator_func)(session, check_opt);
1838
2110
 
1839
2111
send_result:
1916
2188
    if (table->table)
1917
2189
    {
1918
2190
      if (fatal_error)
1919
 
      {
1920
 
        table->table->getMutableShare()->resetVersion();               // Force close of table
1921
 
      }
 
2191
        table->table->s->version=0;               // Force close of table
1922
2192
      else if (open_for_modify)
1923
2193
      {
1924
 
        if (table->table->getShare()->getType())
1925
 
        {
 
2194
        if (table->table->s->tmp_table)
1926
2195
          table->table->cursor->info(HA_STATUS_CONST);
1927
 
        }
1928
2196
        else
1929
2197
        {
1930
 
          boost::unique_lock<boost::mutex> lock(table::Cache::singleton().mutex());
1931
 
          TableIdentifier identifier(table->table->getShare()->getSchemaName(), table->table->getShare()->getTableName());
1932
 
          table::Cache::singleton().removeTable(session, identifier, RTFC_NO_FLAG);
 
2198
          pthread_mutex_lock(&LOCK_open);
 
2199
          remove_table_from_cache(session, table->table->s->db.str,
 
2200
                                  table->table->s->table_name.str, RTFC_NO_FLAG);
 
2201
          pthread_mutex_unlock(&LOCK_open);
1933
2202
        }
1934
2203
      }
1935
2204
    }
1936
 
    transaction_services.autocommitOrRollback(session, false);
 
2205
    ha_autocommit_or_rollback(session, 0);
1937
2206
    session->endTransaction(COMMIT);
1938
2207
    session->close_thread_tables();
1939
2208
    table->table=0;                             // For query cache
1945
2214
  return(false);
1946
2215
 
1947
2216
err:
1948
 
  transaction_services.autocommitOrRollback(session, true);
 
2217
  ha_autocommit_or_rollback(session, 1);
1949
2218
  session->endTransaction(ROLLBACK);
1950
2219
  session->close_thread_tables();                       // Shouldn't be needed
1951
2220
  if (table)
1953
2222
  return(true);
1954
2223
}
1955
2224
 
1956
 
  /*
1957
 
    Create a new table by copying from source table
1958
 
 
1959
 
    Altough exclusive name-lock on target table protects us from concurrent
1960
 
    DML and DDL operations on it we still want to wrap .FRM creation and call
1961
 
    to plugin::StorageEngine::createTable() in critical section protected by
1962
 
    table::Cache::singleton().mutex() in order to provide minimal atomicity against operations which
1963
 
    disregard name-locks, like I_S implementation, for example. This is a
1964
 
    temporary and should not be copied. Instead we should fix our code to
1965
 
    always honor name-locks.
1966
 
 
1967
 
    Also some engines (e.g. NDB cluster) require that table::Cache::singleton().mutex() should be held
1968
 
    during the call to plugin::StorageEngine::createTable().
1969
 
    See bug #28614 for more info.
1970
 
  */
1971
 
static bool create_table_wrapper(Session &session, const message::Table& create_table_proto,
1972
 
                                 const TableIdentifier &destination_identifier,
1973
 
                                 const TableIdentifier &src_table,
1974
 
                                 bool is_engine_set)
1975
 
{
1976
 
  int protoerr= EEXIST;
1977
 
  message::Table new_proto;
1978
 
  message::table::shared_ptr src_proto;
1979
 
 
1980
 
  protoerr= plugin::StorageEngine::getTableDefinition(session,
1981
 
                                                      src_table,
1982
 
                                                      src_proto);
1983
 
  new_proto.CopyFrom(*src_proto);
1984
 
 
1985
 
  if (destination_identifier.isTmp())
1986
 
  {
1987
 
    new_proto.set_type(message::Table::TEMPORARY);
1988
 
  }
1989
 
  else
1990
 
  {
1991
 
    new_proto.set_type(message::Table::STANDARD);
1992
 
  }
1993
 
 
1994
 
  if (is_engine_set)
1995
 
  {
1996
 
    new_proto.mutable_engine()->set_name(create_table_proto.engine().name());
1997
 
  }
1998
 
 
1999
 
  { // We now do a selective copy of elements on to the new table.
2000
 
    new_proto.set_name(create_table_proto.name());
2001
 
    new_proto.set_schema(create_table_proto.schema());
2002
 
    new_proto.set_catalog(create_table_proto.catalog());
2003
 
  }
2004
 
 
2005
 
  if (protoerr && protoerr != EEXIST)
2006
 
  {
2007
 
    if (errno == ENOENT)
2008
 
      my_error(ER_BAD_DB_ERROR,MYF(0), destination_identifier.getSchemaName().c_str());
2009
 
    else
2010
 
      my_error(ER_CANT_CREATE_FILE, MYF(0), destination_identifier.getPath().c_str(), errno);
2011
 
 
2012
 
    return false;
2013
 
  }
2014
 
 
2015
 
  /*
2016
 
    As mysql_truncate don't work on a new table at this stage of
2017
 
    creation, instead create the table directly (for both normal
2018
 
    and temporary tables).
2019
 
  */
2020
 
  int err= plugin::StorageEngine::createTable(session,
2021
 
                                              destination_identifier,
2022
 
                                              new_proto);
2023
 
 
2024
 
  if (err == false && not destination_identifier.isTmp())
2025
 
  {
2026
 
    TransactionServices &transaction_services= TransactionServices::singleton();
2027
 
    transaction_services.createTable(&session, new_proto);
2028
 
  }
2029
 
 
2030
 
  return err ? false : true;
2031
 
}
2032
 
 
2033
2225
/*
2034
2226
  Create a table identical to the specified table
2035
2227
 
2045
2237
    true  error
2046
2238
*/
2047
2239
 
2048
 
bool mysql_create_like_table(Session* session,
2049
 
                             const TableIdentifier &destination_identifier,
2050
 
                             TableList* table, TableList* src_table,
2051
 
                             message::Table &create_table_proto,
 
2240
bool mysql_create_like_table(Session* session, TableList* table, TableList* src_table,
 
2241
                             drizzled::message::Table& create_table_proto,
 
2242
                             drizzled::plugin::StorageEngine *engine_arg,
2052
2243
                             bool is_if_not_exists,
2053
2244
                             bool is_engine_set)
2054
2245
{
 
2246
  Table *name_lock= 0;
 
2247
  char src_path[FN_REFLEN];
 
2248
  char *db= table->db;
 
2249
  char *table_name= table->table_name;
 
2250
  int  err;
2055
2251
  bool res= true;
2056
2252
  uint32_t not_used;
 
2253
  message::Table src_proto;
 
2254
  bool lex_identified_temp_table=
 
2255
    (create_table_proto.type() == drizzled::message::Table::TEMPORARY);
2057
2256
 
2058
2257
  /*
2059
2258
    By opening source table we guarantee that it exists and no concurrent
2067
2266
  if (session->open_tables_from_list(&src_table, &not_used))
2068
2267
    return true;
2069
2268
 
2070
 
  TableIdentifier src_identifier(src_table->table->getShare()->getSchemaName(),
2071
 
                                 src_table->table->getShare()->getTableName(), src_table->table->getShare()->getType());
2072
 
 
2073
 
 
 
2269
  strncpy(src_path, src_table->table->s->path.str, sizeof(src_path));
 
2270
 
 
2271
 
 
2272
  TableIdentifier destination_identifier(db, table_name, lex_identified_temp_table ?
 
2273
                                         (engine_arg->check_flag(HTON_BIT_DOES_TRANSACTIONS) ? TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE) :
 
2274
                                         NO_TMP_TABLE);
2074
2275
 
2075
2276
  /*
2076
2277
    Check that destination tables does not exist. Note that its name
2077
2278
    was already checked when it was added to the table list.
2078
 
 
2079
 
    For temporary tables we don't aim to grab locks.
2080
 
  */
2081
 
  bool table_exists= false;
2082
 
  if (destination_identifier.isTmp())
2083
 
  {
2084
 
    if (session->find_temporary_table(destination_identifier))
2085
 
    {
2086
 
      table_exists= true;
2087
 
    }
2088
 
    else
2089
 
    {
2090
 
      bool was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2091
 
                                             src_identifier, is_engine_set);
2092
 
      if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2093
 
      {
2094
 
        (void) session->rm_temporary_table(destination_identifier, true);
2095
 
      }
2096
 
      else if (not session->open_temporary_table(destination_identifier))
2097
 
      {
2098
 
        // We created, but we can't open... also, a hack.
2099
 
        (void) session->rm_temporary_table(destination_identifier, true);
2100
 
      }
2101
 
      else
2102
 
      {
2103
 
        res= false;
2104
 
      }
2105
 
    }
2106
 
  }
2107
 
  else // Standard table which will require locks.
2108
 
  {
2109
 
    Table *name_lock= 0;
2110
 
 
2111
 
    if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
2112
 
    {
2113
 
      if (name_lock)
2114
 
      {
2115
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2116
 
        session->unlink_open_table(name_lock);
2117
 
      }
2118
 
 
2119
 
      return res;
2120
 
    }
2121
 
 
2122
 
    if (not name_lock)
2123
 
    {
2124
 
      table_exists= true;
2125
 
    }
2126
 
    else if (plugin::StorageEngine::doesTableExist(*session, destination_identifier))
2127
 
    {
2128
 
      table_exists= true;
2129
 
    }
2130
 
    else // Otherwise we create the table
2131
 
    {
2132
 
      bool was_created;
2133
 
      {
2134
 
        boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
2135
 
        was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2136
 
                                               src_identifier, is_engine_set);
2137
 
      }
2138
 
 
2139
 
      // So we blew the creation of the table, and we scramble to clean up
2140
 
      // anything that might have been created (read... it is a hack)
2141
 
      if (not was_created)
2142
 
      {
2143
 
        plugin::StorageEngine::dropTable(*session, destination_identifier);
2144
 
      } 
2145
 
      else
2146
 
      {
2147
 
        res= false;
2148
 
      }
2149
 
    }
2150
 
 
2151
 
    if (name_lock)
2152
 
    {
2153
 
      boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2154
 
      session->unlink_open_table(name_lock);
2155
 
    }
2156
 
  }
2157
 
 
2158
 
  if (table_exists)
2159
 
  {
2160
 
    if (is_if_not_exists)
2161
 
    {
2162
 
      char warn_buff[DRIZZLE_ERRMSG_SIZE];
2163
 
      snprintf(warn_buff, sizeof(warn_buff),
2164
 
               ER(ER_TABLE_EXISTS_ERROR), table->getTableName());
2165
 
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2166
 
                   ER_TABLE_EXISTS_ERROR,warn_buff);
2167
 
      res= false;
2168
 
    }
2169
 
    else
2170
 
    {
2171
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table->getTableName());
2172
 
    }
2173
 
  }
2174
 
 
 
2279
  */
 
2280
  if (lex_identified_temp_table)
 
2281
  {
 
2282
    if (session->find_temporary_table(db, table_name))
 
2283
      goto table_exists;
 
2284
  }
 
2285
  else
 
2286
  {
 
2287
    if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
 
2288
      goto err;
 
2289
    if (! name_lock)
 
2290
      goto table_exists;
 
2291
 
 
2292
    if (plugin::StorageEngine::getTableDefinition(*session,
 
2293
                                                  destination_identifier) == EEXIST)
 
2294
      goto table_exists;
 
2295
  }
 
2296
 
 
2297
  /*
 
2298
    Create a new table by copying from source table
 
2299
 
 
2300
    Altough exclusive name-lock on target table protects us from concurrent
 
2301
    DML and DDL operations on it we still want to wrap .FRM creation and call
 
2302
    to plugin::StorageEngine::createTable() in critical section protected by
 
2303
    LOCK_open in order to provide minimal atomicity against operations which
 
2304
    disregard name-locks, like I_S implementation, for example. This is a
 
2305
    temporary and should not be copied. Instead we should fix our code to
 
2306
    always honor name-locks.
 
2307
 
 
2308
    Also some engines (e.g. NDB cluster) require that LOCK_open should be held
 
2309
    during the call to plugin::StorageEngine::createTable().
 
2310
    See bug #28614 for more info.
 
2311
  */
 
2312
  pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
 
2313
  {
 
2314
    int protoerr= EEXIST;
 
2315
 
 
2316
    /*
 
2317
     * If an engine was not specified and we are reading from an I_S table, then we need to toss an
 
2318
     * error. This should go away soon.
 
2319
     * @todo make this go away!
 
2320
     */
 
2321
    if (! is_engine_set)
 
2322
    {
 
2323
      string tab_name(src_path);
 
2324
      string i_s_prefix("./information_schema/");
 
2325
      if (tab_name.compare(0, i_s_prefix.length(), i_s_prefix) == 0)
 
2326
      {
 
2327
        pthread_mutex_unlock(&LOCK_open);
 
2328
        my_error(ER_ILLEGAL_HA_CREATE_OPTION,
 
2329
                 MYF(0),
 
2330
                 "INFORMATION_ENGINE",
 
2331
                 "TEMPORARY");
 
2332
        goto err;
 
2333
      }
 
2334
    }
 
2335
 
 
2336
    protoerr= plugin::StorageEngine::getTableDefinition(*session,
 
2337
                                                        src_path,
 
2338
                                                        db,
 
2339
                                                        table_name,
 
2340
                                                        false,
 
2341
                                                        &src_proto);
 
2342
 
 
2343
    message::Table new_proto(src_proto);
 
2344
 
 
2345
    if (lex_identified_temp_table)
 
2346
    {
 
2347
      new_proto.set_type(message::Table::TEMPORARY);
 
2348
    }
 
2349
    else
 
2350
    {
 
2351
      new_proto.set_type(message::Table::STANDARD);
 
2352
    }
 
2353
 
 
2354
    if (is_engine_set)
 
2355
    {
 
2356
      message::Table::StorageEngine *protoengine;
 
2357
 
 
2358
      protoengine= new_proto.mutable_engine();
 
2359
      protoengine->set_name(create_table_proto.engine().name());
 
2360
    }
 
2361
 
 
2362
    if (protoerr == EEXIST)
 
2363
    {
 
2364
      plugin::StorageEngine* engine= plugin::StorageEngine::findByName(*session,
 
2365
                                                                       new_proto.engine().name());
 
2366
 
 
2367
      if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY) == false)
 
2368
      {
 
2369
        string dst_proto_path(destination_identifier.getPath());
 
2370
        dst_proto_path.append(".dfe");
 
2371
 
 
2372
        protoerr= drizzle_write_proto_file(dst_proto_path.c_str(), &new_proto);
 
2373
      }
 
2374
      else
 
2375
      {
 
2376
        protoerr= 0;
 
2377
      }
 
2378
    }
 
2379
 
 
2380
    if (protoerr)
 
2381
    {
 
2382
      if (my_errno == ENOENT)
 
2383
        my_error(ER_BAD_DB_ERROR,MYF(0),db);
 
2384
      else
 
2385
        my_error(ER_CANT_CREATE_FILE, MYF(0), destination_identifier.getPath(), my_errno);
 
2386
      pthread_mutex_unlock(&LOCK_open);
 
2387
      goto err;
 
2388
    }
 
2389
 
 
2390
    /*
 
2391
      As mysql_truncate don't work on a new table at this stage of
 
2392
      creation, instead create the table directly (for both normal
 
2393
      and temporary tables).
 
2394
    */
 
2395
    err= plugin::StorageEngine::createTable(*session,
 
2396
                                            destination_identifier,
 
2397
                                            true, new_proto);
 
2398
  }
 
2399
  pthread_mutex_unlock(&LOCK_open);
 
2400
 
 
2401
  if (lex_identified_temp_table)
 
2402
  {
 
2403
    if (err || !session->open_temporary_table(destination_identifier))
 
2404
    {
 
2405
      (void) session->rm_temporary_table(engine_arg, destination_identifier);
 
2406
      goto err;
 
2407
    }
 
2408
  }
 
2409
  else if (err)
 
2410
  {
 
2411
    (void) quick_rm_table(*session, db,
 
2412
                          table_name, false);
 
2413
    goto err;
 
2414
  }
 
2415
 
 
2416
  /*
 
2417
    We have to write the query before we unlock the tables.
 
2418
  */
 
2419
  {
 
2420
    /*
 
2421
       Since temporary tables are not replicated under row-based
 
2422
       replication, CREATE TABLE ... LIKE ... needs special
 
2423
       treatement.  We have four cases to consider, according to the
 
2424
       following decision table:
 
2425
 
 
2426
           ==== ========= ========= ==============================
 
2427
           Case    Target    Source Write to binary log
 
2428
           ==== ========= ========= ==============================
 
2429
           1       normal    normal Original statement
 
2430
           2       normal temporary Generated statement
 
2431
           3    temporary    normal Nothing
 
2432
           4    temporary temporary Nothing
 
2433
           ==== ========= ========= ==============================
 
2434
    */
 
2435
    if (! lex_identified_temp_table)
 
2436
    {
 
2437
      if (src_table->table->s->tmp_table)               // Case 2
 
2438
      {
 
2439
        char buf[2048];
 
2440
        String query(buf, sizeof(buf), system_charset_info);
 
2441
        query.length(0);  // Have to zero it since constructor doesn't
 
2442
 
 
2443
 
 
2444
        /*
 
2445
          Here we open the destination table, on which we already have
 
2446
          name-lock. This is needed for store_create_info() to work.
 
2447
          The table will be closed by unlink_open_table() at the end
 
2448
          of this function.
 
2449
        */
 
2450
        table->table= name_lock;
 
2451
        pthread_mutex_lock(&LOCK_open); /* Open new table we have just acquired */
 
2452
        if (session->reopen_name_locked_table(table, false))
 
2453
        {
 
2454
          pthread_mutex_unlock(&LOCK_open);
 
2455
          goto err;
 
2456
        }
 
2457
        pthread_mutex_unlock(&LOCK_open);
 
2458
 
 
2459
        int result= store_create_info(table, &query, is_if_not_exists);
 
2460
 
 
2461
        assert(result == 0); // store_create_info() always return 0
 
2462
        write_bin_log(session, query.ptr(), query.length());
 
2463
      }
 
2464
      else                                      // Case 1
 
2465
        write_bin_log(session, session->query, session->query_length);
 
2466
    }
 
2467
  }
 
2468
 
 
2469
  res= false;
 
2470
  goto err;
 
2471
 
 
2472
table_exists:
 
2473
  if (is_if_not_exists)
 
2474
  {
 
2475
    char warn_buff[DRIZZLE_ERRMSG_SIZE];
 
2476
    snprintf(warn_buff, sizeof(warn_buff),
 
2477
             ER(ER_TABLE_EXISTS_ERROR), table_name);
 
2478
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
2479
                 ER_TABLE_EXISTS_ERROR,warn_buff);
 
2480
    res= false;
 
2481
  }
 
2482
  else
 
2483
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
2484
 
 
2485
err:
 
2486
  if (name_lock)
 
2487
  {
 
2488
    pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
 
2489
    session->unlink_open_table(name_lock);
 
2490
    pthread_mutex_unlock(&LOCK_open);
 
2491
  }
2175
2492
  return(res);
2176
2493
}
2177
2494
 
2181
2498
  thr_lock_type lock_type = TL_READ_NO_INSERT;
2182
2499
 
2183
2500
  return(mysql_admin_table(session, tables, check_opt,
2184
 
                                "analyze", lock_type, true,
 
2501
                                "analyze", lock_type, 1, 0, 0, 0,
2185
2502
                                &Cursor::ha_analyze));
2186
2503
}
2187
2504
 
2192
2509
 
2193
2510
  return(mysql_admin_table(session, tables, check_opt,
2194
2511
                                "check", lock_type,
2195
 
                                false,
 
2512
                                0, 0, HA_OPEN_FOR_REPAIR, 0,
2196
2513
                                &Cursor::ha_check));
2197
2514
}
2198
2515
 
2199
 
} /* namespace drizzled */
 
2516
/*
 
2517
  Recreates tables by calling drizzled::alter_table().
 
2518
 
 
2519
  SYNOPSIS
 
2520
    mysql_recreate_table()
 
2521
    session                     Thread Cursor
 
2522
    tables              Tables to recreate
 
2523
 
 
2524
 RETURN
 
2525
    Like drizzled::alter_table().
 
2526
*/
 
2527
bool mysql_recreate_table(Session *session, TableList *table_list)
 
2528
{
 
2529
  HA_CREATE_INFO create_info;
 
2530
  AlterInfo alter_info;
 
2531
  message::Table table_proto;
 
2532
 
 
2533
  assert(!table_list->next_global);
 
2534
  /*
 
2535
    table_list->table has been closed and freed. Do not reference
 
2536
    uninitialized data. open_tables() could fail.
 
2537
  */
 
2538
  table_list->table= NULL;
 
2539
 
 
2540
  memset(&create_info, 0, sizeof(create_info));
 
2541
  create_info.row_type=ROW_TYPE_NOT_USED;
 
2542
  create_info.default_table_charset=default_charset_info;
 
2543
  /* Force alter table to recreate table */
 
2544
  alter_info.flags.set(ALTER_CHANGE_COLUMN);
 
2545
  alter_info.flags.set(ALTER_RECREATE);
 
2546
  return(alter_table(session, NULL, NULL, &create_info, &table_proto,
 
2547
                     table_list, &alter_info, 0,
 
2548
                     (order_st *) 0, 0));
 
2549
}
 
2550
 
 
2551
 
 
2552
bool mysql_checksum_table(Session *session, TableList *tables,
 
2553
                          HA_CHECK_OPT *)
 
2554
{
 
2555
  TableList *table;
 
2556
  List<Item> field_list;
 
2557
  Item *item;
 
2558
 
 
2559
  field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
 
2560
  item->maybe_null= 1;
 
2561
  field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
 
2562
                                          MY_INT64_NUM_DECIMAL_DIGITS));
 
2563
  item->maybe_null= 1;
 
2564
  if (session->client->sendFields(&field_list))
 
2565
    return true;
 
2566
 
 
2567
  /* Open one table after the other to keep lock time as short as possible. */
 
2568
  for (table= tables; table; table= table->next_local)
 
2569
  {
 
2570
    char table_name[NAME_LEN*2+2];
 
2571
    Table *t;
 
2572
 
 
2573
    sprintf(table_name,"%s.%s",table->db,table->table_name);
 
2574
 
 
2575
    t= table->table= session->openTableLock(table, TL_READ);
 
2576
    session->clear_error();                     // these errors shouldn't get client
 
2577
 
 
2578
    session->client->store(table_name);
 
2579
 
 
2580
    if (!t)
 
2581
    {
 
2582
      /* Table didn't exist */
 
2583
      session->client->store();
 
2584
      session->clear_error();
 
2585
    }
 
2586
    else
 
2587
    {
 
2588
      /**
 
2589
        @note if the engine keeps a checksum then we return the checksum, otherwise we calculate
 
2590
      */
 
2591
      if (t->cursor->ha_table_flags() & HA_HAS_CHECKSUM)
 
2592
        session->client->store((uint64_t)t->cursor->checksum());
 
2593
      else
 
2594
      {
 
2595
        /* calculating table's checksum */
 
2596
        ha_checksum crc= 0;
 
2597
        unsigned char null_mask=256 -  (1 << t->s->last_null_bit_pos);
 
2598
 
 
2599
        t->use_all_columns();
 
2600
 
 
2601
        if (t->cursor->ha_rnd_init(1))
 
2602
          session->client->store();
 
2603
        else
 
2604
        {
 
2605
          for (;;)
 
2606
          {
 
2607
            ha_checksum row_crc= 0;
 
2608
            int error= t->cursor->rnd_next(t->record[0]);
 
2609
            if (unlikely(error))
 
2610
            {
 
2611
              if (error == HA_ERR_RECORD_DELETED)
 
2612
                continue;
 
2613
              break;
 
2614
            }
 
2615
            if (t->s->null_bytes)
 
2616
            {
 
2617
              /* fix undefined null bits */
 
2618
              t->record[0][t->s->null_bytes-1] |= null_mask;
 
2619
              if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
 
2620
                t->record[0][0] |= 1;
 
2621
 
 
2622
              row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
 
2623
            }
 
2624
 
 
2625
            for (uint32_t i= 0; i < t->s->fields; i++ )
 
2626
            {
 
2627
              Field *f= t->field[i];
 
2628
              if ((f->type() == DRIZZLE_TYPE_BLOB) ||
 
2629
                  (f->type() == DRIZZLE_TYPE_VARCHAR))
 
2630
              {
 
2631
                String tmp;
 
2632
                f->val_str(&tmp);
 
2633
                row_crc= my_checksum(row_crc, (unsigned char*) tmp.ptr(), tmp.length());
 
2634
              }
 
2635
              else
 
2636
                row_crc= my_checksum(row_crc, f->ptr,
 
2637
                                     f->pack_length());
 
2638
            }
 
2639
 
 
2640
            crc+= row_crc;
 
2641
          }
 
2642
          session->client->store((uint64_t)crc);
 
2643
          t->cursor->ha_rnd_end();
 
2644
        }
 
2645
      }
 
2646
      session->clear_error();
 
2647
      session->close_thread_tables();
 
2648
      table->table=0;                           // For query cache
 
2649
    }
 
2650
    if (session->client->flush())
 
2651
      goto err;
 
2652
  }
 
2653
 
 
2654
  session->my_eof();
 
2655
  return(false);
 
2656
 
 
2657
 err:
 
2658
  session->close_thread_tables();                       // Shouldn't be needed
 
2659
  if (table)
 
2660
    table->table=0;
 
2661
  return(true);
 
2662
}