~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to plugin/pbms/src/discover_ms.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-10-02 14:17:48 UTC
  • mfrom: (1.1.1 upstream)
  • mto: (2.1.17 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20101002141748-m6vbfbfjhrw1153e
Tags: 2010.09.1802-1
* New upstream release.
* Removed pid-file argument hack.
* Updated GPL-2 address to be new address.
* Directly copy in drizzledump.1 since debian doesn't have sphinx 1.0 yet.
* Link to jquery from libjs-jquery. Add it as a depend.
* Add drizzled.8 symlink to the install files.

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