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

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-06-19 10:46:49 UTC
  • mfrom: (1.1.6)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20120619104649-e2l0ggd4oz3um0f4
Tags: upstream-7.1.36-stable
ImportĀ upstreamĀ versionĀ 7.1.36-stable

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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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<Create_field>::iterator it(alter_info->create_list);
216
 
  List<Create_field>::iterator 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<String>::iterator 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= alter_info->create_list;
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= alter_info->create_list;
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<Key>::iterator key_iterator(alter_info->key_list);
542
 
  List<Key>::iterator 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= alter_info->key_list;
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= alter_info->key_list;
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<Key_part_spec>::iterator cols(key->columns);
755
 
    List<Key_part_spec>::iterator cols2(key->columns);
756
 
    CHARSET_INFO *ft_key_charset=0;  // for FULLTEXT
757
 
    for (uint column_nr=0 ; (column=cols++) ; column_nr++)
758
 
    {
759
 
      uint length;
760
 
      Key_part_spec *dup_column;
761
 
 
762
 
      it= alter_info->create_list;
763
 
      field=0;
764
 
      while ((sql_field=it++) &&
765
 
             my_strcasecmp(system_charset_info,
766
 
                           column->DOT_STR(field_name),
767
 
                           sql_field->field_name))
768
 
        field++;
769
 
      if (!sql_field)
770
 
      {
771
 
        my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name);
772
 
        DBUG_RETURN(TRUE);
773
 
      }
774
 
      while ((dup_column= cols2++) != column)
775
 
      {
776
 
        if (!my_strcasecmp(system_charset_info,
777
 
                           column->DOT_STR(field_name), dup_column->DOT_STR(field_name)))
778
 
        {
779
 
          my_printf_error(ER_DUP_FIELDNAME,
780
 
                          ER(ER_DUP_FIELDNAME),MYF(0),
781
 
                          column->field_name);
782
 
          DBUG_RETURN(TRUE);
783
 
        }
784
 
      }
785
 
      cols2= key->columns;
786
 
      if (key->type == Key::FULLTEXT)
787
 
      {
788
 
        if ((sql_field->sql_type != MYSQL_TYPE_STRING &&
789
 
             sql_field->sql_type != MYSQL_TYPE_VARCHAR &&
790
 
             !f_is_blob(sql_field->pack_flag)) ||
791
 
            sql_field->charset == &my_charset_bin ||
792
 
            sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet
793
 
            (ft_key_charset && sql_field->charset != ft_key_charset))
794
 
        {
795
 
            my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name);
796
 
            DBUG_RETURN(-1);
797
 
        }
798
 
        ft_key_charset=sql_field->charset;
799
 
        /*
800
 
          for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
801
 
          code anyway, and 0 (set to column width later) for char's. it has
802
 
          to be correct col width for char's, as char data are not prefixed
803
 
          with length (unlike blobs, where ft code takes data length from a
804
 
          data prefix, ignoring column->length).
805
 
        */
806
 
        column->length=test(f_is_blob(sql_field->pack_flag));
807
 
      }
808
 
      else
809
 
      {
810
 
        column->length*= sql_field->charset->mbmaxlen;
811
 
 
812
 
        if (key->type == Key::SPATIAL && column->length)
813
 
        {
814
 
          my_error(ER_WRONG_SUB_KEY, MYF(0));
815
 
          DBUG_RETURN(TRUE);
816
 
        }
817
 
 
818
 
        if (f_is_blob(sql_field->pack_flag) ||
819
 
            (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
820
 
        {
821
 
          if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
822
 
          {
823
 
            my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name);
824
 
            DBUG_RETURN(TRUE);
825
 
          }
826
 
          if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
827
 
              Field::GEOM_POINT)
828
 
            column->length= 25;
829
 
          if (!column->length)
830
 
          {
831
 
            my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name);
832
 
            DBUG_RETURN(TRUE);
833
 
          }
834
 
        }
835
 
#ifdef HAVE_SPATIAL
836
 
        if (key->type == Key::SPATIAL)
837
 
        {
838
 
          if (!column->length)
839
 
          {
840
 
            /*
841
 
              4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
842
 
              Lately we'll extend this code to support more dimensions
843
 
            */
844
 
            column->length= 4*sizeof(double);
845
 
          }
846
 
        }
847
 
#endif
848
 
        if (!(sql_field->flags & NOT_NULL_FLAG))
849
 
        {
850
 
          if (key->type == Key::PRIMARY)
851
 
          {
852
 
            /* Implicitly set primary key fields to NOT NULL for ISO conf. */
853
 
            sql_field->flags|= NOT_NULL_FLAG;
854
 
            sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
855
 
            null_fields--;
856
 
          }
857
 
          else
858
 
          {
859
 
            key_info->flags|= HA_NULL_PART_KEY;
860
 
            if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
861
 
            {
862
 
              my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name);
863
 
              DBUG_RETURN(TRUE);
864
 
            }
865
 
            if (key->type == Key::SPATIAL)
866
 
            {
867
 
              my_message(ER_SPATIAL_CANT_HAVE_NULL,
868
 
                         ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
869
 
              DBUG_RETURN(TRUE);
870
 
            }
871
 
          }
872
 
        }
873
 
        if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
874
 
        {
875
 
          if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
876
 
            auto_increment--;                   // Field is used
877
 
        }
878
 
      }
879
 
 
880
 
      key_part_info->fieldnr= field;
881
 
      key_part_info->offset=  (uint16) sql_field->offset;
882
 
      key_part_info->key_type=sql_field->pack_flag;
883
 
      length= sql_field->key_length;
884
 
 
885
 
      if (column->length)
886
 
      {
887
 
        if (f_is_blob(sql_field->pack_flag))
888
 
        {
889
 
          if ((length=column->length) > max_key_length ||
890
 
              length > file->max_key_part_length())
891
 
          {
892
 
            length=min(max_key_length, file->max_key_part_length());
893
 
            if (key->type == Key::MULTIPLE)
894
 
            {
895
 
              /* not a critical problem */
896
 
              char warn_buff[MYSQL_ERRMSG_SIZE];
897
 
              my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
898
 
                          length);
899
 
              push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
900
 
                           ER_TOO_LONG_KEY, warn_buff);
901
 
              /* Align key length to multibyte char boundary */
902
 
              length-= length % sql_field->charset->mbmaxlen;
903
 
            }
904
 
            else
905
 
            {
906
 
              my_error(ER_TOO_LONG_KEY,MYF(0),length);
907
 
              DBUG_RETURN(TRUE);
908
 
            }
909
 
          }
910
 
        }
911
 
        else if (!f_is_geom(sql_field->pack_flag) &&
912
 
                  (column->length > length ||
913
 
                   !Field::type_can_have_key_part (sql_field->sql_type) ||
914
 
                   ((f_is_packed(sql_field->pack_flag) ||
915
 
                     ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
916
 
                      (key_info->flags & HA_NOSAME))) &&
917
 
                    column->length != length)))
918
 
        {
919
 
          my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
920
 
          DBUG_RETURN(TRUE);
921
 
        }
922
 
        else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
923
 
          length=column->length;
924
 
      }
925
 
      else if (length == 0)
926
 
      {
927
 
        my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name);
928
 
          DBUG_RETURN(TRUE);
929
 
      }
930
 
      if (length > file->max_key_part_length() && key->type != Key::FULLTEXT)
931
 
      {
932
 
        length= file->max_key_part_length();
933
 
        if (key->type == Key::MULTIPLE)
934
 
        {
935
 
          /* not a critical problem */
936
 
          char warn_buff[MYSQL_ERRMSG_SIZE];
937
 
          my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
938
 
                      length);
939
 
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
940
 
                       ER_TOO_LONG_KEY, warn_buff);
941
 
          /* Align key length to multibyte char boundary */
942
 
          length-= length % sql_field->charset->mbmaxlen;
943
 
        }
944
 
        else
945
 
        {
946
 
          my_error(ER_TOO_LONG_KEY,MYF(0),length);
947
 
          DBUG_RETURN(TRUE);
948
 
        }
949
 
      }
950
 
      key_part_info->length=(uint16) length;
951
 
      /* Use packed keys for long strings on the first column */
952
 
      if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
953
 
          (length >= KEY_DEFAULT_PACK_LENGTH &&
954
 
           (sql_field->sql_type == MYSQL_TYPE_STRING ||
955
 
            sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
956
 
            sql_field->pack_flag & FIELDFLAG_BLOB)))
957
 
      {
958
 
        if (column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB) ||
959
 
            sql_field->sql_type == MYSQL_TYPE_VARCHAR)
960
 
          key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
961
 
        else
962
 
          key_info->flags|= HA_PACK_KEY;
963
 
      }
964
 
      /* Check if the key segment is partial, set the key flag accordingly */
965
 
      if (length != sql_field->key_length)
966
 
        key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
967
 
 
968
 
      key_length+=length;
969
 
      key_part_info++;
970
 
 
971
 
      /* Create the key name based on the first column (if not given) */
972
 
      if (column_nr == 0)
973
 
      {
974
 
        if (key->type == Key::PRIMARY)
975
 
        {
976
 
          if (primary_key)
977
 
          {
978
 
            my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY),
979
 
                       MYF(0));
980
 
            DBUG_RETURN(TRUE);
981
 
          }
982
 
          key_name=primary_key_name;
983
 
          primary_key=1;
984
 
        }
985
 
        else if (!(key_name = key->DOT_STR(name)))
986
 
          key_name=make_unique_key_name(sql_field->field_name,
987
 
                                        *key_info_buffer, key_info);
988
 
        if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
989
 
        {
990
 
          my_error(ER_DUP_KEYNAME, MYF(0), key_name);
991
 
          DBUG_RETURN(TRUE);
992
 
        }
993
 
        key_info->name=(char*) key_name;
994
 
      }
995
 
    }
996
 
    if (!key_info->name || check_column_name(key_info->name))
997
 
    {
998
 
      my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
999
 
      DBUG_RETURN(TRUE);
1000
 
    }
1001
 
    if (!(key_info->flags & HA_NULL_PART_KEY))
1002
 
      unique_key=1;
1003
 
    key_info->key_length=(uint16) key_length;
1004
 
    if (key_length > max_key_length && key->type != Key::FULLTEXT)
1005
 
    {
1006
 
      my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
1007
 
      DBUG_RETURN(TRUE);
1008
 
    }
1009
 
    key_info++;
1010
 
  }
1011
 
  if (!unique_key && !primary_key &&
1012
 
      (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
1013
 
  {
1014
 
    my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
1015
 
    DBUG_RETURN(TRUE);
1016
 
  }
1017
 
  if (auto_increment > 0)
1018
 
  {
1019
 
    my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
1020
 
    DBUG_RETURN(TRUE);
1021
 
  }
1022
 
  /* Sort keys in optimized order */
1023
 
  my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
1024
 
           (qsort_cmp) sort_keys);
1025
 
  create_info->null_bits= null_fields;
1026
 
 
1027
 
  /* Check fields. */
1028
 
  it= alter_info->create_list;
1029
 
  while ((sql_field=it++))
1030
 
  {
1031
 
    Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
1032
 
 
1033
 
    if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
1034
 
        !sql_field->def &&
1035
 
        sql_field->sql_type == MYSQL_TYPE_TIMESTAMP &&
1036
 
        (sql_field->flags & NOT_NULL_FLAG) &&
1037
 
        (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
1038
 
    {
1039
 
      /*
1040
 
        An error should be reported if:
1041
 
          - NO_ZERO_DATE SQL mode is active;
1042
 
          - there is no explicit DEFAULT clause (default column value);
1043
 
          - this is a TIMESTAMP column;
1044
 
          - the column is not NULL;
1045
 
          - this is not the DEFAULT CURRENT_TIMESTAMP column.
1046
 
 
1047
 
        In other words, an error should be reported if
1048
 
          - NO_ZERO_DATE SQL mode is active;
1049
 
          - the column definition is equivalent to
1050
 
            'column_name TIMESTAMP DEFAULT 0'.
1051
 
      */
1052
 
 
1053
 
      my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
1054
 
      DBUG_RETURN(TRUE);
1055
 
    }
1056
 
  }
1057
 
 
1058
 
  DBUG_RETURN(FALSE);
1059
 
}
1060
 
 
1061
 
//////////////////////////////
1062
 
// mysql_create_table_no_lock() cut and pasted directly from sql_table.cc. (I did make is static after copying it.)
1063
 
 
1064
 
static bool mysql_create_table_no_lock(THD *thd,
1065
 
                                const char *db, const char *table_name,
1066
 
                                HA_CREATE_INFO *create_info,
1067
 
                                Alter_info *alter_info,
1068
 
                                bool internal_tmp_table,
1069
 
                                uint select_field_count)
1070
 
{
1071
 
  char                  path[FN_REFLEN];
1072
 
  uint          path_length;
1073
 
  const char    *alias;
1074
 
  uint                  db_options, key_count;
1075
 
  KEY                   *key_info_buffer;
1076
 
  handler               *file;
1077
 
  bool                  error= TRUE;
1078
 
  DBUG_ENTER("mysql_create_table_no_lock");
1079
 
  DBUG_PRINT("enter", ("db: '%s'  table: '%s'  tmp: %d",
1080
 
                       db, table_name, internal_tmp_table));
1081
 
 
1082
 
 
1083
 
  /* Check for duplicate fields and check type of table to create */
1084
 
  if (!alter_info->create_list.elements)
1085
 
  {
1086
 
    my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
1087
 
               MYF(0));
1088
 
    DBUG_RETURN(TRUE);
1089
 
  }
1090
 
  if (check_engine(thd, table_name, create_info))
1091
 
    DBUG_RETURN(TRUE);
1092
 
  db_options= create_info->table_options;
1093
 
  if (create_info->row_type == ROW_TYPE_DYNAMIC)
1094
 
    db_options|=HA_OPTION_PACK_RECORD;
1095
 
  alias= table_case_name(create_info, table_name);
1096
 
 
1097
 
  /* PMC - Done to avoid getting the partition handler by mistake! */
1098
 
  if (!(file= new (thd->mem_root) ha_pbms(pbms_hton, NULL)))
1099
 
  {
1100
 
        mem_alloc_error(sizeof(handler));
1101
 
        DBUG_RETURN(TRUE);
1102
 
  }
1103
 
 
1104
 
  file->init();
1105
 
  
1106
 
  set_table_default_charset(thd, create_info, (char*) db);
1107
 
 
1108
 
  if (mysql_prepare_create_table(thd, create_info, alter_info,
1109
 
                                 internal_tmp_table,
1110
 
                                 &db_options, file,
1111
 
                                 &key_info_buffer, &key_count,
1112
 
                                 select_field_count))
1113
 
    goto err;
1114
 
 
1115
 
      /* Check if table exists */
1116
 
  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
1117
 
  {
1118
 
    path_length= build_tmptable_filename(thd, path, sizeof(path));
1119
 
    create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
1120
 
  }
1121
 
  else  
1122
 
  {
1123
 
 #ifdef FN_DEVCHAR
1124
 
    /* check if the table name contains FN_DEVCHAR when defined */
1125
 
    if (strchr(alias, FN_DEVCHAR))
1126
 
    {
1127
 
      my_error(ER_WRONG_TABLE_NAME, MYF(0), alias);
1128
 
      DBUG_RETURN(TRUE);
1129
 
    }
1130
 
#endif
1131
 
    path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext,
1132
 
                                      internal_tmp_table ? FN_IS_TMP : 0);
1133
 
  }
1134
 
 
1135
 
  /* Check if table already exists */
1136
 
  if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
1137
 
      find_temporary_table(thd, db, table_name))
1138
 
  {
1139
 
    if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
1140
 
    {
1141
 
      create_info->table_existed= 1;            // Mark that table existed
1142
 
      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
1143
 
                          ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1144
 
                          alias);
1145
 
      error= 0;
1146
 
      goto err;
1147
 
    }
1148
 
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
1149
 
    goto err;
1150
 
  }
1151
 
 
1152
 
  pthread_mutex_lock(&LOCK_open);
1153
 
  if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
1154
 
  {
1155
 
    if (!access(path,F_OK))
1156
 
    {
1157
 
      if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
1158
 
        goto warn;
1159
 
      my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
1160
 
      goto unlock_and_end;
1161
 
    }
1162
 
    /*
1163
 
      We don't assert here, but check the result, because the table could be
1164
 
      in the table definition cache and in the same time the .frm could be
1165
 
      missing from the disk, in case of manual intervention which deletes
1166
 
      the .frm file. The user has to use FLUSH TABLES; to clear the cache.
1167
 
      Then she could create the table. This case is pretty obscure and
1168
 
      therefore we don't introduce a new error message only for it.
1169
 
    */
1170
 
    if (get_cached_table_share(db, alias))
1171
 
    {
1172
 
      my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
1173
 
      goto unlock_and_end;
1174
 
    }
1175
 
  }
1176
 
 
1177
 
  /*
1178
 
    Check that table with given name does not already
1179
 
    exist in any storage engine. In such a case it should
1180
 
    be discovered and the error ER_TABLE_EXISTS_ERROR be returned
1181
 
    unless user specified CREATE TABLE IF EXISTS
1182
 
    The LOCK_open mutex has been locked to make sure no
1183
 
    one else is attempting to discover the table. Since
1184
 
    it's not on disk as a frm file, no one could be using it!
1185
 
  */
1186
 
  if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
1187
 
  {
1188
 
    bool create_if_not_exists =
1189
 
      create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
1190
 
    int retcode = ha_table_exists_in_engine(thd, db, table_name);
1191
 
    DBUG_PRINT("info", ("exists_in_engine: %"PRIu32"",retcode));
1192
 
    switch (retcode)
1193
 
    {
1194
 
      case HA_ERR_NO_SUCH_TABLE:
1195
 
        /* Normal case, no table exists. we can go and create it */
1196
 
        break;
1197
 
      case HA_ERR_TABLE_EXIST:
1198
 
        DBUG_PRINT("info", ("Table existed in handler"));
1199
 
 
1200
 
        if (create_if_not_exists)
1201
 
          goto warn;
1202
 
        my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
1203
 
        goto unlock_and_end;
1204
 
        break;
1205
 
      default:
1206
 
        DBUG_PRINT("info", ("error: %"PRIu32" from storage engine", retcode));
1207
 
        my_error(retcode, MYF(0),table_name);
1208
 
        goto unlock_and_end;
1209
 
    }
1210
 
  }
1211
 
 
1212
 
  thd_proc_info(thd, "creating table");
1213
 
  create_info->table_existed= 0;                // Mark that table is created
1214
 
 
1215
 
  create_info->table_options=db_options;
1216
 
 
1217
 
  path[path_length - reg_ext_length]= '\0'; // Remove .frm extension
1218
 
  if (rea_create_table(thd, path, db, table_name,
1219
 
                       create_info, alter_info->create_list,
1220
 
                       key_count, key_info_buffer, file))
1221
 
    goto unlock_and_end;
1222
 
 
1223
 
  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
1224
 
  {
1225
 
    /* Open table and put in temporary table list */
1226
 
#if MYSQL_VERSION_ID > 60005
1227
 
    if (!(open_temporary_table(thd, path, db, table_name, 1, OTM_OPEN)))
1228
 
#else
1229
 
    if (!(open_temporary_table(thd, path, db, table_name, 1)))
1230
 
#endif
1231
 
    {
1232
 
#if MYSQL_VERSION_ID > 60005
1233
 
      (void) rm_temporary_table(create_info->db_type, path, false);
1234
 
#else
1235
 
      (void) rm_temporary_table(create_info->db_type, path);
1236
 
#endif
1237
 
      goto unlock_and_end;
1238
 
    }
1239
 
    thd->thread_specific_used= TRUE;
1240
 
  }
1241
 
 
1242
 
  /*
1243
 
    Don't write statement if:
1244
 
    - It is an internal temporary table,
1245
 
    - Row-based logging is used and it we are creating a temporary table, or
1246
 
    - The binary log is not open.
1247
 
    Otherwise, the statement shall be binlogged.
1248
 
   */
1249
 
  if (!internal_tmp_table &&
1250
 
      (!thd->current_stmt_binlog_row_based ||
1251
 
       (thd->current_stmt_binlog_row_based &&
1252
 
        !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
1253
 
#if MYSQL_VERSION_ID > 50140
1254
 
   write_bin_log(thd, TRUE, thd->query(), thd->query_length());
1255
 
#else
1256
 
    write_bin_log(thd, TRUE, thd->query, thd->query_length);
1257
 
#endif
1258
 
  error= FALSE;
1259
 
unlock_and_end:
1260
 
  pthread_mutex_unlock(&LOCK_open);
1261
 
 
1262
 
err:
1263
 
  thd_proc_info(thd, "After create");
1264
 
  delete file;
1265
 
  DBUG_RETURN(error);
1266
 
 
1267
 
warn:
1268
 
  error= FALSE;
1269
 
  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
1270
 
                      ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1271
 
                      alias);
1272
 
  create_info->table_existed= 1;                // Mark that table existed
1273
 
  goto unlock_and_end;
1274
 
}
1275
 
 
1276
 
////////////////////////////////////////////////////////
1277
 
////// END OF CUT AND PASTES FROM  sql_table.cc ////////
1278
 
////////////////////////////////////////////////////////
1279
 
 
1280
 
#endif // LOCK_OPEN_HACK_REQUIRED
1281
 
 
1282
 
//#define HAVE_KEYS
1283
 
//------------------------------
1284
 
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 )
1285
 
{
1286
 
        char file_name[FN_REFLEN];
1287
 
        int err = 1, delete_frm = 0;
1288
 
        char field_length_buffer[12], *field_length_ptr;
1289
 
        LEX  *save_lex= thd->lex, mylex;
1290
 
        
1291
 
        memset(&mylex.create_info, 0, sizeof(HA_CREATE_INFO));
1292
 
 
1293
 
        thd->lex = &mylex;
1294
 
    lex_start(thd);
1295
 
        
1296
 
        /* setup the create info */
1297
 
        mylex.create_info.db_type = hton;
1298
 
        mylex.create_info.frm_only = 1;
1299
 
        mylex.create_info.default_table_charset = system_charset_info;
1300
 
        
1301
 
        /* setup the column info. */
1302
 
        while (info->field_name) {              
1303
 
                 LEX_STRING field_name, comment;                 
1304
 
                 field_name.str = (char*)(info->field_name);
1305
 
                 field_name.length = strlen(info->field_name);
1306
 
                 
1307
 
                 comment.str = (char*)(info->comment);
1308
 
                 comment.length = strlen(info->comment);
1309
 
                                        
1310
 
                 if (info->field_length) {
1311
 
                        snprintf(field_length_buffer, 12, "%d", info->field_length);
1312
 
                        field_length_ptr = field_length_buffer;
1313
 
                 } else 
1314
 
                        field_length_ptr = NULL;
1315
 
 
1316
 
                if (add_field_to_list(thd, &field_name, info->field_type, field_length_ptr, info->field_decimal_length,
1317
 
                        info->field_flags,
1318
 
#if MYSQL_VERSION_ID > 60005
1319
 
                                HA_SM_DISK,
1320
 
                                COLUMN_FORMAT_TYPE_FIXED,
1321
 
#endif
1322
 
                       NULL /*default_value*/, NULL /*on_update_value*/, &comment, NULL /*change*/, 
1323
 
                       NULL /*interval_list*/, info->field_charset, 0 /*uint_geom_type*/)) 
1324
 
                        goto error;
1325
 
 
1326
 
 
1327
 
                info++;
1328
 
        }
1329
 
 
1330
 
        if (keys) {
1331
 
#ifdef HAVE_KEYS
1332
 
                while (keys->key_name) {
1333
 
                        LEX_STRING lex;
1334
 
                        Key *key;
1335
 
                        enum Key::Keytype type;
1336
 
                        List<Key_part_spec> col_list;
1337
 
                        int i =0;
1338
 
                        while (keys->key_columns[i]) {
1339
 
                                lex.str = (char *)(keys->key_columns[i++]);
1340
 
                                lex.length = strlen(lex.str);
1341
 
                                col_list.push_back(new Key_part_spec(lex, 0));
1342
 
                                //col_list.push_back(new Key_part_spec(keys->key_columns[i++], 0));
1343
 
                        }
1344
 
                        
1345
 
                        switch (keys->key_type) {
1346
 
                                case PRI_KEY_FLAG:
1347
 
                                        type = Key::PRIMARY;
1348
 
                                        break;
1349
 
                                case UNIQUE_KEY_FLAG:
1350
 
                                        type = Key::UNIQUE;
1351
 
                                        break;
1352
 
                                case MULTIPLE_KEY_FLAG:
1353
 
                                        type = Key::MULTIPLE;
1354
 
                                        break;
1355
 
                        }
1356
 
                        
1357
 
                        key= new Key(type, keys->key_name, strlen(keys->key_name),
1358
 
                                                          &default_key_create_info,
1359
 
                                                          0, col_list);
1360
 
                        mylex.alter_info.key_list.push_back(key);
1361
 
                        col_list.empty();
1362
 
                        keys++;
1363
 
                }
1364
 
#endif
1365
 
        }
1366
 
        
1367
 
        /* Create an internal temp table */
1368
 
        if (mysql_create_table_no_lock(thd, db, name, &mylex.create_info, &mylex.alter_info, 1, 0)) 
1369
 
                goto error;
1370
 
 
1371
 
        delete_frm = 1;
1372
 
        /* Read the FRM file. */
1373
 
        build_table_filename(file_name, sizeof(file_name), db, name, "", FN_IS_TMP);
1374
 
        if (readfrm(file_name, frmblob, frmlen)) 
1375
 
                goto error;
1376
 
 
1377
 
        err = 0;
1378
 
 
1379
 
error:
1380
 
        lex_end(&mylex);
1381
 
        thd->lex = save_lex;
1382
 
        
1383
 
        if (delete_frm) {
1384
 
                build_table_filename(file_name, sizeof(file_name), db, name, reg_ext, FN_IS_TMP);
1385
 
                my_delete(file_name, MYF(0));
1386
 
        }
1387
 
        return err;
1388
 
}
1389
 
 
1390
 
#endif // DRIZZLED