~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-06-28 16:17:36 UTC
  • mfrom: (1637.4.1 drizzle)
  • Revision ID: brian@gaz-20100628161736-eormhb2mnd551i2h
MergeĀ unused

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_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
 
  pthread_mutex_lock(&LOCK_open);
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
 
  pthread_mutex_unlock(&LOCK_open);
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