~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2011-12-13 03:21:35 UTC
  • mto: This revision was merged to the branch mainline in revision 2475.
  • Revision ID: brian@tangent.org-20111213032135-8dta0336wn38uok9
Rmove PBMS (deprecated)

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