~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Added the PBMS daemon plugin.

(Augen zu und durch!)

Show diffs side-by-side

added added

removed removed

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