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

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

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