~stewart/drizzle/embedded-innodb-create-select-transaction-arrgh

« back to all changes in this revision

Viewing changes to plugin/pbxt/src/discover_xt.cc

Merged embedded-innodb-autoincrement into embedded-innodb-create-select-transaction-arrgh.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
 
2
 * Derived from code Copyright (C) 2000-2004 MySQL AB
 
3
 *
 
4
 * PrimeBase XT
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
19
 *
 
20
 *  Created by Leslie on 8/27/08.
 
21
 *
 
22
 */
 
23
 
 
24
#include "xt_config.h"
 
25
 
 
26
#ifdef PBXT_SYS_TAB
 
27
 
 
28
#ifndef DRIZZLED
 
29
#include "mysql_priv.h"
 
30
#include "item_create.h"
 
31
#include <m_ctype.h>
 
32
#else
 
33
#include <drizzled/session.h>
 
34
#include <drizzled/sql_base.h>
 
35
#include <drizzled/statement/alter_table.h>
 
36
#include <drizzled/sql_table.h>
 
37
#include <algorithm>
 
38
#include <sstream>
 
39
namespace drizzled { 
 
40
extern pid_t current_pid;
 
41
namespace internal {
 
42
size_t unpack_filename(char * to, const char *from);
 
43
}
 
44
}
 
45
using namespace drizzled;
 
46
using namespace drizzled::internal;
 
47
#endif
 
48
 
 
49
#include "strutil_xt.h"
 
50
#include "ha_pbxt.h"
 
51
#include "discover_xt.h"
 
52
#include "ha_xtsys.h"
 
53
 
 
54
#ifndef DRIZZLED
 
55
#if MYSQL_VERSION_ID >= 50404
 
56
#define DOT_STR(x)                      x.str
 
57
#else
 
58
#define DOT_STR(x)                      x
 
59
#endif
 
60
#endif
 
61
 
 
62
//#ifndef DRIZZLED
 
63
#define LOCK_OPEN_HACK_REQUIRED
 
64
//#endif // DRIZZLED
 
65
 
 
66
#ifdef LOCK_OPEN_HACK_REQUIRED
 
67
#ifdef DRIZZLED
 
68
 
 
69
using namespace drizzled;
 
70
using namespace std;
 
71
 
 
72
#define mysql_create_table_no_lock hacked_mysql_create_table_no_lock
 
73
 
 
74
namespace drizzled {
 
75
 
 
76
int rea_create_table(Session *session,
 
77
                     TableIdentifier &identifier,
 
78
                     message::Table &table_proto,
 
79
                     HA_CREATE_INFO *create_info,
 
80
                     List<CreateField> &create_field,
 
81
                     uint32_t key_count,KEY *key_info);
 
82
 
 
83
int mysql_prepare_create_table(Session *session,
 
84
                                      HA_CREATE_INFO *create_info,
 
85
                                      message::Table &create_proto,
 
86
                                      AlterInfo *alter_info,
 
87
                                      bool tmp_table,
 
88
                                      uint32_t *db_options,
 
89
                                      KEY **key_info_buffer,
 
90
                                      uint32_t *key_count,
 
91
                                      int select_field_count);
 
92
 
 
93
}
 
94
 
 
95
static uint32_t build_tmptable_filename(Session* session,
 
96
                                        char *buff, size_t bufflen)
 
97
{
 
98
  uint32_t length;
 
99
  ostringstream path_str, post_tmpdir_str;
 
100
  string tmp;
 
101
 
 
102
  path_str << drizzle_tmpdir;
 
103
  post_tmpdir_str << "/" << TMP_FILE_PREFIX << current_pid;
 
104
  post_tmpdir_str << session->thread_id << session->tmp_table++;
 
105
  tmp= post_tmpdir_str.str();
 
106
 
 
107
  transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
 
108
 
 
109
  path_str << tmp;
 
110
 
 
111
  if (bufflen < path_str.str().length())
 
112
    length= 0;
 
113
  else
 
114
    length= unpack_filename(buff, path_str.str().c_str());
 
115
 
 
116
  return length;
 
117
}
 
118
 
 
119
static bool mysql_create_table_no_lock(Session *session,
 
120
                                const char *db, const char *table_name,
 
121
                                HA_CREATE_INFO *create_info,
 
122
                                message::Table *table_proto,
 
123
                                AlterInfo *alter_info,
 
124
                                bool internal_tmp_table,
 
125
                                uint32_t select_field_count,
 
126
                                bool skip_existing)
 
127
{
 
128
  char          path[FN_REFLEN];
 
129
  uint32_t          path_length;
 
130
  uint          db_options, key_count;
 
131
  KEY           *key_info_buffer;
 
132
  Cursor        *file;
 
133
  bool          error= true;
 
134
  /* Check for duplicate fields and check type of table to create */
 
135
  if (!alter_info->create_list.elements)
 
136
  {
 
137
    my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
 
138
               MYF(0));
 
139
    return true;
 
140
  }
 
141
  assert(strcmp(table_name,table_proto->name().c_str())==0);
 
142
  //if (check_engine(session, table_name, table_proto, create_info))
 
143
  //  return true;
 
144
  db_options= create_info->table_options;
 
145
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
 
146
    db_options|=HA_OPTION_PACK_RECORD;
 
147
  
 
148
  /*if (!(file= create_info->db_type->getCursor((TableShare*) 0, session->mem_root)))
 
149
  {
 
150
    my_error(ER_OUTOFMEMORY, MYF(0), sizeof(Cursor));
 
151
    return true;
 
152
  }*/
 
153
 
 
154
  TableIdentifier ident(db, table_name, table_proto->type());
 
155
 
 
156
  /* PMC - Done to avoid getting the partition handler by mistake! */
 
157
  if (!(file= new (session->mem_root) ha_xtsys(pbxt_hton, *TableShare::getShare(ident))))
 
158
  {
 
159
    my_error(ER_OUTOFMEMORY, MYF(0), sizeof(Cursor));
 
160
    return true;
 
161
  }
 
162
 
 
163
  set_table_default_charset(create_info, (char*) db);
 
164
 
 
165
  if (mysql_prepare_create_table(session, 
 
166
                                 create_info,
 
167
                                 *table_proto,
 
168
                                 alter_info,
 
169
                                 internal_tmp_table,
 
170
                                 &db_options,
 
171
                                 &key_info_buffer, &key_count,
 
172
                                 select_field_count))
 
173
    goto err;
 
174
 
 
175
      /* Check if table exists */
 
176
  if (table_proto->type() == message::Table::TEMPORARY)
 
177
  {
 
178
    path_length= build_tmptable_filename(session, path, sizeof(path));
 
179
  }
 
180
  else
 
181
  {
 
182
 #ifdef FN_DEVCHAR
 
183
    /* check if the table name contains FN_DEVCHAR when defined */
 
184
    if (strchr(table_name, FN_DEVCHAR))
 
185
    {
 
186
      my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name);
 
187
      return true;
 
188
    }
 
189
#endif
 
190
    std::string path_str;
 
191
    path_length= build_table_filename(path_str, db, table_name, internal_tmp_table);
 
192
  }
 
193
 
 
194
  /* Check if table already exists */
 
195
  if ((table_proto->type() == message::Table::TEMPORARY) &&
 
196
      session->find_temporary_table(db, table_name))
 
197
  {
 
198
    if (skip_existing)
 
199
    {
 
200
      create_info->table_existed= 1;            // Mark that table existed
 
201
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
202
                          ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
 
203
                          table_name);
 
204
      error= 0;
 
205
      goto err;
 
206
    }
 
207
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
208
    goto err;
 
209
  }
 
210
 
 
211
  //pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
 
212
  if (!internal_tmp_table && table_proto->type() != message::Table::TEMPORARY)
 
213
  {
 
214
    if (plugin::StorageEngine::getTableDefinition(*session,
 
215
                                                  ident, 
 
216
                                                  *table_proto,
 
217
                                                  false) == EEXIST)
 
218
    {
 
219
      if (skip_existing)
 
220
      {
 
221
        error= false;
 
222
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
223
                            ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
 
224
                            table_name);
 
225
        create_info->table_existed= 1;          // Mark that table existed
 
226
      }
 
227
      else
 
228
        my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
 
229
 
 
230
      goto unlock_and_end;
 
231
    }
 
232
    /*
 
233
 *       We don't assert here, but check the result, because the table could be
 
234
 *             in the table definition cache and in the same time the .frm could be
 
235
 *                   missing from the disk, in case of manual intervention which deletes
 
236
 *                         the .frm file. The user has to use FLUSH TABLES; to clear the cache.
 
237
 *                               Then she could create the table. This case is pretty obscure and
 
238
 *                                     therefore we don't introduce a new error message only for it.
 
239
 *                                         */
 
240
    if (TableShare::getShare(ident))
 
241
    {
 
242
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
243
      goto unlock_and_end;
 
244
    }
 
245
  }
 
246
  /*
 
247
 *     Check that table with given name does not already
 
248
 *         exist in any storage engine. In such a case it should
 
249
 *             be discovered and the error ER_TABLE_EXISTS_ERROR be returned
 
250
 *                 unless user specified CREATE TABLE IF EXISTS
 
251
 *                     The LOCK_open mutex has been locked to make sure no
 
252
 *                         one else is attempting to discover the table. Since
 
253
 *                             it's not on disk as a frm file, no one could be using it!
 
254
 *                               */
 
255
  if (table_proto->type() != message::Table::TEMPORARY)
 
256
  {
 
257
    bool create_if_not_exists = skip_existing;
 
258
 
 
259
    std::string path_str;
 
260
    uint32_t          table_path_length;
 
261
 
 
262
    table_path_length= build_table_filename(path_str, db, table_name, false);
 
263
 
 
264
    int retcode= plugin::StorageEngine::getTableDefinition(*session,
 
265
                                                           ident, 
 
266
                                                           *table_proto,
 
267
                                                           false);
 
268
    switch (retcode)
 
269
    {
 
270
      case ENOENT:
 
271
        /* Normal case, no table exists. we can go and create it */
 
272
        break;
 
273
      case EEXIST:
 
274
        if (create_if_not_exists)
 
275
        {
 
276
          error= false;
 
277
          push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
 
278
                              ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
 
279
                              table_name);
 
280
          create_info->table_existed= 1;                // Mark that table existed
 
281
          goto unlock_and_end;
 
282
        }
 
283
        my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
 
284
        goto unlock_and_end;
 
285
      default:
 
286
        my_error(retcode, MYF(0),table_name);
 
287
        goto unlock_and_end;
 
288
    }
 
289
  }
 
290
 
 
291
  session->set_proc_info("creating table");
 
292
  create_info->table_existed= 0;                // Mark that table is created
 
293
 
 
294
  create_info->table_options=db_options;
 
295
 
 
296
  if (rea_create_table(session, ident,
 
297
                       *table_proto,
 
298
                       create_info, alter_info->create_list,
 
299
                       key_count, key_info_buffer))
 
300
    goto unlock_and_end;
 
301
 
 
302
  if (table_proto->type() == message::Table::TEMPORARY)
 
303
  {
 
304
    /* Open table and put in temporary table list */
 
305
    if (!(session->open_temporary_table(ident)))
 
306
    {
 
307
      (void) session->rm_temporary_table(ident);
 
308
      goto unlock_and_end;
 
309
    }
 
310
  }
 
311
 
 
312
  /*
 
313
 *     Don't write statement if:
 
314
 *         - It is an internal temporary table,
 
315
 *             - Row-based logging is used and it we are creating a temporary table, or
 
316
 *                 - The binary log is not open.
 
317
 *                     Otherwise, the statement shall be binlogged.
 
318
 *                        */
 
319
  if (!internal_tmp_table &&
 
320
      ((table_proto->type() != message::Table::TEMPORARY)))
 
321
    write_bin_log(session, session->getQueryString().c_str());
 
322
  error= false;
 
323
unlock_and_end:
 
324
  //pthread_mutex_unlock(&LOCK_open);
 
325
 
 
326
err:
 
327
  session->set_proc_info("After create");
 
328
  delete file;
 
329
  return(error);
 
330
}
 
331
 
 
332
#else // MySQL case
 
333
///////////////////////////////
 
334
/*
 
335
 * Unfortunately I cannot use the standard mysql_create_table_no_lock() because it will lock "LOCK_open"
 
336
 * which has already been locked while the server is performing table discovery. So I have added this hack 
 
337
 * in here to create my own version. The following macros will make the changes I need to get it to work.
 
338
 * The actual function code has been copied here without changes.
 
339
 *
 
340
 * Its almost enough to make you want to cry. :(
 
341
*/
 
342
//-----------------------------
 
343
 
 
344
#ifdef pthread_mutex_lock
 
345
#undef pthread_mutex_lock
 
346
#endif
 
347
 
 
348
#ifdef pthread_mutex_unlock
 
349
#undef pthread_mutex_unlock
 
350
#endif
 
351
 
 
352
#define mysql_create_table_no_lock hacked_mysql_create_table_no_lock
 
353
#define pthread_mutex_lock(l)
 
354
#define pthread_mutex_unlock(l)
 
355
 
 
356
#define check_engine(t, n, c) (0)
 
357
#define set_table_default_charset(t, c, d)
 
358
 
 
359
void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
 
360
                                uint32 *max_length, uint32 *tot_length);
 
361
 
 
362
uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen);
 
363
uint build_table_filename(char *buff, size_t bufflen, const char *db,
 
364
                          const char *table_name, const char *ext, uint flags);
 
365
 
 
366
//////////////////////////////////////////////////////////
 
367
////// START OF CUT AND PASTES FROM  sql_table.cc ////////
 
368
//////////////////////////////////////////////////////////
 
369
 
 
370
// sort_keys() cut and pasted directly from sql_table.cc. 
 
371
static int sort_keys(KEY *a, KEY *b)
 
372
{
 
373
  ulong a_flags= a->flags, b_flags= b->flags;
 
374
  
 
375
  if (a_flags & HA_NOSAME)
 
376
  {
 
377
    if (!(b_flags & HA_NOSAME))
 
378
      return -1;
 
379
    if ((a_flags ^ b_flags) & HA_NULL_PART_KEY)
 
380
    {
 
381
      /* Sort NOT NULL keys before other keys */
 
382
      return (a_flags & HA_NULL_PART_KEY) ? 1 : -1;
 
383
    }
 
384
    if (a->name == primary_key_name)
 
385
      return -1;
 
386
    if (b->name == primary_key_name)
 
387
      return 1;
 
388
    /* Sort keys don't containing partial segments before others */
 
389
    if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG)
 
390
      return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1;
 
391
  }
 
392
  else if (b_flags & HA_NOSAME)
 
393
    return 1;                                   // Prefer b
 
394
 
 
395
  if ((a_flags ^ b_flags) & HA_FULLTEXT)
 
396
  {
 
397
    return (a_flags & HA_FULLTEXT) ? 1 : -1;
 
398
  }
 
399
  /*
 
400
    Prefer original key order.  usable_key_parts contains here
 
401
    the original key position.
 
402
  */
 
403
  return ((a->usable_key_parts < b->usable_key_parts) ? -1 :
 
404
          (a->usable_key_parts > b->usable_key_parts) ? 1 :
 
405
          0);
 
406
}
 
407
 
 
408
// check_if_keyname_exists() cut and pasted directly from sql_table.cc. 
 
409
static bool
 
410
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
 
411
{
 
412
  for (KEY *key=start ; key != end ; key++)
 
413
    if (!my_strcasecmp(system_charset_info,name,key->name))
 
414
      return 1;
 
415
  return 0;
 
416
}
 
417
 
 
418
// make_unique_key_name() cut and pasted directly from sql_table.cc. 
 
419
static char *
 
420
make_unique_key_name(const char *field_name,KEY *start,KEY *end)
 
421
{
 
422
  char buff[MAX_FIELD_NAME],*buff_end;
 
423
 
 
424
  if (!check_if_keyname_exists(field_name,start,end) &&
 
425
      my_strcasecmp(system_charset_info,field_name,primary_key_name))
 
426
    return (char*) field_name;                  // Use fieldname
 
427
  buff_end=strmake(buff,field_name, sizeof(buff)-4);
 
428
 
 
429
  /*
 
430
    Only 3 chars + '\0' left, so need to limit to 2 digit
 
431
    This is ok as we can't have more than 100 keys anyway
 
432
  */
 
433
  for (uint i=2 ; i< 100; i++)
 
434
  {
 
435
    *buff_end= '_';
 
436
    int10_to_str(i, buff_end+1, 10);
 
437
    if (!check_if_keyname_exists(buff,start,end))
 
438
      return sql_strdup(buff);
 
439
  }
 
440
  return (char*) "not_specified";               // Should never happen
 
441
}
 
442
 
 
443
 
 
444
// prepare_blob_field() cut and pasted directly from sql_table.cc. 
 
445
static bool prepare_blob_field(THD *thd, Create_field *sql_field)
 
446
{
 
447
  DBUG_ENTER("prepare_blob_field");
 
448
 
 
449
  if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
 
450
      !(sql_field->flags & BLOB_FLAG))
 
451
  {
 
452
    /* Convert long VARCHAR columns to TEXT or BLOB */
 
453
    char warn_buff[MYSQL_ERRMSG_SIZE];
 
454
 
 
455
    if (sql_field->def || (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
 
456
                                                      MODE_STRICT_ALL_TABLES)))
 
457
    {
 
458
      my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name,
 
459
               MAX_FIELD_VARCHARLENGTH / sql_field->charset->mbmaxlen);
 
460
      DBUG_RETURN(1);
 
461
    }
 
462
    sql_field->sql_type= MYSQL_TYPE_BLOB;
 
463
    sql_field->flags|= BLOB_FLAG;
 
464
    sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name,
 
465
            (sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR",
 
466
            (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT");
 
467
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
 
468
                 warn_buff);
 
469
  }
 
470
    
 
471
  if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
 
472
  {
 
473
    if (sql_field->sql_type == MYSQL_TYPE_BLOB)
 
474
    {
 
475
      /* The user has given a length to the blob column */
 
476
      sql_field->sql_type= get_blob_type_from_length(sql_field->length);
 
477
      sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0);
 
478
    }
 
479
    sql_field->length= 0;
 
480
  }
 
481
  DBUG_RETURN(0);
 
482
}
 
483
 
 
484
//////////////////////////////
 
485
// mysql_prepare_create_table() cut and pasted directly from sql_table.cc.
 
486
static int
 
487
mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
 
488
                           Alter_info *alter_info,
 
489
                           bool tmp_table,
 
490
                           uint *db_options,
 
491
                           handler *file, KEY **key_info_buffer,
 
492
                           uint *key_count, int select_field_count)
 
493
{
 
494
  const char    *key_name;
 
495
  Create_field  *sql_field,*dup_field;
 
496
  uint          field,null_fields,blob_columns,max_key_length;
 
497
  ulong         record_offset= 0;
 
498
  KEY           *key_info;
 
499
  KEY_PART_INFO *key_part_info;
 
500
  int           timestamps= 0, timestamps_with_niladic= 0;
 
501
  int           field_no,dup_no;
 
502
  int           select_field_pos,auto_increment=0;
 
503
  List_iterator<Create_field> it(alter_info->create_list);
 
504
  List_iterator<Create_field> it2(alter_info->create_list);
 
505
  uint total_uneven_bit_length= 0;
 
506
  DBUG_ENTER("mysql_prepare_create_table");
 
507
 
 
508
  select_field_pos= alter_info->create_list.elements - select_field_count;
 
509
  null_fields=blob_columns=0;
 
510
  create_info->varchar= 0;
 
511
  max_key_length= file->max_key_length();
 
512
 
 
513
  for (field_no=0; (sql_field=it++) ; field_no++)
 
514
  {
 
515
    CHARSET_INFO *save_cs;
 
516
 
 
517
    /*
 
518
      Initialize length from its original value (number of characters),
 
519
      which was set in the parser. This is necessary if we're
 
520
      executing a prepared statement for the second time.
 
521
    */
 
522
    sql_field->length= sql_field->char_length;
 
523
    if (!sql_field->charset)
 
524
      sql_field->charset= create_info->default_table_charset;
 
525
    /*
 
526
      table_charset is set in ALTER TABLE if we want change character set
 
527
      for all varchar/char columns.
 
528
      But the table charset must not affect the BLOB fields, so don't
 
529
      allow to change my_charset_bin to somethig else.
 
530
    */
 
531
    if (create_info->table_charset && sql_field->charset != &my_charset_bin)
 
532
      sql_field->charset= create_info->table_charset;
 
533
 
 
534
    save_cs= sql_field->charset;
 
535
    if ((sql_field->flags & BINCMP_FLAG) &&
 
536
        !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname,
 
537
                                                    MY_CS_BINSORT,MYF(0))))
 
538
    {
 
539
      char tmp[64];
 
540
      strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4),
 
541
              STRING_WITH_LEN("_bin"));
 
542
      my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
 
543
      DBUG_RETURN(TRUE);
 
544
    }
 
545
 
 
546
    /*
 
547
      Convert the default value from client character
 
548
      set into the column character set if necessary.
 
549
    */
 
550
    if (sql_field->def && 
 
551
        save_cs != sql_field->def->collation.collation &&
 
552
        (sql_field->sql_type == MYSQL_TYPE_VAR_STRING ||
 
553
         sql_field->sql_type == MYSQL_TYPE_STRING ||
 
554
         sql_field->sql_type == MYSQL_TYPE_SET ||
 
555
         sql_field->sql_type == MYSQL_TYPE_ENUM))
 
556
    {
 
557
      /*
 
558
        Starting from 5.1 we work here with a copy of Create_field
 
559
        created by the caller, not with the instance that was
 
560
        originally created during parsing. It's OK to create
 
561
        a temporary item and initialize with it a member of the
 
562
        copy -- this item will be thrown away along with the copy
 
563
        at the end of execution, and thus not introduce a dangling
 
564
        pointer in the parsed tree of a prepared statement or a
 
565
        stored procedure statement.
 
566
      */
 
567
      sql_field->def= sql_field->def->safe_charset_converter(save_cs);
 
568
 
 
569
      if (sql_field->def == NULL)
 
570
      {
 
571
        /* Could not convert */
 
572
        my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
 
573
        DBUG_RETURN(TRUE);
 
574
      }
 
575
    }
 
576
 
 
577
    if (sql_field->sql_type == MYSQL_TYPE_SET ||
 
578
        sql_field->sql_type == MYSQL_TYPE_ENUM)
 
579
    {
 
580
      uint32 dummy;
 
581
      CHARSET_INFO *cs= sql_field->charset;
 
582
      TYPELIB *interval= sql_field->interval;
 
583
 
 
584
      /*
 
585
        Create typelib from interval_list, and if necessary
 
586
        convert strings from client character set to the
 
587
        column character set.
 
588
      */
 
589
      if (!interval)
 
590
      {
 
591
        /*
 
592
          Create the typelib in runtime memory - we will free the
 
593
          occupied memory at the same time when we free this
 
594
          sql_field -- at the end of execution.
 
595
        */
 
596
        interval= sql_field->interval= typelib(thd->mem_root,
 
597
                                               sql_field->interval_list);
 
598
        List_iterator<String> int_it(sql_field->interval_list);
 
599
        String conv, *tmp;
 
600
        char comma_buf[2];
 
601
        int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf,
 
602
                                          (uchar*) comma_buf + 
 
603
                                          sizeof(comma_buf));
 
604
        DBUG_ASSERT(comma_length > 0);
 
605
        for (uint i= 0; (tmp= int_it++); i++)
 
606
        {
 
607
          uint lengthsp;
 
608
          if (String::needs_conversion(tmp->length(), tmp->charset(),
 
609
                                       cs, &dummy))
 
610
          {
 
611
            uint cnv_errs;
 
612
            conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
 
613
            interval->type_names[i]= strmake_root(thd->mem_root, conv.ptr(),
 
614
                                                  conv.length());
 
615
            interval->type_lengths[i]= conv.length();
 
616
          }
 
617
 
 
618
          // Strip trailing spaces.
 
619
          lengthsp= cs->cset->lengthsp(cs, interval->type_names[i],
 
620
                                       interval->type_lengths[i]);
 
621
          interval->type_lengths[i]= lengthsp;
 
622
          ((uchar *)interval->type_names[i])[lengthsp]= '\0';
 
623
          if (sql_field->sql_type == MYSQL_TYPE_SET)
 
624
          {
 
625
            if (cs->coll->instr(cs, interval->type_names[i], 
 
626
                                interval->type_lengths[i], 
 
627
                                comma_buf, comma_length, NULL, 0))
 
628
            {
 
629
              my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", tmp->ptr());
 
630
              DBUG_RETURN(TRUE);
 
631
            }
 
632
          }
 
633
        }
 
634
        sql_field->interval_list.empty(); // Don't need interval_list anymore
 
635
      }
 
636
 
 
637
      if (sql_field->sql_type == MYSQL_TYPE_SET)
 
638
      {
 
639
        uint32 field_length;
 
640
        if (sql_field->def != NULL)
 
641
        {
 
642
          char *not_used;
 
643
          uint not_used2;
 
644
          bool not_found= 0;
 
645
          String str, *def= sql_field->def->val_str(&str);
 
646
          if (def == NULL) /* SQL "NULL" maps to NULL */
 
647
          {
 
648
            if ((sql_field->flags & NOT_NULL_FLAG) != 0)
 
649
            {
 
650
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
 
651
              DBUG_RETURN(TRUE);
 
652
            }
 
653
 
 
654
            /* else, NULL is an allowed value */
 
655
            (void) find_set(interval, NULL, 0,
 
656
                            cs, &not_used, &not_used2, &not_found);
 
657
          }
 
658
          else /* not NULL */
 
659
          {
 
660
            (void) find_set(interval, def->ptr(), def->length(),
 
661
                            cs, &not_used, &not_used2, &not_found);
 
662
          }
 
663
 
 
664
          if (not_found)
 
665
          {
 
666
            my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
 
667
            DBUG_RETURN(TRUE);
 
668
          }
 
669
        }
 
670
        calculate_interval_lengths(cs, interval, &dummy, &field_length);
 
671
        sql_field->length= field_length + (interval->count - 1);
 
672
      }
 
673
      else  /* MYSQL_TYPE_ENUM */
 
674
      {
 
675
        uint32 field_length;
 
676
        DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM);
 
677
        if (sql_field->def != NULL)
 
678
        {
 
679
          String str, *def= sql_field->def->val_str(&str);
 
680
          if (def == NULL) /* SQL "NULL" maps to NULL */
 
681
          {
 
682
            if ((sql_field->flags & NOT_NULL_FLAG) != 0)
 
683
            {
 
684
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
 
685
              DBUG_RETURN(TRUE);
 
686
            }
 
687
 
 
688
            /* else, the defaults yield the correct length for NULLs. */
 
689
          } 
 
690
          else /* not NULL */
 
691
          {
 
692
            def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
 
693
            if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
 
694
            {
 
695
              my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
 
696
              DBUG_RETURN(TRUE);
 
697
            }
 
698
          }
 
699
        }
 
700
        calculate_interval_lengths(cs, interval, &field_length, &dummy);
 
701
        sql_field->length= field_length;
 
702
      }
 
703
      set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
 
704
    }
 
705
 
 
706
    if (sql_field->sql_type == MYSQL_TYPE_BIT)
 
707
    { 
 
708
      sql_field->pack_flag= FIELDFLAG_NUMBER;
 
709
      if (file->ha_table_flags() & HA_CAN_BIT_FIELD)
 
710
        total_uneven_bit_length+= sql_field->length & 7;
 
711
      else
 
712
        sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
 
713
    }
 
714
 
 
715
    sql_field->create_length_to_internal_length();
 
716
    if (prepare_blob_field(thd, sql_field))
 
717
      DBUG_RETURN(TRUE);
 
718
 
 
719
    if (!(sql_field->flags & NOT_NULL_FLAG))
 
720
      null_fields++;
 
721
 
 
722
    if (check_column_name(sql_field->field_name))
 
723
    {
 
724
      my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
 
725
      DBUG_RETURN(TRUE);
 
726
    }
 
727
 
 
728
    /* Check if we have used the same field name before */
 
729
    for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++)
 
730
    {
 
731
      if (my_strcasecmp(system_charset_info,
 
732
                        sql_field->field_name,
 
733
                        dup_field->field_name) == 0)
 
734
      {
 
735
        /*
 
736
          If this was a CREATE ... SELECT statement, accept a field
 
737
          redefinition if we are changing a field in the SELECT part
 
738
        */
 
739
        if (field_no < select_field_pos || dup_no >= select_field_pos)
 
740
        {
 
741
          my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name);
 
742
          DBUG_RETURN(TRUE);
 
743
        }
 
744
        else
 
745
        {
 
746
          /* Field redefined */
 
747
          sql_field->def=               dup_field->def;
 
748
          sql_field->sql_type=          dup_field->sql_type;
 
749
          sql_field->charset=           (dup_field->charset ?
 
750
                                         dup_field->charset :
 
751
                                         create_info->default_table_charset);
 
752
          sql_field->length=            dup_field->char_length;
 
753
          sql_field->pack_length=       dup_field->pack_length;
 
754
          sql_field->key_length=        dup_field->key_length;
 
755
          sql_field->decimals=          dup_field->decimals;
 
756
          sql_field->create_length_to_internal_length();
 
757
          sql_field->unireg_check=      dup_field->unireg_check;
 
758
          /* 
 
759
            We're making one field from two, the result field will have
 
760
            dup_field->flags as flags. If we've incremented null_fields
 
761
            because of sql_field->flags, decrement it back.
 
762
          */
 
763
          if (!(sql_field->flags & NOT_NULL_FLAG))
 
764
            null_fields--;
 
765
          sql_field->flags=             dup_field->flags;
 
766
          sql_field->interval=          dup_field->interval;
 
767
          it2.remove();                 // Remove first (create) definition
 
768
          select_field_pos--;
 
769
          break;
 
770
        }
 
771
      }
 
772
    }
 
773
    /* Don't pack rows in old tables if the user has requested this */
 
774
    if ((sql_field->flags & BLOB_FLAG) ||
 
775
        (sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
 
776
         create_info->row_type != ROW_TYPE_FIXED))
 
777
      (*db_options)|= HA_OPTION_PACK_RECORD;
 
778
    it2.rewind();
 
779
  }
 
780
 
 
781
  /* record_offset will be increased with 'length-of-null-bits' later */
 
782
  record_offset= 0;
 
783
  null_fields+= total_uneven_bit_length;
 
784
 
 
785
  it.rewind();
 
786
  while ((sql_field=it++))
 
787
  {
 
788
    DBUG_ASSERT(sql_field->charset != 0);
 
789
 
 
790
    if (prepare_create_field(sql_field, &blob_columns, 
 
791
                             &timestamps, &timestamps_with_niladic,
 
792
                             file->ha_table_flags()))
 
793
      DBUG_RETURN(TRUE);
 
794
    if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
 
795
      create_info->varchar= TRUE;
 
796
    sql_field->offset= record_offset;
 
797
    if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
 
798
      auto_increment++;
 
799
    record_offset+= sql_field->pack_length;
 
800
  }
 
801
  if (timestamps_with_niladic > 1)
 
802
  {
 
803
    my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,
 
804
               ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0));
 
805
    DBUG_RETURN(TRUE);
 
806
  }
 
807
  if (auto_increment > 1)
 
808
  {
 
809
    my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
 
810
    DBUG_RETURN(TRUE);
 
811
  }
 
812
  if (auto_increment &&
 
813
      (file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
 
814
  {
 
815
    my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
 
816
               ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
 
817
    DBUG_RETURN(TRUE);
 
818
  }
 
819
 
 
820
  if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS))
 
821
  {
 
822
    my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
 
823
               MYF(0));
 
824
    DBUG_RETURN(TRUE);
 
825
  }
 
826
 
 
827
  /* Create keys */
 
828
 
 
829
  List_iterator<Key> key_iterator(alter_info->key_list);
 
830
  List_iterator<Key> key_iterator2(alter_info->key_list);
 
831
  uint key_parts=0, fk_key_count=0;
 
832
  bool primary_key=0,unique_key=0;
 
833
  Key *key, *key2;
 
834
  uint tmp, key_number;
 
835
  /* special marker for keys to be ignored */
 
836
  static char ignore_key[1];
 
837
 
 
838
  /* Calculate number of key segements */
 
839
  *key_count= 0;
 
840
  
 
841
  while ((key=key_iterator++))
 
842
  {
 
843
    DBUG_PRINT("info", ("key name: '%s'  type: %d", key->DOT_STR(name) ? key->DOT_STR(name) :
 
844
                        "(none)" , key->type));
 
845
    LEX_STRING key_name_str;
 
846
    if (key->type == Key::FOREIGN_KEY)
 
847
    {
 
848
      fk_key_count++;
 
849
      Foreign_key *fk_key= (Foreign_key*) key;
 
850
      if (fk_key->ref_columns.elements &&
 
851
          fk_key->ref_columns.elements != fk_key->columns.elements)
 
852
      {
 
853
        my_error(ER_WRONG_FK_DEF, MYF(0),
 
854
                 (fk_key->DOT_STR(name) ?  fk_key->DOT_STR(name) : "foreign key without name"),
 
855
                 ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
 
856
        DBUG_RETURN(TRUE);
 
857
      }
 
858
      continue;
 
859
    }
 
860
    (*key_count)++;
 
861
    tmp=file->max_key_parts();
 
862
    if (key->columns.elements > tmp)
 
863
    {
 
864
      my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
 
865
      DBUG_RETURN(TRUE);
 
866
    }
 
867
    key_name_str.str= (char*) key->DOT_STR(name);
 
868
    key_name_str.length= key->DOT_STR(name) ? strlen(key->DOT_STR(name)) : 0;
 
869
    if (check_string_char_length(&key_name_str, "", NAME_CHAR_LEN,
 
870
                                 system_charset_info, 1))
 
871
    {
 
872
      my_error(ER_TOO_LONG_IDENT, MYF(0), key->DOT_STR(name));
 
873
      DBUG_RETURN(TRUE);
 
874
    }
 
875
    key_iterator2.rewind ();
 
876
    if (key->type != Key::FOREIGN_KEY)
 
877
    {
 
878
      while ((key2 = key_iterator2++) != key)
 
879
      {
 
880
        /*
 
881
          foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is
 
882
          'generated', and a generated key is a prefix of the other key.
 
883
          Then we do not need the generated shorter key.
 
884
        */
 
885
        if ((key2->type != Key::FOREIGN_KEY &&
 
886
             key2->DOT_STR(name) != ignore_key &&
 
887
             !foreign_key_prefix(key, key2)))
 
888
        {
 
889
          /* TODO: issue warning message */
 
890
          /* mark that the generated key should be ignored */
 
891
          if (!key2->generated ||
 
892
              (key->generated && key->columns.elements <
 
893
               key2->columns.elements))
 
894
            key->DOT_STR(name)= ignore_key;
 
895
          else
 
896
          {
 
897
            key2->DOT_STR(name)= ignore_key;
 
898
            key_parts-= key2->columns.elements;
 
899
            (*key_count)--;
 
900
          }
 
901
          break;
 
902
        }
 
903
      }
 
904
    }
 
905
    if (key->DOT_STR(name) != ignore_key)
 
906
      key_parts+=key->columns.elements;
 
907
    else
 
908
      (*key_count)--;
 
909
    if (key->DOT_STR(name) && !tmp_table && (key->type != Key::PRIMARY) &&
 
910
        !my_strcasecmp(system_charset_info,key->DOT_STR(name),primary_key_name))
 
911
    {
 
912
      my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->DOT_STR(name));
 
913
      DBUG_RETURN(TRUE);
 
914
    }
 
915
  }
 
916
  tmp=file->max_keys();
 
917
  if (*key_count > tmp)
 
918
  {
 
919
    my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
 
920
    DBUG_RETURN(TRUE);
 
921
  }
 
922
 
 
923
  (*key_info_buffer)= key_info= (KEY*) sql_calloc(sizeof(KEY) * (*key_count));
 
924
  key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
 
925
  if (!*key_info_buffer || ! key_part_info)
 
926
    DBUG_RETURN(TRUE);                          // Out of memory
 
927
 
 
928
  key_iterator.rewind();
 
929
  key_number=0;
 
930
  for (; (key=key_iterator++) ; key_number++)
 
931
  {
 
932
    uint key_length=0;
 
933
    Key_part_spec *column;
 
934
 
 
935
    if (key->DOT_STR(name) == ignore_key)
 
936
    {
 
937
      /* ignore redundant keys */
 
938
      do
 
939
        key=key_iterator++;
 
940
      while (key && key->DOT_STR(name) == ignore_key);
 
941
      if (!key)
 
942
        break;
 
943
    }
 
944
 
 
945
    switch (key->type) {
 
946
    case Key::MULTIPLE:
 
947
        key_info->flags= 0;
 
948
        break;
 
949
    case Key::FULLTEXT:
 
950
        key_info->flags= HA_FULLTEXT;
 
951
        if ((key_info->parser_name= &key->key_create_info.parser_name)->str)
 
952
          key_info->flags|= HA_USES_PARSER;
 
953
        else
 
954
          key_info->parser_name= 0;
 
955
        break;
 
956
    case Key::SPATIAL:
 
957
#ifdef HAVE_SPATIAL
 
958
        key_info->flags= HA_SPATIAL;
 
959
        break;
 
960
#else
 
961
        my_error(ER_FEATURE_DISABLED, MYF(0),
 
962
                 sym_group_geom.name, sym_group_geom.needed_define);
 
963
        DBUG_RETURN(TRUE);
 
964
#endif
 
965
    case Key::FOREIGN_KEY:
 
966
      key_number--;                             // Skip this key
 
967
      continue;
 
968
    default:
 
969
      key_info->flags = HA_NOSAME;
 
970
      break;
 
971
    }
 
972
    if (key->generated)
 
973
      key_info->flags|= HA_GENERATED_KEY;
 
974
 
 
975
    key_info->key_parts=(uint8) key->columns.elements;
 
976
    key_info->key_part=key_part_info;
 
977
    key_info->usable_key_parts= key_number;
 
978
    key_info->algorithm= key->key_create_info.algorithm;
 
979
 
 
980
    if (key->type == Key::FULLTEXT)
 
981
    {
 
982
      if (!(file->ha_table_flags() & HA_CAN_FULLTEXT))
 
983
      {
 
984
        my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT),
 
985
                   MYF(0));
 
986
        DBUG_RETURN(TRUE);
 
987
      }
 
988
    }
 
989
    /*
 
990
       Make SPATIAL to be RTREE by default
 
991
       SPATIAL only on BLOB or at least BINARY, this
 
992
       actually should be replaced by special GEOM type
 
993
       in near future when new frm file is ready
 
994
       checking for proper key parts number:
 
995
    */
 
996
 
 
997
    /* TODO: Add proper checks if handler supports key_type and algorithm */
 
998
    if (key_info->flags & HA_SPATIAL)
 
999
    {
 
1000
      if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS))
 
1001
      {
 
1002
        my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS),
 
1003
                   MYF(0));
 
1004
        DBUG_RETURN(TRUE);
 
1005
      }
 
1006
      if (key_info->key_parts != 1)
 
1007
      {
 
1008
        my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
 
1009
        DBUG_RETURN(TRUE);
 
1010
      }
 
1011
    }
 
1012
    else if (key_info->algorithm == HA_KEY_ALG_RTREE)
 
1013
    {
 
1014
#ifdef HAVE_RTREE_KEYS
 
1015
      if ((key_info->key_parts & 1) == 1)
 
1016
      {
 
1017
        my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX");
 
1018
        DBUG_RETURN(TRUE);
 
1019
      }
 
1020
      /* TODO: To be deleted */
 
1021
      my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX");
 
1022
      DBUG_RETURN(TRUE);
 
1023
#else
 
1024
      my_error(ER_FEATURE_DISABLED, MYF(0),
 
1025
               sym_group_rtree.name, sym_group_rtree.needed_define);
 
1026
      DBUG_RETURN(TRUE);
 
1027
#endif
 
1028
    }
 
1029
 
 
1030
    /* Take block size from key part or table part */
 
1031
    /*
 
1032
      TODO: Add warning if block size changes. We can't do it here, as
 
1033
      this may depend on the size of the key
 
1034
    */
 
1035
    key_info->block_size= (key->key_create_info.block_size ?
 
1036
                           key->key_create_info.block_size :
 
1037
                           create_info->key_block_size);
 
1038
 
 
1039
    if (key_info->block_size)
 
1040
      key_info->flags|= HA_USES_BLOCK_SIZE;
 
1041
 
 
1042
    List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
 
1043
    CHARSET_INFO *ft_key_charset=0;  // for FULLTEXT
 
1044
    for (uint column_nr=0 ; (column=cols++) ; column_nr++)
 
1045
    {
 
1046
      uint length;
 
1047
      Key_part_spec *dup_column;
 
1048
 
 
1049
      it.rewind();
 
1050
      field=0;
 
1051
      while ((sql_field=it++) &&
 
1052
             my_strcasecmp(system_charset_info,
 
1053
                           column->DOT_STR(field_name),
 
1054
                           sql_field->field_name))
 
1055
        field++;
 
1056
      if (!sql_field)
 
1057
      {
 
1058
        my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name);
 
1059
        DBUG_RETURN(TRUE);
 
1060
      }
 
1061
      while ((dup_column= cols2++) != column)
 
1062
      {
 
1063
        if (!my_strcasecmp(system_charset_info,
 
1064
                           column->DOT_STR(field_name), dup_column->DOT_STR(field_name)))
 
1065
        {
 
1066
          my_printf_error(ER_DUP_FIELDNAME,
 
1067
                          ER(ER_DUP_FIELDNAME),MYF(0),
 
1068
                          column->field_name);
 
1069
          DBUG_RETURN(TRUE);
 
1070
        }
 
1071
      }
 
1072
      cols2.rewind();
 
1073
      if (key->type == Key::FULLTEXT)
 
1074
      {
 
1075
        if ((sql_field->sql_type != MYSQL_TYPE_STRING &&
 
1076
             sql_field->sql_type != MYSQL_TYPE_VARCHAR &&
 
1077
             !f_is_blob(sql_field->pack_flag)) ||
 
1078
            sql_field->charset == &my_charset_bin ||
 
1079
            sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet
 
1080
            (ft_key_charset && sql_field->charset != ft_key_charset))
 
1081
        {
 
1082
            my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name);
 
1083
            DBUG_RETURN(-1);
 
1084
        }
 
1085
        ft_key_charset=sql_field->charset;
 
1086
        /*
 
1087
          for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
 
1088
          code anyway, and 0 (set to column width later) for char's. it has
 
1089
          to be correct col width for char's, as char data are not prefixed
 
1090
          with length (unlike blobs, where ft code takes data length from a
 
1091
          data prefix, ignoring column->length).
 
1092
        */
 
1093
        column->length=test(f_is_blob(sql_field->pack_flag));
 
1094
      }
 
1095
      else
 
1096
      {
 
1097
        column->length*= sql_field->charset->mbmaxlen;
 
1098
 
 
1099
        if (key->type == Key::SPATIAL && column->length)
 
1100
        {
 
1101
          my_error(ER_WRONG_SUB_KEY, MYF(0));
 
1102
          DBUG_RETURN(TRUE);
 
1103
        }
 
1104
 
 
1105
        if (f_is_blob(sql_field->pack_flag) ||
 
1106
            (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
 
1107
        {
 
1108
          if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
 
1109
          {
 
1110
            my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name);
 
1111
            DBUG_RETURN(TRUE);
 
1112
          }
 
1113
          if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
 
1114
              Field::GEOM_POINT)
 
1115
            column->length= 25;
 
1116
          if (!column->length)
 
1117
          {
 
1118
            my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name);
 
1119
            DBUG_RETURN(TRUE);
 
1120
          }
 
1121
        }
 
1122
#ifdef HAVE_SPATIAL
 
1123
        if (key->type == Key::SPATIAL)
 
1124
        {
 
1125
          if (!column->length)
 
1126
          {
 
1127
            /*
 
1128
              4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
 
1129
              Lately we'll extend this code to support more dimensions
 
1130
            */
 
1131
            column->length= 4*sizeof(double);
 
1132
          }
 
1133
        }
 
1134
#endif
 
1135
        if (!(sql_field->flags & NOT_NULL_FLAG))
 
1136
        {
 
1137
          if (key->type == Key::PRIMARY)
 
1138
          {
 
1139
            /* Implicitly set primary key fields to NOT NULL for ISO conf. */
 
1140
            sql_field->flags|= NOT_NULL_FLAG;
 
1141
            sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
 
1142
            null_fields--;
 
1143
          }
 
1144
          else
 
1145
          {
 
1146
            key_info->flags|= HA_NULL_PART_KEY;
 
1147
            if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
 
1148
            {
 
1149
              my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name);
 
1150
              DBUG_RETURN(TRUE);
 
1151
            }
 
1152
            if (key->type == Key::SPATIAL)
 
1153
            {
 
1154
              my_message(ER_SPATIAL_CANT_HAVE_NULL,
 
1155
                         ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
 
1156
              DBUG_RETURN(TRUE);
 
1157
            }
 
1158
          }
 
1159
        }
 
1160
        if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
 
1161
        {
 
1162
          if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
 
1163
            auto_increment--;                   // Field is used
 
1164
        }
 
1165
      }
 
1166
 
 
1167
      key_part_info->fieldnr= field;
 
1168
      key_part_info->offset=  (uint16) sql_field->offset;
 
1169
      key_part_info->key_type=sql_field->pack_flag;
 
1170
      length= sql_field->key_length;
 
1171
 
 
1172
      if (column->length)
 
1173
      {
 
1174
        if (f_is_blob(sql_field->pack_flag))
 
1175
        {
 
1176
          if ((length=column->length) > max_key_length ||
 
1177
              length > file->max_key_part_length())
 
1178
          {
 
1179
            length=min(max_key_length, file->max_key_part_length());
 
1180
            if (key->type == Key::MULTIPLE)
 
1181
            {
 
1182
              /* not a critical problem */
 
1183
              char warn_buff[MYSQL_ERRMSG_SIZE];
 
1184
              my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
 
1185
                          length);
 
1186
              push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
1187
                           ER_TOO_LONG_KEY, warn_buff);
 
1188
              /* Align key length to multibyte char boundary */
 
1189
              length-= length % sql_field->charset->mbmaxlen;
 
1190
            }
 
1191
            else
 
1192
            {
 
1193
              my_error(ER_TOO_LONG_KEY,MYF(0),length);
 
1194
              DBUG_RETURN(TRUE);
 
1195
            }
 
1196
          }
 
1197
        }
 
1198
        else if (!f_is_geom(sql_field->pack_flag) &&
 
1199
                  (column->length > length ||
 
1200
                   !Field::type_can_have_key_part (sql_field->sql_type) ||
 
1201
                   ((f_is_packed(sql_field->pack_flag) ||
 
1202
                     ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
 
1203
                      (key_info->flags & HA_NOSAME))) &&
 
1204
                    column->length != length)))
 
1205
        {
 
1206
          my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
 
1207
          DBUG_RETURN(TRUE);
 
1208
        }
 
1209
        else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
 
1210
          length=column->length;
 
1211
      }
 
1212
      else if (length == 0)
 
1213
      {
 
1214
        my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name);
 
1215
          DBUG_RETURN(TRUE);
 
1216
      }
 
1217
      if (length > file->max_key_part_length() && key->type != Key::FULLTEXT)
 
1218
      {
 
1219
        length= file->max_key_part_length();
 
1220
        if (key->type == Key::MULTIPLE)
 
1221
        {
 
1222
          /* not a critical problem */
 
1223
          char warn_buff[MYSQL_ERRMSG_SIZE];
 
1224
          my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
 
1225
                      length);
 
1226
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
1227
                       ER_TOO_LONG_KEY, warn_buff);
 
1228
          /* Align key length to multibyte char boundary */
 
1229
          length-= length % sql_field->charset->mbmaxlen;
 
1230
        }
 
1231
        else
 
1232
        {
 
1233
          my_error(ER_TOO_LONG_KEY,MYF(0),length);
 
1234
          DBUG_RETURN(TRUE);
 
1235
        }
 
1236
      }
 
1237
      key_part_info->length=(uint16) length;
 
1238
      /* Use packed keys for long strings on the first column */
 
1239
      if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
 
1240
          (length >= KEY_DEFAULT_PACK_LENGTH &&
 
1241
           (sql_field->sql_type == MYSQL_TYPE_STRING ||
 
1242
            sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
 
1243
            sql_field->pack_flag & FIELDFLAG_BLOB)))
 
1244
      {
 
1245
        if ((column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB)) ||
 
1246
            sql_field->sql_type == MYSQL_TYPE_VARCHAR)
 
1247
          key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
 
1248
        else
 
1249
          key_info->flags|= HA_PACK_KEY;
 
1250
      }
 
1251
      /* Check if the key segment is partial, set the key flag accordingly */
 
1252
      if (length != sql_field->key_length)
 
1253
        key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
 
1254
 
 
1255
      key_length+=length;
 
1256
      key_part_info++;
 
1257
 
 
1258
      /* Create the key name based on the first column (if not given) */
 
1259
      if (column_nr == 0)
 
1260
      {
 
1261
        if (key->type == Key::PRIMARY)
 
1262
        {
 
1263
          if (primary_key)
 
1264
          {
 
1265
            my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY),
 
1266
                       MYF(0));
 
1267
            DBUG_RETURN(TRUE);
 
1268
          }
 
1269
          key_name=primary_key_name;
 
1270
          primary_key=1;
 
1271
        }
 
1272
        else if (!(key_name = key->DOT_STR(name)))
 
1273
          key_name=make_unique_key_name(sql_field->field_name,
 
1274
                                        *key_info_buffer, key_info);
 
1275
        if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
 
1276
        {
 
1277
          my_error(ER_DUP_KEYNAME, MYF(0), key_name);
 
1278
          DBUG_RETURN(TRUE);
 
1279
        }
 
1280
        key_info->name=(char*) key_name;
 
1281
      }
 
1282
    }
 
1283
    if (!key_info->name || check_column_name(key_info->name))
 
1284
    {
 
1285
      my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
 
1286
      DBUG_RETURN(TRUE);
 
1287
    }
 
1288
    if (!(key_info->flags & HA_NULL_PART_KEY))
 
1289
      unique_key=1;
 
1290
    key_info->key_length=(uint16) key_length;
 
1291
    if (key_length > max_key_length && key->type != Key::FULLTEXT)
 
1292
    {
 
1293
      my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
 
1294
      DBUG_RETURN(TRUE);
 
1295
    }
 
1296
    key_info++;
 
1297
  }
 
1298
  if (!unique_key && !primary_key &&
 
1299
      (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
 
1300
  {
 
1301
    my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
 
1302
    DBUG_RETURN(TRUE);
 
1303
  }
 
1304
  if (auto_increment > 0)
 
1305
  {
 
1306
    my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
 
1307
    DBUG_RETURN(TRUE);
 
1308
  }
 
1309
  /* Sort keys in optimized order */
 
1310
  my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
 
1311
           (qsort_cmp) sort_keys);
 
1312
  create_info->null_bits= null_fields;
 
1313
 
 
1314
  /* Check fields. */
 
1315
  it.rewind();
 
1316
  while ((sql_field=it++))
 
1317
  {
 
1318
    Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
 
1319
 
 
1320
    if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
 
1321
        !sql_field->def &&
 
1322
        sql_field->sql_type == MYSQL_TYPE_TIMESTAMP &&
 
1323
        (sql_field->flags & NOT_NULL_FLAG) &&
 
1324
        (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
 
1325
    {
 
1326
      /*
 
1327
        An error should be reported if:
 
1328
          - NO_ZERO_DATE SQL mode is active;
 
1329
          - there is no explicit DEFAULT clause (default column value);
 
1330
          - this is a TIMESTAMP column;
 
1331
          - the column is not NULL;
 
1332
          - this is not the DEFAULT CURRENT_TIMESTAMP column.
 
1333
 
 
1334
        In other words, an error should be reported if
 
1335
          - NO_ZERO_DATE SQL mode is active;
 
1336
          - the column definition is equivalent to
 
1337
            'column_name TIMESTAMP DEFAULT 0'.
 
1338
      */
 
1339
 
 
1340
      my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
 
1341
      DBUG_RETURN(TRUE);
 
1342
    }
 
1343
  }
 
1344
 
 
1345
  DBUG_RETURN(FALSE);
 
1346
}
 
1347
 
 
1348
//////////////////////////////
 
1349
// mysql_create_table_no_lock() cut and pasted directly from sql_table.cc. (I did make is static after copying it.)
 
1350
 
 
1351
static bool mysql_create_table_no_lock(THD *thd,
 
1352
                                const char *db, const char *table_name,
 
1353
                                HA_CREATE_INFO *create_info,
 
1354
                                Alter_info *alter_info,
 
1355
                                bool internal_tmp_table,
 
1356
                                uint select_field_count)
 
1357
{
 
1358
  char                  path[FN_REFLEN];
 
1359
  uint          path_length;
 
1360
  const char    *alias;
 
1361
  uint                  db_options, key_count;
 
1362
  KEY                   *key_info_buffer;
 
1363
  handler               *file;
 
1364
  bool                  error= TRUE;
 
1365
  DBUG_ENTER("mysql_create_table_no_lock");
 
1366
  DBUG_PRINT("enter", ("db: '%s'  table: '%s'  tmp: %d",
 
1367
                       db, table_name, internal_tmp_table));
 
1368
 
 
1369
 
 
1370
  /* Check for duplicate fields and check type of table to create */
 
1371
  if (!alter_info->create_list.elements)
 
1372
  {
 
1373
    my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
 
1374
               MYF(0));
 
1375
    DBUG_RETURN(TRUE);
 
1376
  }
 
1377
  if (check_engine(thd, table_name, create_info))
 
1378
    DBUG_RETURN(TRUE);
 
1379
  db_options= create_info->table_options;
 
1380
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
 
1381
    db_options|=HA_OPTION_PACK_RECORD;
 
1382
  alias= table_case_name(create_info, table_name);
 
1383
 
 
1384
  /* PMC - Done to avoid getting the partition handler by mistake! */
 
1385
  if (!(file= new (thd->mem_root) ha_xtsys(pbxt_hton, NULL)))
 
1386
  {
 
1387
    mem_alloc_error(sizeof(handler));
 
1388
    DBUG_RETURN(TRUE);
 
1389
  }
 
1390
 
 
1391
  set_table_default_charset(thd, create_info, (char*) db);
 
1392
 
 
1393
  if (mysql_prepare_create_table(thd, create_info, alter_info,
 
1394
                                 internal_tmp_table,
 
1395
                                 &db_options, file,
 
1396
                                 &key_info_buffer, &key_count,
 
1397
                                 select_field_count))
 
1398
    goto err;
 
1399
 
 
1400
      /* Check if table exists */
 
1401
  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
 
1402
  {
 
1403
    path_length= build_tmptable_filename(thd, path, sizeof(path));
 
1404
    create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
 
1405
  }
 
1406
  else  
 
1407
  {
 
1408
 #ifdef FN_DEVCHAR
 
1409
    /* check if the table name contains FN_DEVCHAR when defined */
 
1410
    if (strchr(alias, FN_DEVCHAR))
 
1411
    {
 
1412
      my_error(ER_WRONG_TABLE_NAME, MYF(0), alias);
 
1413
      DBUG_RETURN(TRUE);
 
1414
    }
 
1415
#endif
 
1416
    path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext,
 
1417
                                      internal_tmp_table ? FN_IS_TMP : 0);
 
1418
  }
 
1419
 
 
1420
  /* Check if table already exists */
 
1421
  if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
 
1422
      find_temporary_table(thd, db, table_name))
 
1423
  {
 
1424
    if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
 
1425
    {
 
1426
      create_info->table_existed= 1;            // Mark that table existed
 
1427
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
 
1428
                          ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
 
1429
                          alias);
 
1430
      error= 0;
 
1431
      goto err;
 
1432
    }
 
1433
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
 
1434
    goto err;
 
1435
  }
 
1436
 
 
1437
  pthread_mutex_lock(&LOCK_open);
 
1438
  if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
 
1439
  {
 
1440
    if (!access(path,F_OK))
 
1441
    {
 
1442
      if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
 
1443
        goto warn;
 
1444
      my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
 
1445
      goto unlock_and_end;
 
1446
    }
 
1447
    /*
 
1448
      We don't assert here, but check the result, because the table could be
 
1449
      in the table definition cache and in the same time the .frm could be
 
1450
      missing from the disk, in case of manual intervention which deletes
 
1451
      the .frm file. The user has to use FLUSH TABLES; to clear the cache.
 
1452
      Then she could create the table. This case is pretty obscure and
 
1453
      therefore we don't introduce a new error message only for it.
 
1454
    */
 
1455
    if (get_cached_table_share(db, alias))
 
1456
    {
 
1457
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
 
1458
      goto unlock_and_end;
 
1459
    }
 
1460
  }
 
1461
 
 
1462
  /*
 
1463
    Check that table with given name does not already
 
1464
    exist in any storage engine. In such a case it should
 
1465
    be discovered and the error ER_TABLE_EXISTS_ERROR be returned
 
1466
    unless user specified CREATE TABLE IF EXISTS
 
1467
    The LOCK_open mutex has been locked to make sure no
 
1468
    one else is attempting to discover the table. Since
 
1469
    it's not on disk as a frm file, no one could be using it!
 
1470
  */
 
1471
  if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
 
1472
  {
 
1473
    bool create_if_not_exists =
 
1474
      create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
 
1475
    int retcode = ha_table_exists_in_engine(thd, db, table_name);
 
1476
    DBUG_PRINT("info", ("exists_in_engine: %u",retcode));
 
1477
    switch (retcode)
 
1478
    {
 
1479
      case HA_ERR_NO_SUCH_TABLE:
 
1480
        /* Normal case, no table exists. we can go and create it */
 
1481
        break;
 
1482
      case HA_ERR_TABLE_EXIST:
 
1483
        DBUG_PRINT("info", ("Table existed in handler"));
 
1484
 
 
1485
        if (create_if_not_exists)
 
1486
          goto warn;
 
1487
        my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
 
1488
        goto unlock_and_end;
 
1489
        break;
 
1490
      default:
 
1491
        DBUG_PRINT("info", ("error: %u from storage engine", retcode));
 
1492
        my_error(retcode, MYF(0),table_name);
 
1493
        goto unlock_and_end;
 
1494
    }
 
1495
  }
 
1496
 
 
1497
  thd_proc_info(thd, "creating table");
 
1498
  create_info->table_existed= 0;                // Mark that table is created
 
1499
 
 
1500
  create_info->table_options=db_options;
 
1501
 
 
1502
  path[path_length - reg_ext_length]= '\0'; // Remove .frm extension
 
1503
  if (rea_create_table(thd, path, db, table_name,
 
1504
                       create_info, alter_info->create_list,
 
1505
                       key_count, key_info_buffer, file))
 
1506
    goto unlock_and_end;
 
1507
 
 
1508
  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
 
1509
  {
 
1510
    /* Open table and put in temporary table list */
 
1511
#if MYSQL_VERSION_ID >= 50404
 
1512
    if (!(open_temporary_table(thd, path, db, table_name, 1, OTM_OPEN)))
 
1513
#else
 
1514
    if (!(open_temporary_table(thd, path, db, table_name, 1)))
 
1515
#endif
 
1516
    {
 
1517
#if MYSQL_VERSION_ID >= 50404
 
1518
      (void) rm_temporary_table(create_info->db_type, path, false);
 
1519
#else
 
1520
      (void) rm_temporary_table(create_info->db_type, path);
 
1521
#endif
 
1522
      goto unlock_and_end;
 
1523
    }
 
1524
    thd->thread_specific_used= TRUE;
 
1525
  }
 
1526
 
 
1527
  /*
 
1528
    Don't write statement if:
 
1529
    - It is an internal temporary table,
 
1530
    - Row-based logging is used and it we are creating a temporary table, or
 
1531
    - The binary log is not open.
 
1532
    Otherwise, the statement shall be binlogged.
 
1533
   */
 
1534
  /* PBXT 1.0.09e
 
1535
   * Firstly we had a compile problem with MySQL 5.1.42 and
 
1536
   * the write_bin_log() call below:
 
1537
   * discover_xt.cc:1259: error: argument of type 'char* (Statement::)()' does not match 'const char*'
 
1538
   * 
 
1539
   * And secondly, we should no write the BINLOG anyway because this is
 
1540
   * an internal PBXT system table.
 
1541
   *
 
1542
   * So I am just commenting out the code altogether.
 
1543
  if (!internal_tmp_table &&
 
1544
      (!thd->current_stmt_binlog_row_based ||
 
1545
       (thd->current_stmt_binlog_row_based &&
 
1546
        !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
 
1547
    write_bin_log(thd, TRUE, thd->query, thd->query_length);
 
1548
   */
 
1549
  error= FALSE;
 
1550
unlock_and_end:
 
1551
  pthread_mutex_unlock(&LOCK_open);
 
1552
 
 
1553
err:
 
1554
  thd_proc_info(thd, "After create");
 
1555
  delete file;
 
1556
  DBUG_RETURN(error);
 
1557
 
 
1558
warn:
 
1559
  error= FALSE;
 
1560
  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
 
1561
                      ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
 
1562
                      alias);
 
1563
  create_info->table_existed= 1;                // Mark that table existed
 
1564
  goto unlock_and_end;
 
1565
}
 
1566
 
 
1567
////////////////////////////////////////////////////////
 
1568
////// END OF CUT AND PASTES FROM  sql_table.cc ////////
 
1569
////////////////////////////////////////////////////////
 
1570
 
 
1571
#endif // DRIZZLED
 
1572
#endif // LOCK_OPEN_HACK_REQUIRED
 
1573
 
 
1574
//------------------------------
 
1575
int xt_create_table_frm(handlerton *hton, THD* thd, const char *db, const char *name, DT_FIELD_INFO *info, DT_KEY_INFO *XT_UNUSED(keys), xtBool skip_existing)
 
1576
{
 
1577
#ifdef DRIZZLED
 
1578
#define MYLEX_CREATE_INFO create_info
 
1579
#else
 
1580
#define MYLEX_CREATE_INFO mylex.create_info 
 
1581
#endif
 
1582
 
 
1583
#ifdef DRIZZLED
 
1584
        drizzled::statement::AlterTable *stmt = new drizzled::statement::AlterTable(thd);
 
1585
        HA_CREATE_INFO create_info;
 
1586
        //AlterInfo alter_info;
 
1587
        drizzled::message::Table table_proto;
 
1588
 
 
1589
        static const char *ext = ".dfe";
 
1590
        static const int ext_len = 4;
 
1591
 
 
1592
        table_proto.mutable_engine()->mutable_name()->assign("PBXT");
 
1593
#else
 
1594
        static const char *ext = ".frm";
 
1595
        static const int ext_len = 4;
 
1596
#endif
 
1597
        int err = 1;
 
1598
        char field_length_buffer[12], *field_length_ptr;
 
1599
        LEX  *save_lex= thd->lex, mylex;
 
1600
 
 
1601
        memset(&MYLEX_CREATE_INFO, 0, sizeof(HA_CREATE_INFO));
 
1602
 
 
1603
        thd->lex = &mylex;
 
1604
        lex_start(thd);
 
1605
#ifdef DRIZZLED
 
1606
        mylex.statement = stmt;
 
1607
#endif
 
1608
        
 
1609
        /* setup the create info */
 
1610
        MYLEX_CREATE_INFO.db_type = hton;
 
1611
 
 
1612
#ifndef DRIZZLED 
 
1613
        mylex.create_info.frm_only = 1;
 
1614
#endif
 
1615
        MYLEX_CREATE_INFO.default_table_charset = system_charset_info;
 
1616
        
 
1617
        /* setup the column info. */
 
1618
        while (info->field_name) {              
 
1619
                 LEX_STRING field_name, comment;                 
 
1620
                 field_name.str = (char*)(info->field_name);
 
1621
                 field_name.length = strlen(info->field_name);
 
1622
                 
 
1623
                 comment.str = (char*)(info->comment);
 
1624
                 comment.length = strlen(info->comment);
 
1625
                                        
 
1626
                 if (info->field_length) {
 
1627
                        sprintf(field_length_buffer, "%d", info->field_length);
 
1628
                        field_length_ptr = field_length_buffer;
 
1629
                 } else 
 
1630
                        field_length_ptr = NULL;
 
1631
 
 
1632
#ifdef DRIZZLED
 
1633
                if (add_field_to_list(thd, &field_name, info->field_type, field_length_ptr, info->field_decimal_length,
 
1634
                        info->field_flags,
 
1635
            COLUMN_FORMAT_TYPE_FIXED,
 
1636
                    NULL /*default_value*/, NULL /*on_update_value*/, &comment, NULL /*change*/,
 
1637
            NULL /*interval_list*/, info->field_charset))
 
1638
#else
 
1639
                if (add_field_to_list(thd, &field_name, info->field_type, field_length_ptr, info->field_decimal_length,
 
1640
                        info->field_flags,
 
1641
#if MYSQL_VERSION_ID >= 50404
 
1642
                                HA_SM_DISK,
 
1643
                                COLUMN_FORMAT_TYPE_FIXED,
 
1644
#endif
 
1645
                       NULL /*default_value*/, NULL /*on_update_value*/, &comment, NULL /*change*/, 
 
1646
                       NULL /*interval_list*/, info->field_charset, 0 /*uint_geom_type*/)) 
 
1647
#endif
 
1648
                        goto error;
 
1649
 
 
1650
 
 
1651
                info++;
 
1652
        }
 
1653
 
 
1654
        if (skip_existing) {
 
1655
                size_t db_len = strlen(db);
 
1656
                size_t name_len = strlen(name);
 
1657
                size_t len = db_len + 1 + name_len + ext_len + 1;
 
1658
                char *path = (char *)xt_malloc_ns(len);
 
1659
                memcpy(path, db, db_len);
 
1660
                memcpy(path + db_len + 1, name, name_len);
 
1661
                memcpy(path + db_len + 1 + name_len, ext, ext_len);
 
1662
                path[db_len] = XT_DIR_CHAR;
 
1663
                path[len - 1] = '\0';
 
1664
                xtBool exists = xt_fs_exists(path);
 
1665
                xt_free_ns(path);
 
1666
                if (exists)
 
1667
                        goto noerror;
 
1668
        }
 
1669
        
 
1670
        /* Create an internal temp table */
 
1671
#ifdef DRIZZLED
 
1672
    table_proto.set_name(name);
 
1673
    table_proto.set_type(drizzled::message::Table::STANDARD);
 
1674
    table_proto.set_schema(db);
 
1675
    table_proto.set_creation_timestamp(time(NULL));
 
1676
    table_proto.set_update_timestamp(time(NULL));
 
1677
        if (mysql_create_table_no_lock(thd, db, name, &create_info, &table_proto, &stmt->alter_info, 1, 0, skip_existing)) 
 
1678
                goto error;
 
1679
#else
 
1680
        if (mysql_create_table_no_lock(thd, db, name, &mylex.create_info, &mylex.alter_info, 1, 0)) 
 
1681
                goto error;
 
1682
#endif
 
1683
 
 
1684
        noerror:
 
1685
        err = 0;
 
1686
 
 
1687
        error:
 
1688
        lex_end(&mylex);
 
1689
        thd->lex = save_lex;
 
1690
        return err;
 
1691
}
 
1692
 
 
1693
#endif
 
1694