~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/unireg.cc

  • Committer: Monty Taylor
  • Date: 2008-10-22 23:45:01 UTC
  • Revision ID: monty@inaugust.com-20081022234501-hwybvprata8ba98l
Moved handler_error_messages array out of header file. Moved associated
functions to live with it.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
 
 
16
 
#include "config.h"
17
 
#include <drizzled/error.h>
18
 
#include <drizzled/session.h>
19
 
#include <drizzled/unireg.h>
20
 
#include "drizzled/sql_table.h"
21
 
#include "drizzled/global_charset_info.h"
22
 
#include "drizzled/message/statement_transform.h"
23
 
 
24
 
#include "drizzled/internal/my_sys.h"
25
 
 
26
 
 
27
 
/* For proto */
28
 
#include <string>
29
 
#include <fstream>
30
 
#include <fcntl.h>
31
 
#include <drizzled/message/schema.pb.h>
32
 
#include <drizzled/message/table.pb.h>
33
 
#include <google/protobuf/io/zero_copy_stream.h>
34
 
#include <google/protobuf/io/zero_copy_stream_impl.h>
35
 
#include <google/protobuf/message.h>
36
 
 
37
 
#include <drizzled/table_proto.h>
38
 
#include <drizzled/charset.h>
39
 
 
40
 
#include "drizzled/function/time/typecast.h"
41
 
 
42
 
using namespace std;
43
 
 
44
 
namespace drizzled {
45
 
 
46
 
static int fill_table_proto(message::Table &table_proto,
47
 
                            List<CreateField> &create_fields,
48
 
                            HA_CREATE_INFO *create_info,
49
 
                            uint32_t keys,
50
 
                            KeyInfo *key_info)
51
 
{
52
 
  CreateField *field_arg;
53
 
  List_iterator<CreateField> it(create_fields);
54
 
  message::Table::TableOptions *table_options= table_proto.mutable_options();
55
 
 
56
 
  if (create_fields.elements > MAX_FIELDS)
57
 
  {
58
 
    my_error(ER_TOO_MANY_FIELDS, MYF(0), ER(ER_TOO_MANY_FIELDS));
59
 
    return(1);
60
 
  }
61
 
 
62
 
  assert(strcmp(table_proto.engine().name().c_str(),
63
 
                create_info->db_type->getName().c_str())==0);
64
 
 
65
 
  int field_number= 0;
66
 
  bool use_existing_fields= table_proto.field_size() > 0;
67
 
  while ((field_arg= it++))
68
 
  {
69
 
    message::Table::Field *attribute;
70
 
 
71
 
    /* some (one) code path for CREATE TABLE fills the proto
72
 
       out more than the others, so we already have partially
73
 
       filled out Field messages */
74
 
 
75
 
    if (use_existing_fields)
76
 
      attribute= table_proto.mutable_field(field_number++);
77
 
    else
78
 
    {
79
 
      /* Other code paths still have to fill out the proto */
80
 
      attribute= table_proto.add_field();
81
 
 
82
 
      if (field_arg->flags & NOT_NULL_FLAG)
83
 
      {
84
 
        message::Table::Field::FieldConstraints *constraints;
85
 
 
86
 
        constraints= attribute->mutable_constraints();
87
 
        constraints->set_is_nullable(false);
88
 
      }
89
 
 
90
 
      attribute->set_name(field_arg->field_name);
91
 
    }
92
 
 
93
 
    assert((!(field_arg->flags & NOT_NULL_FLAG)) == attribute->constraints().is_nullable());
94
 
    assert(strcmp(attribute->name().c_str(), field_arg->field_name)==0);
95
 
 
96
 
 
97
 
    message::Table::Field::FieldType parser_type= attribute->type();
98
 
 
99
 
    if (field_arg->sql_type == DRIZZLE_TYPE_NULL)
100
 
    {
101
 
      my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), table_proto.name().c_str(), -1);
102
 
      return -1;
103
 
    }
104
 
 
105
 
    attribute->set_type(message::internalFieldTypeToFieldProtoType(field_arg->sql_type));
106
 
 
107
 
    switch (attribute->type()) {
108
 
    default: /* Only deal with types that need extra information */
109
 
      break;
110
 
    case message::Table::Field::DOUBLE:
111
 
      {
112
 
        /*
113
 
         * For DOUBLE, we only add a specific scale and precision iff
114
 
         * the fixed decimal point has been specified...
115
 
         */
116
 
        if (field_arg->decimals != NOT_FIXED_DEC)
117
 
        {
118
 
          message::Table::Field::NumericFieldOptions *numeric_field_options;
119
 
 
120
 
          numeric_field_options= attribute->mutable_numeric_options();
121
 
 
122
 
          numeric_field_options->set_precision(field_arg->length);
123
 
          numeric_field_options->set_scale(field_arg->decimals);
124
 
        }
125
 
      }
126
 
      break;
127
 
    case message::Table::Field::VARCHAR:
128
 
      {
129
 
        message::Table::Field::StringFieldOptions *string_field_options;
130
 
 
131
 
        string_field_options= attribute->mutable_string_options();
132
 
 
133
 
        if (! use_existing_fields || string_field_options->length()==0)
134
 
          string_field_options->set_length(field_arg->length
135
 
                                           / field_arg->charset->mbmaxlen);
136
 
        else
137
 
          assert((uint32_t)string_field_options->length() == (uint32_t)(field_arg->length / field_arg->charset->mbmaxlen));
138
 
 
139
 
        if (! string_field_options->has_collation())
140
 
        {
141
 
          string_field_options->set_collation_id(field_arg->charset->number);
142
 
          string_field_options->set_collation(field_arg->charset->name);
143
 
        }
144
 
        break;
145
 
      }
146
 
    case message::Table::Field::DECIMAL:
147
 
      {
148
 
        message::Table::Field::NumericFieldOptions *numeric_field_options;
149
 
 
150
 
        numeric_field_options= attribute->mutable_numeric_options();
151
 
        /* This is magic, I hate magic numbers -Brian */
152
 
        numeric_field_options->set_precision(field_arg->length + ( field_arg->decimals ? -2 : -1));
153
 
        numeric_field_options->set_scale(field_arg->decimals);
154
 
        break;
155
 
      }
156
 
    case message::Table::Field::ENUM:
157
 
      {
158
 
        message::Table::Field::EnumerationValues *enumeration_options;
159
 
 
160
 
        assert(field_arg->interval);
161
 
 
162
 
        enumeration_options= attribute->mutable_enumeration_values();
163
 
 
164
 
        for (uint32_t pos= 0; pos < field_arg->interval->count; pos++)
165
 
        {
166
 
          const char *src= field_arg->interval->type_names[pos];
167
 
 
168
 
          enumeration_options->add_field_value(src);
169
 
        }
170
 
        enumeration_options->set_collation_id(field_arg->charset->number);
171
 
        enumeration_options->set_collation(field_arg->charset->name);
172
 
        break;
173
 
      }
174
 
    case message::Table::Field::BLOB:
175
 
      {
176
 
        message::Table::Field::StringFieldOptions *string_field_options;
177
 
 
178
 
        string_field_options= attribute->mutable_string_options();
179
 
        string_field_options->set_collation_id(field_arg->charset->number);
180
 
        string_field_options->set_collation(field_arg->charset->name);
181
 
      }
182
 
 
183
 
      break;
184
 
    }
185
 
 
186
 
    assert (!use_existing_fields || parser_type == attribute->type());
187
 
 
188
 
#ifdef NOTDONE
189
 
    field_constraints= attribute->mutable_constraints();
190
 
    constraints->set_is_nullable(field_arg->def->null_value);
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/*
 
18
  Functions to create a unireg form-file from a FIELD and a fieldname-fieldinfo
 
19
  struct.
 
20
  In the following functions FIELD * is an ordinary field-structure with
 
21
  the following exeptions:
 
22
    sc_length,typepos,row,kol,dtype,regnr and field need not to be set.
 
23
    str is a (long) to record position where 0 is the first position.
 
24
*/
 
25
 
 
26
#include <drizzled/server_includes.h>
 
27
#include <drizzled/drizzled_error_messages.h>
 
28
 
 
29
#define FCOMP                   17              /* Bytes for a packed field */
 
30
 
 
31
static unsigned char * pack_screens(List<Create_field> &create_fields,
 
32
                            uint32_t *info_length, uint32_t *screens, bool small_file);
 
33
static uint32_t pack_keys(unsigned char *keybuff,uint32_t key_count, KEY *key_info,
 
34
                      ulong data_offset);
 
35
static bool pack_header(unsigned char *forminfo,
 
36
                        List<Create_field> &create_fields,
 
37
                        uint32_t info_length, uint32_t screens, uint32_t table_options,
 
38
                        ulong data_offset, handler *file);
 
39
static uint32_t get_interval_id(uint32_t *int_count,List<Create_field> &create_fields,
 
40
                            Create_field *last_field);
 
41
static bool pack_fields(File file, List<Create_field> &create_fields,
 
42
                        ulong data_offset);
 
43
static bool make_empty_rec(Session *session, int file, enum legacy_db_type table_type,
 
44
                           uint32_t table_options,
 
45
                           List<Create_field> &create_fields,
 
46
                           uint32_t reclength, ulong data_offset,
 
47
                           handler *handler);
 
48
 
 
49
/**
 
50
  An interceptor to hijack ER_TOO_MANY_FIELDS error from
 
51
  pack_screens and retry again without UNIREG screens.
 
52
 
 
53
  XXX: what is a UNIREG  screen?
 
54
*/
 
55
 
 
56
struct Pack_header_error_handler: public Internal_error_handler
 
57
{
 
58
  virtual bool handle_error(uint32_t sql_errno,
 
59
                            const char *message,
 
60
                            DRIZZLE_ERROR::enum_warning_level level,
 
61
                            Session *session);
 
62
  bool is_handled;
 
63
  Pack_header_error_handler() :is_handled(false) {}
 
64
};
 
65
 
 
66
 
 
67
bool
 
68
Pack_header_error_handler::
 
69
handle_error(uint32_t sql_errno,
 
70
             const char * /* message */,
 
71
             DRIZZLE_ERROR::enum_warning_level /* level */,
 
72
             Session * /* session */)
 
73
{
 
74
  is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
 
75
  return is_handled;
 
76
}
 
77
 
 
78
/*
 
79
  Create a frm (table definition) file
 
80
 
 
81
  SYNOPSIS
 
82
    mysql_create_frm()
 
83
    session                     Thread handler
 
84
    file_name           Path for file (including database and .frm)
 
85
    db                  Name of database
 
86
    table               Name of table
 
87
    create_info         create info parameters
 
88
    create_fields       Fields to create
 
89
    keys                number of keys to create
 
90
    key_info            Keys to create
 
91
    db_file             Handler to use. May be zero, in which case we use
 
92
                        create_info->db_type
 
93
  RETURN
 
94
    0  ok
 
95
    1  error
 
96
*/
 
97
 
 
98
bool mysql_create_frm(Session *session, const char *file_name,
 
99
                      const char *db, const char *table,
 
100
                      HA_CREATE_INFO *create_info,
 
101
                      List<Create_field> &create_fields,
 
102
                      uint32_t keys, KEY *key_info,
 
103
                      handler *db_file)
 
104
{
 
105
  LEX_STRING str_db_type;
 
106
  uint32_t reclength, info_length, screens, key_info_length, maxlength, tmp_len;
 
107
  ulong key_buff_length;
 
108
  File file;
 
109
  ulong filepos, data_offset;
 
110
  unsigned char fileinfo[64],forminfo[288],*keybuff;
 
111
  TYPELIB formnames;
 
112
  unsigned char *screen_buff;
 
113
  char buff[128];
 
114
  const uint32_t format_section_header_size= 8;
 
115
  uint32_t format_section_len;
 
116
  Pack_header_error_handler pack_header_error_handler;
 
117
  int error;
 
118
 
 
119
  assert(*fn_rext((char*)file_name)); // Check .frm extension
 
120
  formnames.type_names=0;
 
121
  if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
 
122
    return(1);
 
123
  assert(db_file != NULL);
 
124
 
 
125
 /* If fixed row records, we need one bit to check for deleted rows */
 
126
  if (!(create_info->table_options & HA_OPTION_PACK_RECORD))
 
127
    create_info->null_bits++;
 
128
  data_offset= (create_info->null_bits + 7) / 8;
 
129
 
 
130
  session->push_internal_handler(&pack_header_error_handler);
 
131
 
 
132
  error= pack_header(forminfo,
 
133
                     create_fields,info_length,
 
134
                     screens, create_info->table_options,
 
135
                     data_offset, db_file);
 
136
 
 
137
  session->pop_internal_handler();
 
138
 
 
139
  if (error)
 
140
  {
 
141
    free(screen_buff);
 
142
    if (! pack_header_error_handler.is_handled)
 
143
      return(1);
 
144
 
 
145
    // Try again without UNIREG screens (to get more columns)
 
146
    if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
 
147
      return(1);
 
148
    if (pack_header(forminfo,
 
149
                    create_fields,info_length,
 
150
                    screens, create_info->table_options, data_offset, db_file))
 
151
    {
 
152
      free(screen_buff);
 
153
      return(1);
 
154
    }
 
155
  }
 
156
  reclength=uint2korr(forminfo+266);
 
157
 
 
158
  /* Calculate extra data segment length */
 
159
  str_db_type.str= (char *) ha_resolve_storage_engine_name(create_info->db_type);
 
160
  str_db_type.length= strlen(str_db_type.str);
 
161
  /* str_db_type */
 
162
  create_info->extra_size= (2 + str_db_type.length +
 
163
                            2 + create_info->connect_string.length);
 
164
  /*
 
165
    Partition:
 
166
      Length of partition info = 4 byte
 
167
      Potential NULL byte at end of partition info string = 1 byte
 
168
      Indicator if auto-partitioned table = 1 byte
 
169
      => Total 6 byte
 
170
  */
 
171
  create_info->extra_size+= 6;
 
172
 
 
173
  /* Add space for storage type and field format array of fields */
 
174
  format_section_len=
 
175
    format_section_header_size + 1 + create_fields.elements;
 
176
  create_info->extra_size+= format_section_len;
 
177
 
 
178
  tmp_len= system_charset_info->cset->charpos(system_charset_info,
 
179
                                              create_info->comment.str,
 
180
                                              create_info->comment.str +
 
181
                                              create_info->comment.length, 
 
182
                                              TABLE_COMMENT_MAXLEN);
 
183
 
 
184
  if (tmp_len < create_info->comment.length)
 
185
  {
 
186
    my_error(ER_WRONG_STRING_LENGTH, MYF(0),
 
187
             create_info->comment.str,"Table COMMENT",
 
188
             (uint) TABLE_COMMENT_MAXLEN);
 
189
    free(screen_buff);
 
190
    return(1);
 
191
  }
 
192
 
 
193
  //if table comment is larger than 180 bytes, store into extra segment.
 
194
  if (create_info->comment.length > 180)
 
195
  {
 
196
    forminfo[46]=255;
 
197
    create_info->extra_size+= 2 + create_info->comment.length;
 
198
  }
 
199
  else{
 
200
    strmake((char*) forminfo+47, create_info->comment.str ?
 
201
            create_info->comment.str : "", create_info->comment.length);
 
202
    forminfo[46]=(unsigned char) create_info->comment.length;
 
203
#ifdef EXTRA_DEBUG
 
204
    /*
 
205
      EXTRA_DEBUG causes strmake() to initialize its buffer behind the
 
206
      payload with a magic value to detect wrong buffer-sizes. We
 
207
      explicitly zero that segment again.
 
208
    */
 
209
    memset(forminfo+47 + forminfo[46], 0, 61 - forminfo[46]);
191
210
#endif
192
 
 
193
 
    if (field_arg->comment.length)
194
 
    {
195
 
      uint32_t tmp_len;
196
 
      tmp_len= system_charset_info->cset->charpos(system_charset_info,
197
 
                                                  field_arg->comment.str,
198
 
                                                  field_arg->comment.str +
199
 
                                                  field_arg->comment.length,
200
 
                                                  COLUMN_COMMENT_MAXLEN);
201
 
 
202
 
      if (tmp_len < field_arg->comment.length)
203
 
      {
204
 
        my_error(ER_WRONG_STRING_LENGTH, MYF(0),
205
 
                 field_arg->comment.str,"COLUMN COMMENT",
206
 
                 (uint32_t) COLUMN_COMMENT_MAXLEN);
207
 
        return(1);
208
 
      }
209
 
 
210
 
      if (! use_existing_fields)
211
 
        attribute->set_comment(field_arg->comment.str);
212
 
 
213
 
      assert(strcmp(attribute->comment().c_str(), field_arg->comment.str)==0);
214
 
    }
215
 
 
216
 
    if (field_arg->unireg_check == Field::NEXT_NUMBER)
217
 
    {
218
 
      message::Table::Field::NumericFieldOptions *field_options;
219
 
      field_options= attribute->mutable_numeric_options();
220
 
      field_options->set_is_autoincrement(true);
221
 
    }
222
 
 
223
 
    if (field_arg->unireg_check == Field::TIMESTAMP_DN_FIELD
224
 
       || field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
225
 
    {
226
 
      message::Table::Field::FieldOptions *field_options;
227
 
      field_options= attribute->mutable_options();
228
 
      field_options->set_default_expression("CURRENT_TIMESTAMP");
229
 
    }
230
 
 
231
 
    if (field_arg->unireg_check == Field::TIMESTAMP_UN_FIELD
232
 
       || field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
233
 
    {
234
 
      message::Table::Field::FieldOptions *field_options;
235
 
      field_options= attribute->mutable_options();
236
 
      field_options->set_update_expression("CURRENT_TIMESTAMP");
237
 
    }
238
 
 
239
 
    if (field_arg->def == NULL  && attribute->constraints().is_nullable())
240
 
    {
241
 
      message::Table::Field::FieldOptions *field_options;
242
 
      field_options= attribute->mutable_options();
243
 
 
244
 
      field_options->set_default_null(true);
245
 
    }
246
 
    if (field_arg->def)
247
 
    {
248
 
      message::Table::Field::FieldOptions *field_options;
249
 
      field_options= attribute->mutable_options();
250
 
 
251
 
      if (field_arg->def->is_null())
252
 
      {
253
 
        field_options->set_default_null(true);
254
 
      }
255
 
      else
256
 
      {
257
 
        String d;
258
 
        String *default_value= field_arg->def->val_str(&d);
259
 
 
260
 
        assert(default_value);
261
 
 
262
 
        if ((field_arg->sql_type==DRIZZLE_TYPE_VARCHAR
263
 
           || field_arg->sql_type==DRIZZLE_TYPE_BLOB)
264
 
           && ((field_arg->length / field_arg->charset->mbmaxlen)
265
 
           < default_value->length()))
266
 
        {
267
 
          my_error(ER_INVALID_DEFAULT, MYF(0), field_arg->field_name);
268
 
          return 1;
269
 
        }
270
 
 
271
 
        if (field_arg->sql_type == DRIZZLE_TYPE_DATE
272
 
            || field_arg->sql_type == DRIZZLE_TYPE_DATETIME
273
 
            || field_arg->sql_type == DRIZZLE_TYPE_TIMESTAMP)
274
 
        {
275
 
          DRIZZLE_TIME ltime;
276
 
 
277
 
          if (field_arg->def->get_date(&ltime, TIME_FUZZY_DATE))
278
 
          {
279
 
            my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR),
280
 
                     default_value->c_str());
281
 
            return 1;
282
 
          }
283
 
 
284
 
          /* We now do the casting down to the appropriate type.
285
 
 
286
 
             Yes, this implicit casting is balls.
287
 
             It was previously done on reading the proto back in,
288
 
             but we really shouldn't store the bogus things in the proto,
289
 
             and instead do the casting behaviour here.
290
 
 
291
 
             the timestamp errors are taken care of elsewhere.
292
 
          */
293
 
 
294
 
          if (field_arg->sql_type == DRIZZLE_TYPE_DATETIME)
295
 
          {
296
 
            Item *typecast= new Item_datetime_typecast(field_arg->def);
297
 
            typecast->quick_fix_field();
298
 
            typecast->val_str(default_value);
299
 
          }
300
 
          else if (field_arg->sql_type == DRIZZLE_TYPE_DATE)
301
 
          {
302
 
            Item *typecast= new Item_date_typecast(field_arg->def);
303
 
            typecast->quick_fix_field();
304
 
            typecast->val_str(default_value);
305
 
          }
306
 
        }
307
 
 
308
 
        if ((field_arg->sql_type==DRIZZLE_TYPE_VARCHAR
309
 
            && field_arg->charset==&my_charset_bin)
310
 
           || (field_arg->sql_type==DRIZZLE_TYPE_BLOB
311
 
            && field_arg->charset==&my_charset_bin))
312
 
        {
313
 
          string bin_default;
314
 
          bin_default.assign(default_value->c_ptr(),
315
 
                             default_value->length());
316
 
          field_options->set_default_bin_value(bin_default);
317
 
        }
318
 
        else
319
 
        {
320
 
          field_options->set_default_value(default_value->c_ptr());
321
 
        }
322
 
      }
323
 
    }
324
 
 
325
 
    assert(field_arg->unireg_check == Field::NONE
326
 
           || field_arg->unireg_check == Field::NEXT_NUMBER
327
 
           || field_arg->unireg_check == Field::TIMESTAMP_DN_FIELD
328
 
           || field_arg->unireg_check == Field::TIMESTAMP_UN_FIELD
329
 
           || field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD);
330
 
 
331
 
  }
332
 
 
333
 
  assert(! use_existing_fields || (field_number == table_proto.field_size()));
334
 
 
335
 
  if (create_info->table_options & HA_OPTION_PACK_RECORD)
336
 
    table_options->set_pack_record(true);
337
 
 
338
 
  if (table_options->has_comment() && table_options->comment().length() == 0)
339
 
    table_options->clear_comment();
340
 
 
341
 
  if (table_options->has_comment())
342
 
  {
343
 
    uint32_t tmp_len;
344
 
    tmp_len= system_charset_info->cset->charpos(system_charset_info,
345
 
                                                table_options->comment().c_str(),
346
 
                                                table_options->comment().c_str() +
347
 
                                                table_options->comment().length(),
348
 
                                                TABLE_COMMENT_MAXLEN);
349
 
 
350
 
    if (tmp_len < table_options->comment().length())
351
 
    {
352
 
      my_error(ER_WRONG_STRING_LENGTH, MYF(0),
353
 
               table_options->comment().c_str(),"Table COMMENT",
354
 
               (uint32_t) TABLE_COMMENT_MAXLEN);
355
 
      return(1);
356
 
    }
357
 
  }
358
 
 
359
 
  if (create_info->default_table_charset)
360
 
  {
361
 
    table_options->set_collation_id(
362
 
                               create_info->default_table_charset->number);
363
 
    table_options->set_collation(create_info->default_table_charset->name);
364
 
  }
365
 
 
366
 
  if (create_info->used_fields & HA_CREATE_USED_AUTO)
367
 
    table_options->set_has_user_set_auto_increment_value(true);
368
 
  else
369
 
    table_options->set_has_user_set_auto_increment_value(false);
370
 
 
371
 
  if (create_info->auto_increment_value)
372
 
    table_options->set_auto_increment_value(create_info->auto_increment_value);
373
 
 
374
 
  for (uint32_t i= 0; i < keys; i++)
375
 
  {
376
 
    message::Table::Index *idx;
377
 
 
378
 
    idx= table_proto.add_indexes();
379
 
 
380
 
    assert(test(key_info[i].flags & HA_USES_COMMENT) ==
381
 
           (key_info[i].comment.length > 0));
382
 
 
383
 
    idx->set_name(key_info[i].name);
384
 
 
385
 
    idx->set_key_length(key_info[i].key_length);
386
 
 
387
 
    if (is_primary_key_name(key_info[i].name))
388
 
      idx->set_is_primary(true);
389
 
    else
390
 
      idx->set_is_primary(false);
391
 
 
392
 
    switch(key_info[i].algorithm)
393
 
    {
394
 
    case HA_KEY_ALG_HASH:
395
 
      idx->set_type(message::Table::Index::HASH);
396
 
      break;
397
 
 
398
 
    case HA_KEY_ALG_BTREE:
399
 
      idx->set_type(message::Table::Index::BTREE);
400
 
      break;
401
 
 
402
 
    case HA_KEY_ALG_UNDEF:
403
 
      idx->set_type(message::Table::Index::UNKNOWN_INDEX);
404
 
      break;
405
 
 
406
 
    default:
407
 
      abort(); /* Somebody's brain broke. haven't added index type to proto */
408
 
    }
409
 
 
410
 
    if (key_info[i].flags & HA_NOSAME)
411
 
      idx->set_is_unique(true);
412
 
    else
413
 
      idx->set_is_unique(false);
414
 
 
415
 
    message::Table::Index::Options *index_options= idx->mutable_options();
416
 
 
417
 
    if (key_info[i].flags & HA_USES_BLOCK_SIZE)
418
 
      index_options->set_key_block_size(key_info[i].block_size);
419
 
 
420
 
    if (key_info[i].flags & HA_PACK_KEY)
421
 
      index_options->set_pack_key(true);
422
 
 
423
 
    if (key_info[i].flags & HA_BINARY_PACK_KEY)
424
 
      index_options->set_binary_pack_key(true);
425
 
 
426
 
    if (key_info[i].flags & HA_VAR_LENGTH_PART)
427
 
      index_options->set_var_length_key(true);
428
 
 
429
 
    if (key_info[i].flags & HA_NULL_PART_KEY)
430
 
      index_options->set_null_part_key(true);
431
 
 
432
 
    if (key_info[i].flags & HA_KEY_HAS_PART_KEY_SEG)
433
 
      index_options->set_has_partial_segments(true);
434
 
 
435
 
    if (key_info[i].flags & HA_GENERATED_KEY)
436
 
      index_options->set_auto_generated_key(true);
437
 
 
438
 
    if (key_info[i].flags & HA_USES_COMMENT)
439
 
    {
440
 
      uint32_t tmp_len;
441
 
      tmp_len= system_charset_info->cset->charpos(system_charset_info,
442
 
                                                  key_info[i].comment.str,
443
 
                                                  key_info[i].comment.str +
444
 
                                                  key_info[i].comment.length,
445
 
                                                  TABLE_COMMENT_MAXLEN);
446
 
 
447
 
      if (tmp_len < key_info[i].comment.length)
448
 
      {
449
 
        my_error(ER_WRONG_STRING_LENGTH, MYF(0),
450
 
                 key_info[i].comment.str,"Index COMMENT",
451
 
                 (uint32_t) TABLE_COMMENT_MAXLEN);
452
 
        return(1);
453
 
      }
454
 
 
455
 
      idx->set_comment(key_info[i].comment.str);
456
 
    }
457
 
    static const uint64_t unknown_index_flag= (HA_NOSAME | HA_PACK_KEY |
458
 
                                               HA_USES_BLOCK_SIZE | 
459
 
                                               HA_BINARY_PACK_KEY |
460
 
                                               HA_VAR_LENGTH_PART |
461
 
                                               HA_NULL_PART_KEY | 
462
 
                                               HA_KEY_HAS_PART_KEY_SEG |
463
 
                                               HA_GENERATED_KEY |
464
 
                                               HA_USES_COMMENT);
465
 
    if (key_info[i].flags & ~unknown_index_flag)
466
 
      abort(); // Invalid (unknown) index flag.
467
 
 
468
 
    for(unsigned int j=0; j< key_info[i].key_parts; j++)
469
 
    {
470
 
      message::Table::Index::IndexPart *idxpart;
471
 
      const int fieldnr= key_info[i].key_part[j].fieldnr;
472
 
      int mbmaxlen= 1;
473
 
 
474
 
      idxpart= idx->add_index_part();
475
 
 
476
 
      idxpart->set_fieldnr(fieldnr);
477
 
 
478
 
      if (table_proto.field(fieldnr).type() == message::Table::Field::VARCHAR
479
 
          || table_proto.field(fieldnr).type() == message::Table::Field::BLOB)
480
 
      {
481
 
        uint32_t collation_id;
482
 
 
483
 
        if (table_proto.field(fieldnr).string_options().has_collation_id())
484
 
          collation_id= table_proto.field(fieldnr).string_options().collation_id();
485
 
        else
486
 
          collation_id= table_proto.options().collation_id();
487
 
 
488
 
        const CHARSET_INFO *cs= get_charset(collation_id);
489
 
 
490
 
        mbmaxlen= cs->mbmaxlen;
491
 
      }
492
 
 
493
 
      idxpart->set_compare_length(key_info[i].key_part[j].length / mbmaxlen);
494
 
    }
495
 
  }
496
 
 
497
 
  if (not table_proto.IsInitialized())
498
 
  {
499
 
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), table_proto.InitializationErrorString().c_str());
500
 
    return 1;
501
 
  }
502
 
 
503
 
  /*
504
 
    Here we test to see if we can validate the Table Message before we continue. 
505
 
    We do this by serializing the protobuffer.
506
 
  */
507
 
  {
508
 
    string tmp_string;
509
 
 
510
 
    try {
511
 
      table_proto.SerializeToString(&tmp_string);
512
 
    }
513
 
 
514
 
    catch (...)
515
 
    {
516
 
      my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
517
 
               table_proto.InitializationErrorString().empty() ? "": table_proto.InitializationErrorString().c_str());
518
 
 
519
 
      return 1;
520
 
    }
521
 
  }
522
 
 
523
 
  return 0;
524
 
}
 
211
  }
 
212
 
 
213
  if ((file=create_frm(session, file_name, db, table, reclength, fileinfo,
 
214
                       create_info, keys, key_info)) < 0)
 
215
  {
 
216
    free(screen_buff);
 
217
    return(1);
 
218
  }
 
219
 
 
220
  key_buff_length= uint4korr(fileinfo+47);
 
221
  keybuff=(unsigned char*) my_malloc(key_buff_length, MYF(0));
 
222
  key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
 
223
  get_form_pos(file,fileinfo,&formnames);
 
224
  if (!(filepos=make_new_entry(file,fileinfo,&formnames,"")))
 
225
    goto err;
 
226
  maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
 
227
  int2store(forminfo+2,maxlength);
 
228
  int4store(fileinfo+10,(ulong) (filepos+maxlength));
 
229
  fileinfo[26]= (unsigned char) test((create_info->max_rows == 1) &&
 
230
                             (create_info->min_rows == 1) && (keys == 0));
 
231
  int2store(fileinfo+28,key_info_length);
 
232
 
 
233
 
 
234
  int2store(fileinfo+59,db_file->extra_rec_buf_length());
 
235
 
 
236
  if (pwrite(file, fileinfo, 64, 0L) == 0 ||
 
237
      pwrite(file, keybuff, key_info_length, (ulong) uint2korr(fileinfo+6)) == 0)
 
238
    goto err;
 
239
  my_seek(file,
 
240
               (ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
 
241
               MY_SEEK_SET,MYF(0));
 
242
  if (make_empty_rec(session,file,ha_legacy_type(create_info->db_type),
 
243
                     create_info->table_options,
 
244
                     create_fields,reclength, data_offset, db_file))
 
245
    goto err;
 
246
 
 
247
  int2store(buff, create_info->connect_string.length);
 
248
  if (my_write(file, (const unsigned char*)buff, 2, MYF(MY_NABP)) ||
 
249
      my_write(file, (const unsigned char*)create_info->connect_string.str,
 
250
               create_info->connect_string.length, MYF(MY_NABP)))
 
251
      goto err;
 
252
 
 
253
  int2store(buff, str_db_type.length);
 
254
  if (my_write(file, (const unsigned char*)buff, 2, MYF(MY_NABP)) ||
 
255
      my_write(file, (const unsigned char*)str_db_type.str,
 
256
               str_db_type.length, MYF(MY_NABP)))
 
257
    goto err;
 
258
 
 
259
  {
 
260
    memset(buff, 0, 6);
 
261
    if (my_write(file, (unsigned char*) buff, 6, MYF_RW))
 
262
      goto err;
 
263
  }
 
264
 
 
265
  if (forminfo[46] == (unsigned char)255)
 
266
  {
 
267
    unsigned char comment_length_buff[2];
 
268
    int2store(comment_length_buff,create_info->comment.length);
 
269
    if (my_write(file, comment_length_buff, 2, MYF(MY_NABP)) ||
 
270
        my_write(file, (unsigned char*)create_info->comment.str,
 
271
                  create_info->comment.length, MYF(MY_NABP)))
 
272
      goto err;
 
273
  }
 
274
 
 
275
  /* Store storage type and field format array of fields */
 
276
  {
 
277
    /* prepare header */
 
278
    {
 
279
      uint32_t flags= 0;
 
280
 
 
281
      memset(buff, 0, format_section_header_size);
 
282
      /* length of section 2 bytes*/
 
283
      int2store(buff+0, format_section_len);
 
284
      /* flags of section 4 bytes*/
 
285
      int4store(buff+2, flags);
 
286
      /* 2 bytes left for future use */
 
287
    }
 
288
    /* write header */
 
289
    if (my_write(file, (const unsigned char*)buff, format_section_header_size, MYF_RW))
 
290
      goto err;
 
291
    buff[0]= 0;
 
292
    if (my_write(file, (const unsigned char*)buff, 1, MYF_RW))
 
293
      goto err;
 
294
    /* write column info, 1 byte per column */
 
295
    {
 
296
      List_iterator<Create_field> it(create_fields);
 
297
      Create_field *field;
 
298
      unsigned char column_format, write_byte;
 
299
      while ((field=it++))
 
300
      {
 
301
        column_format= (unsigned char)field->column_format();
 
302
        write_byte= (column_format << COLUMN_FORMAT_SHIFT);
 
303
        if (my_write(file, &write_byte, 1, MYF_RW))
 
304
          goto err;
 
305
      }
 
306
    }
 
307
  }
 
308
  my_seek(file,filepos,MY_SEEK_SET,MYF(0));
 
309
  if (my_write(file, forminfo, 288, MYF_RW) ||
 
310
      my_write(file, screen_buff, info_length, MYF_RW) ||
 
311
      pack_fields(file, create_fields, data_offset))
 
312
    goto err;
 
313
 
 
314
  free(screen_buff);
 
315
  free(keybuff);
 
316
 
 
317
  if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
 
318
      (my_sync(file, MYF(MY_WME)) ||
 
319
       my_sync_dir_by_file(file_name, MYF(MY_WME))))
 
320
      goto err2;
 
321
 
 
322
  if (my_close(file,MYF(MY_WME)))
 
323
    goto err3;
 
324
 
 
325
  {
 
326
    /* 
 
327
      Restore all UCS2 intervals.
 
328
      HEX representation of them is not needed anymore.
 
329
    */
 
330
    List_iterator<Create_field> it(create_fields);
 
331
    Create_field *field;
 
332
    while ((field=it++))
 
333
    {
 
334
      if (field->save_interval)
 
335
      {
 
336
        field->interval= field->save_interval;
 
337
        field->save_interval= 0;
 
338
      }
 
339
    }
 
340
  }
 
341
  return(0);
 
342
 
 
343
err:
 
344
  free(screen_buff);
 
345
  free(keybuff);
 
346
err2:
 
347
  my_close(file,MYF(MY_WME));
 
348
err3:
 
349
  my_delete(file_name,MYF(0));
 
350
  return(1);
 
351
} /* mysql_create_frm */
 
352
 
525
353
 
526
354
/*
527
 
  Create a table definition proto file and the tables
 
355
  Create a frm (table definition) file and the tables
528
356
 
529
357
  SYNOPSIS
530
358
    rea_create_table()
536
364
    create_fields       Fields to create
537
365
    keys                number of keys to create
538
366
    key_info            Keys to create
 
367
    file                Handler to use
539
368
 
540
369
  RETURN
541
370
    0  ok
542
371
    1  error
543
372
*/
544
373
 
545
 
bool rea_create_table(Session *session,
546
 
                      const TableIdentifier &identifier,
547
 
                      message::Table &table_proto,
548
 
                      HA_CREATE_INFO *create_info,
549
 
                      List<CreateField> &create_fields,
550
 
                      uint32_t keys, KeyInfo *key_info)
 
374
int rea_create_table(Session *session, const char *path,
 
375
                     const char *db, const char *table_name,
 
376
                     HA_CREATE_INFO *create_info,
 
377
                     List<Create_field> &create_fields,
 
378
                     uint32_t keys, KEY *key_info, handler *file)
551
379
{
552
 
  assert(table_proto.has_name());
553
 
  if (fill_table_proto(table_proto, create_fields, create_info,
554
 
                       keys, key_info))
555
 
    return false;
556
 
 
557
 
  assert(table_proto.name() == identifier.getTableName());
558
 
 
559
 
  if (plugin::StorageEngine::createTable(*session,
560
 
                                         identifier,
561
 
                                         table_proto))
562
 
  {
563
 
    return false;
564
 
  }
565
 
 
566
 
  return true;
567
 
 
 
380
  
 
381
 
 
382
  char frm_name[FN_REFLEN];
 
383
  strxmov(frm_name, path, reg_ext, NULL);
 
384
  if (mysql_create_frm(session, frm_name, db, table_name, create_info,
 
385
                       create_fields, keys, key_info, file))
 
386
 
 
387
    return(1);
 
388
 
 
389
  // Make sure mysql_create_frm din't remove extension
 
390
  assert(*fn_rext(frm_name));
 
391
  if (session->variables.keep_files_on_create)
 
392
    create_info->options|= HA_CREATE_KEEP_FILES;
 
393
  if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info))
 
394
    goto err_handler;
 
395
  if (!create_info->frm_only && ha_create_table(session, path, db, table_name,
 
396
                                                create_info,0))
 
397
    goto err_handler;
 
398
  return(0);
 
399
 
 
400
err_handler:
 
401
  file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
 
402
  my_delete(frm_name, MYF(0));
 
403
  return(1);
568
404
} /* rea_create_table */
569
405
 
570
 
} /* namespace drizzled */
571
 
 
 
406
 
 
407
        /* Pack screens to a screen for save in a form-file */
 
408
 
 
409
static unsigned char *pack_screens(List<Create_field> &create_fields,
 
410
                           uint32_t *info_length, uint32_t *screens,
 
411
                           bool small_file)
 
412
{
 
413
  register uint32_t i;
 
414
  uint32_t row,start_row,end_row,fields_on_screen;
 
415
  uint32_t length,cols;
 
416
  unsigned char *info,*pos,*start_screen;
 
417
  uint32_t fields=create_fields.elements;
 
418
  List_iterator<Create_field> it(create_fields);
 
419
  
 
420
 
 
421
  start_row=4; end_row=22; cols=80; fields_on_screen=end_row+1-start_row;
 
422
 
 
423
  *screens=(fields-1)/fields_on_screen+1;
 
424
  length= (*screens) * (SC_INFO_LENGTH+ (cols>> 1)+4);
 
425
 
 
426
  Create_field *field;
 
427
  while ((field=it++))
 
428
    length+=(uint) strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
 
429
 
 
430
  if (!(info=(unsigned char*) my_malloc(length,MYF(MY_WME))))
 
431
    return(0);
 
432
 
 
433
  start_screen=0;
 
434
  row=end_row;
 
435
  pos=info;
 
436
  it.rewind();
 
437
  for (i=0 ; i < fields ; i++)
 
438
  {
 
439
    Create_field *cfield=it++;
 
440
    if (row++ == end_row)
 
441
    {
 
442
      if (i)
 
443
      {
 
444
        length=(uint) (pos-start_screen);
 
445
        int2store(start_screen,length);
 
446
        start_screen[2]=(unsigned char) (fields_on_screen+1);
 
447
        start_screen[3]=(unsigned char) (fields_on_screen);
 
448
      }
 
449
      row=start_row;
 
450
      start_screen=pos;
 
451
      pos+=4;
 
452
      pos[0]= (unsigned char) start_row-2;      /* Header string */
 
453
      pos[1]= (unsigned char) (cols >> 2);
 
454
      pos[2]= (unsigned char) (cols >> 1) +1;
 
455
      strfill((char *) pos+3,(uint) (cols >> 1),' ');
 
456
      pos+=(cols >> 1)+4;
 
457
    }
 
458
    length=(uint) strlen(cfield->field_name);
 
459
    if (length > cols-3)
 
460
      length=cols-3;
 
461
 
 
462
    if (!small_file)
 
463
    {
 
464
      pos[0]=(unsigned char) row;
 
465
      pos[1]=0;
 
466
      pos[2]=(unsigned char) (length+1);
 
467
      pos=(unsigned char*) strmake((char*) pos+3,cfield->field_name,length)+1;
 
468
    }
 
469
    cfield->row=(uint8_t) row;
 
470
    cfield->col=(uint8_t) (length+1);
 
471
    cfield->sc_length=(uint8_t) cmin(cfield->length,(uint32_t)cols-(length+2));
 
472
  }
 
473
  length=(uint) (pos-start_screen);
 
474
  int2store(start_screen,length);
 
475
  start_screen[2]=(unsigned char) (row-start_row+2);
 
476
  start_screen[3]=(unsigned char) (row-start_row+1);
 
477
 
 
478
  *info_length=(uint) (pos-info);
 
479
  return(info);
 
480
} /* pack_screens */
 
481
 
 
482
 
 
483
        /* Pack keyinfo and keynames to keybuff for save in form-file. */
 
484
 
 
485
static uint32_t pack_keys(unsigned char *keybuff, uint32_t key_count, KEY *keyinfo,
 
486
                      ulong data_offset)
 
487
{
 
488
  uint32_t key_parts,length;
 
489
  unsigned char *pos, *keyname_pos;
 
490
  KEY *key,*end;
 
491
  KEY_PART_INFO *key_part,*key_part_end;
 
492
  
 
493
 
 
494
  pos=keybuff+6;
 
495
  key_parts=0;
 
496
  for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
 
497
  {
 
498
    int2store(pos, (key->flags ^ HA_NOSAME));
 
499
    int2store(pos+2,key->key_length);
 
500
    pos[4]= (unsigned char) key->key_parts;
 
501
    pos[5]= (unsigned char) key->algorithm;
 
502
    int2store(pos+6, key->block_size);
 
503
    pos+=8;
 
504
    key_parts+=key->key_parts;
 
505
    for (key_part=key->key_part,key_part_end=key_part+key->key_parts ;
 
506
         key_part != key_part_end ;
 
507
         key_part++)
 
508
 
 
509
    {
 
510
      uint32_t offset;
 
511
      int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED);
 
512
      offset= (uint) (key_part->offset+data_offset+1);
 
513
      int2store(pos+2, offset);
 
514
      pos[4]=0;                                 // Sort order
 
515
      int2store(pos+5,key_part->key_type);
 
516
      int2store(pos+7,key_part->length);
 
517
      pos+=9;
 
518
    }
 
519
  }
 
520
        /* Save keynames */
 
521
  keyname_pos=pos;
 
522
  *pos++=(unsigned char) NAMES_SEP_CHAR;
 
523
  for (key=keyinfo ; key != end ; key++)
 
524
  {
 
525
    unsigned char *tmp=(unsigned char*) my_stpcpy((char*) pos,key->name);
 
526
    *tmp++= (unsigned char) NAMES_SEP_CHAR;
 
527
    *tmp=0;
 
528
    pos=tmp;
 
529
  }
 
530
  *(pos++)=0;
 
531
 
 
532
  for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
 
533
  {
 
534
    if (key->flags & HA_USES_COMMENT)
 
535
    {
 
536
      int2store(pos, key->comment.length);
 
537
      unsigned char *tmp= (unsigned char*)my_stpncpy((char*) pos+2,key->comment.str,key->comment.length);
 
538
      pos= tmp;
 
539
    }
 
540
  }
 
541
 
 
542
  if (key_count > 127 || key_parts > 127)
 
543
  {
 
544
    keybuff[0]= (key_count & 0x7f) | 0x80;
 
545
    keybuff[1]= key_count >> 7;
 
546
    int2store(keybuff+2,key_parts);
 
547
  }
 
548
  else
 
549
  {
 
550
    keybuff[0]=(unsigned char) key_count;
 
551
    keybuff[1]=(unsigned char) key_parts;
 
552
    keybuff[2]= keybuff[3]= 0;
 
553
  }
 
554
  length=(uint) (pos-keyname_pos);
 
555
  int2store(keybuff+4,length);
 
556
  return((uint) (pos-keybuff));
 
557
} /* pack_keys */
 
558
 
 
559
 
 
560
/* Make formheader */
 
561
 
 
562
static bool pack_header(unsigned char *forminfo,
 
563
                        List<Create_field> &create_fields,
 
564
                        uint32_t info_length, uint32_t screens, uint32_t table_options,
 
565
                        ulong data_offset, handler *file)
 
566
{
 
567
  uint32_t length,int_count,int_length,no_empty, int_parts;
 
568
  uint32_t time_stamp_pos,null_fields;
 
569
  ulong reclength, totlength, n_length, com_length, vcol_info_length;
 
570
 
 
571
 
 
572
  if (create_fields.elements > MAX_FIELDS)
 
573
  {
 
574
    my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
 
575
    return(1);
 
576
  }
 
577
 
 
578
  totlength= 0L;
 
579
  reclength= data_offset;
 
580
  no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=
 
581
    com_length=vcol_info_length=0;
 
582
  n_length=2L;
 
583
 
 
584
        /* Check fields */
 
585
 
 
586
  List_iterator<Create_field> it(create_fields);
 
587
  Create_field *field;
 
588
  while ((field=it++))
 
589
  {
 
590
    uint32_t tmp_len= system_charset_info->cset->charpos(system_charset_info,
 
591
                                                     field->comment.str,
 
592
                                                     field->comment.str +
 
593
                                                     field->comment.length,
 
594
                                                     COLUMN_COMMENT_MAXLEN);
 
595
 
 
596
    if (tmp_len < field->comment.length)
 
597
    {
 
598
      my_error(ER_WRONG_STRING_LENGTH, MYF(0),
 
599
               field->comment.str,"COLUMN COMMENT",
 
600
               (uint) COLUMN_COMMENT_MAXLEN);
 
601
      return(1);
 
602
    }
 
603
    if (field->vcol_info)
 
604
    {
 
605
      tmp_len= system_charset_info->cset->charpos(system_charset_info,
 
606
                                                  field->vcol_info->expr_str.str,
 
607
                                                  field->vcol_info->expr_str.str +
 
608
                                                  field->vcol_info->expr_str.length,
 
609
                                                  VIRTUAL_COLUMN_EXPRESSION_MAXLEN);
 
610
 
 
611
      if (tmp_len < field->vcol_info->expr_str.length)
 
612
      {
 
613
        my_error(ER_WRONG_STRING_LENGTH, MYF(0),
 
614
                 field->vcol_info->expr_str.str,"VIRTUAL COLUMN EXPRESSION",
 
615
                 (uint) VIRTUAL_COLUMN_EXPRESSION_MAXLEN);
 
616
        return(1);
 
617
      }
 
618
      /*
 
619
        Sum up the length of the expression string and mandatory header bytes
 
620
        to the total length.
 
621
      */
 
622
      vcol_info_length+= field->vcol_info->expr_str.length+(uint)FRM_VCOL_HEADER_SIZE;
 
623
    }
 
624
 
 
625
    totlength+= field->length;
 
626
    com_length+= field->comment.length;
 
627
    if (MTYP_TYPENR(field->unireg_check) == Field::NOEMPTY ||
 
628
        field->unireg_check & MTYP_NOEMPTY_BIT)
 
629
    {
 
630
      field->unireg_check= (Field::utype) ((uint) field->unireg_check |
 
631
                                           MTYP_NOEMPTY_BIT);
 
632
      no_empty++;
 
633
    }
 
634
    /* 
 
635
      We mark first TIMESTAMP field with NOW() in DEFAULT or ON UPDATE 
 
636
      as auto-update field.
 
637
    */
 
638
    if (field->sql_type == DRIZZLE_TYPE_TIMESTAMP &&
 
639
        MTYP_TYPENR(field->unireg_check) != Field::NONE &&
 
640
        !time_stamp_pos)
 
641
      time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1;
 
642
    length=field->pack_length;
 
643
    if ((uint) field->offset+ (uint) data_offset+ length > reclength)
 
644
      reclength=(uint) (field->offset+ data_offset + length);
 
645
    n_length+= (ulong) strlen(field->field_name)+1;
 
646
    field->interval_id=0;
 
647
    field->save_interval= 0;
 
648
    if (field->interval)
 
649
    {
 
650
      uint32_t old_int_count=int_count;
 
651
 
 
652
      if (field->charset->mbminlen > 1)
 
653
      {
 
654
        /* 
 
655
          Escape UCS2 intervals using HEX notation to avoid
 
656
          problems with delimiters between enum elements.
 
657
          As the original representation is still needed in 
 
658
          the function make_empty_rec to create a record of
 
659
          filled with default values it is saved in save_interval
 
660
          The HEX representation is created from this copy.
 
661
        */
 
662
        field->save_interval= field->interval;
 
663
        field->interval= (TYPELIB*) sql_alloc(sizeof(TYPELIB));
 
664
        *field->interval= *field->save_interval; 
 
665
        field->interval->type_names= 
 
666
          (const char **) sql_alloc(sizeof(char*) * 
 
667
                                    (field->interval->count+1));
 
668
        field->interval->type_names[field->interval->count]= 0;
 
669
        field->interval->type_lengths=
 
670
          (uint32_t *) sql_alloc(sizeof(uint) * field->interval->count);
 
671
 
 
672
        for (uint32_t pos= 0; pos < field->interval->count; pos++)
 
673
        {
 
674
          char *dst;
 
675
          const char *src= field->save_interval->type_names[pos];
 
676
          uint32_t hex_length;
 
677
          length= field->save_interval->type_lengths[pos];
 
678
          hex_length= length * 2;
 
679
          field->interval->type_lengths[pos]= hex_length;
 
680
          field->interval->type_names[pos]= dst= (char*) sql_alloc(hex_length +
 
681
                                                                   1);
 
682
          octet2hex(dst, src, length);
 
683
        }
 
684
      }
 
685
 
 
686
      field->interval_id=get_interval_id(&int_count,create_fields,field);
 
687
      if (old_int_count != int_count)
 
688
      {
 
689
        for (const char **pos=field->interval->type_names ; *pos ; pos++)
 
690
          int_length+=(uint) strlen(*pos)+1;    // field + suffix prefix
 
691
        int_parts+=field->interval->count+1;
 
692
      }
 
693
    }
 
694
    if (f_maybe_null(field->pack_flag))
 
695
      null_fields++;
 
696
  }
 
697
  int_length+=int_count*2;                      // 255 prefix + 0 suffix
 
698
 
 
699
        /* Save values in forminfo */
 
700
 
 
701
  if (reclength > (ulong) file->max_record_length())
 
702
  {
 
703
    my_error(ER_TOO_BIG_ROWSIZE, MYF(0), (uint) file->max_record_length());
 
704
    return(1);
 
705
  }
 
706
  /* Hack to avoid bugs with small static rows in MySQL */
 
707
  reclength=cmax((ulong)file->min_record_length(table_options),reclength);
 
708
  if (info_length+(ulong) create_fields.elements*FCOMP+288+
 
709
      n_length+int_length+com_length+vcol_info_length > 65535L || 
 
710
      int_count > 255)
 
711
  {
 
712
    my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
 
713
    return(1);
 
714
  }
 
715
 
 
716
  memset(forminfo, 0, 288);
 
717
  length=(info_length+create_fields.elements*FCOMP+288+n_length+int_length+
 
718
          com_length+vcol_info_length);
 
719
  int2store(forminfo,length);
 
720
  forminfo[256] = (uint8_t) screens;
 
721
  int2store(forminfo+258,create_fields.elements);
 
722
  int2store(forminfo+260,info_length);
 
723
  int2store(forminfo+262,totlength);
 
724
  int2store(forminfo+264,no_empty);
 
725
  int2store(forminfo+266,reclength);
 
726
  int2store(forminfo+268,n_length);
 
727
  int2store(forminfo+270,int_count);
 
728
  int2store(forminfo+272,int_parts);
 
729
  int2store(forminfo+274,int_length);
 
730
  int2store(forminfo+276,time_stamp_pos);
 
731
  int2store(forminfo+278,80);                   /* Columns needed */
 
732
  int2store(forminfo+280,22);                   /* Rows needed */
 
733
  int2store(forminfo+282,null_fields);
 
734
  int2store(forminfo+284,com_length);
 
735
  int2store(forminfo+286,vcol_info_length);
 
736
  /* forminfo+288 is free to use for additional information */
 
737
  return(0);
 
738
} /* pack_header */
 
739
 
 
740
 
 
741
        /* get each unique interval each own id */
 
742
 
 
743
static uint32_t get_interval_id(uint32_t *int_count,List<Create_field> &create_fields,
 
744
                            Create_field *last_field)
 
745
{
 
746
  List_iterator<Create_field> it(create_fields);
 
747
  Create_field *field;
 
748
  TYPELIB *interval=last_field->interval;
 
749
 
 
750
  while ((field=it++) != last_field)
 
751
  {
 
752
    if (field->interval_id && field->interval->count == interval->count)
 
753
    {
 
754
      const char **a,**b;
 
755
      for (a=field->interval->type_names, b=interval->type_names ;
 
756
           *a && !strcmp(*a,*b);
 
757
           a++,b++) ;
 
758
 
 
759
      if (! *a)
 
760
      {
 
761
        return field->interval_id;              // Re-use last interval
 
762
      }
 
763
    }
 
764
  }
 
765
  return ++*int_count;                          // New unique interval
 
766
}
 
767
 
 
768
 
 
769
        /* Save fields, fieldnames and intervals */
 
770
 
 
771
static bool pack_fields(File file, List<Create_field> &create_fields,
 
772
                        ulong data_offset)
 
773
{
 
774
  register uint32_t i;
 
775
  uint32_t int_count, comment_length=0, vcol_info_length=0;
 
776
  unsigned char buff[MAX_FIELD_WIDTH];
 
777
  Create_field *field;
 
778
  
 
779
 
 
780
        /* Write field info */
 
781
 
 
782
  List_iterator<Create_field> it(create_fields);
 
783
 
 
784
  int_count=0;
 
785
  while ((field=it++))
 
786
  {
 
787
    uint32_t recpos;
 
788
    uint32_t cur_vcol_expr_len= 0;
 
789
    buff[0]= (unsigned char) field->row;
 
790
    buff[1]= (unsigned char) field->col;
 
791
    buff[2]= (unsigned char) field->sc_length;
 
792
    int2store(buff+3, field->length);
 
793
    /* The +1 is here becasue the col offset in .frm file have offset 1 */
 
794
    recpos= field->offset+1 + (uint) data_offset;
 
795
    int3store(buff+5,recpos);
 
796
    int2store(buff+8,field->pack_flag);
 
797
    int2store(buff+10,field->unireg_check);
 
798
    buff[12]= (unsigned char) field->interval_id;
 
799
    buff[13]= (unsigned char) field->sql_type; 
 
800
    if (field->charset) 
 
801
      buff[14]= (unsigned char) field->charset->number;
 
802
    else
 
803
      buff[14]= 0;                              // Numerical
 
804
    if (field->vcol_info)
 
805
    {
 
806
      /* 
 
807
        Use the interval_id place in the .frm file to store the length of
 
808
        virtual field's data.
 
809
      */
 
810
      buff[12]= cur_vcol_expr_len= field->vcol_info->expr_str.length +
 
811
                (uint)FRM_VCOL_HEADER_SIZE;
 
812
      vcol_info_length+= cur_vcol_expr_len+(uint)FRM_VCOL_HEADER_SIZE;
 
813
      buff[13]= (unsigned char) DRIZZLE_TYPE_VIRTUAL;
 
814
    }
 
815
    int2store(buff+15, field->comment.length);
 
816
    comment_length+= field->comment.length;
 
817
    set_if_bigger(int_count,field->interval_id);
 
818
    if (my_write(file, buff, FCOMP, MYF_RW))
 
819
      return(1);
 
820
  }
 
821
 
 
822
        /* Write fieldnames */
 
823
  buff[0]=(unsigned char) NAMES_SEP_CHAR;
 
824
  if (my_write(file, buff, 1, MYF_RW))
 
825
    return(1);
 
826
  i=0;
 
827
  it.rewind();
 
828
  while ((field=it++))
 
829
  {
 
830
    char *pos= my_stpcpy((char*) buff,field->field_name);
 
831
    *pos++=NAMES_SEP_CHAR;
 
832
    if (i == create_fields.elements-1)
 
833
      *pos++=0;
 
834
    if (my_write(file, buff, (size_t) (pos-(char*) buff),MYF_RW))
 
835
      return(1);
 
836
    i++;
 
837
  }
 
838
 
 
839
        /* Write intervals */
 
840
  if (int_count)
 
841
  {
 
842
    String tmp((char*) buff,sizeof(buff), &my_charset_bin);
 
843
    tmp.length(0);
 
844
    it.rewind();
 
845
    int_count=0;
 
846
    while ((field=it++))
 
847
    {
 
848
      if (field->interval_id > int_count)
 
849
      {
 
850
        unsigned char  sep= 0;
 
851
        unsigned char  occ[256];
 
852
        uint32_t           i;
 
853
        unsigned char *val= NULL;
 
854
 
 
855
        memset(occ, 0, sizeof(occ));
 
856
 
 
857
        for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++)
 
858
          for (uint32_t j = 0; j < field->interval->type_lengths[i]; j++)
 
859
            occ[(unsigned int) (val[j])]= 1;
 
860
 
 
861
        if (!occ[(unsigned char)NAMES_SEP_CHAR])
 
862
          sep= (unsigned char) NAMES_SEP_CHAR;
 
863
        else if (!occ[(unsigned int)','])
 
864
          sep= ',';
 
865
        else
 
866
        {
 
867
          for (uint32_t i=1; i<256; i++)
 
868
          {
 
869
            if(!occ[i])
 
870
            {
 
871
              sep= i;
 
872
              break;
 
873
            }
 
874
          }
 
875
 
 
876
          if(!sep)    /* disaster, enum uses all characters, none left as separator */
 
877
          {
 
878
            my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
 
879
                       MYF(0));
 
880
            return(1);
 
881
          }
 
882
        }
 
883
 
 
884
        int_count= field->interval_id;
 
885
        tmp.append(sep);
 
886
        for (const char **pos=field->interval->type_names ; *pos ; pos++)
 
887
        {
 
888
          tmp.append(*pos);
 
889
          tmp.append(sep);
 
890
        }
 
891
        tmp.append('\0');                      // End of intervall
 
892
      }
 
893
    }
 
894
    if (my_write(file,(unsigned char*) tmp.ptr(),tmp.length(),MYF_RW))
 
895
      return(1);
 
896
  }
 
897
  if (comment_length)
 
898
  {
 
899
    it.rewind();
 
900
    int_count=0;
 
901
    while ((field=it++))
 
902
    {
 
903
      if (field->comment.length)
 
904
        if (my_write(file, (unsigned char*) field->comment.str, field->comment.length,
 
905
                     MYF_RW))
 
906
          return(1);
 
907
    }
 
908
  }
 
909
  if (vcol_info_length)
 
910
  {
 
911
    it.rewind();
 
912
    int_count=0;
 
913
    while ((field=it++))
 
914
    {
 
915
      /*
 
916
        Pack each virtual field as follows:
 
917
        byte 1      = 1 (always 1 to allow for future extensions)
 
918
        byte 2      = sql_type
 
919
        byte 3      = flags (as of now, 0 - no flags, 1 - field is physically stored)
 
920
        byte 4-...  = virtual column expression (text data)
 
921
      */
 
922
      if (field->vcol_info && field->vcol_info->expr_str.length)
 
923
      {
 
924
        buff[0]= (unsigned char)1;
 
925
        buff[1]= (unsigned char) field->sql_type;
 
926
        buff[2]= (unsigned char) field->is_stored;
 
927
        if (my_write(file, buff, 3, MYF_RW))
 
928
          return(1);
 
929
        if (my_write(file, 
 
930
                     (unsigned char*) field->vcol_info->expr_str.str, 
 
931
                     field->vcol_info->expr_str.length,
 
932
                     MYF_RW))
 
933
          return(1);
 
934
      }
 
935
    }
 
936
  }
 
937
  return(0);
 
938
}
 
939
 
 
940
 
 
941
/* save an empty record on start of formfile */
 
942
 
 
943
static bool make_empty_rec(Session *session, File file,
 
944
                           enum legacy_db_type table_type __attribute__((unused)),
 
945
                           uint32_t table_options,
 
946
                           List<Create_field> &create_fields,
 
947
                           uint32_t reclength,
 
948
                           ulong data_offset,
 
949
                           handler *handler)
 
950
{
 
951
  int error= 0;
 
952
  Field::utype type;
 
953
  uint32_t null_count;
 
954
  unsigned char *buff,*null_pos;
 
955
  Table table;
 
956
  TABLE_SHARE share;
 
957
  Create_field *field;
 
958
  enum_check_fields old_count_cuted_fields= session->count_cuted_fields;
 
959
  
 
960
 
 
961
  /* We need a table to generate columns for default values */
 
962
  memset(&table, 0, sizeof(table));
 
963
  memset(&share, 0, sizeof(share));
 
964
  table.s= &share;
 
965
 
 
966
  if (!(buff=(unsigned char*) my_malloc((size_t) reclength,MYF(MY_WME | MY_ZEROFILL))))
 
967
  {
 
968
    return(1);
 
969
  }
 
970
 
 
971
  table.in_use= session;
 
972
  table.s->db_low_byte_first= handler->low_byte_first();
 
973
  table.s->blob_ptr_size= portable_sizeof_char_ptr;
 
974
 
 
975
  null_count=0;
 
976
  if (!(table_options & HA_OPTION_PACK_RECORD))
 
977
  {
 
978
    null_count++;                       // Need one bit for delete mark
 
979
    *buff|= 1;
 
980
  }
 
981
  null_pos= buff;
 
982
 
 
983
  List_iterator<Create_field> it(create_fields);
 
984
  session->count_cuted_fields= CHECK_FIELD_WARN;    // To find wrong default values
 
985
  while ((field=it++))
 
986
  {
 
987
    /*
 
988
      regfield don't have to be deleted as it's allocated with sql_alloc()
 
989
    */
 
990
    Field *regfield= make_field(&share,
 
991
                                buff+field->offset + data_offset,
 
992
                                field->length,
 
993
                                null_pos + null_count / 8,
 
994
                                null_count & 7,
 
995
                                field->pack_flag,
 
996
                                field->sql_type,
 
997
                                field->charset,
 
998
                                field->unireg_check,
 
999
                                field->save_interval ? field->save_interval :
 
1000
                                field->interval, 
 
1001
                                field->field_name);
 
1002
    if (!regfield)
 
1003
    {
 
1004
      error= 1;
 
1005
      goto err;                                 // End of memory
 
1006
    }
 
1007
 
 
1008
    /* save_in_field() will access regfield->table->in_use */
 
1009
    regfield->init(&table);
 
1010
 
 
1011
    if (!(field->flags & NOT_NULL_FLAG))
 
1012
    {
 
1013
      *regfield->null_ptr|= regfield->null_bit;
 
1014
      null_count++;
 
1015
    }
 
1016
 
 
1017
    type= (Field::utype) MTYP_TYPENR(field->unireg_check);
 
1018
 
 
1019
    if (field->def)
 
1020
    {
 
1021
      int res= field->def->save_in_field(regfield, 1);
 
1022
      /* If not ok or warning of level 'note' */
 
1023
      if (res != 0 && res != 3)
 
1024
      {
 
1025
        my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
 
1026
        error= 1;
 
1027
        delete regfield; //To avoid memory leak
 
1028
        goto err;
 
1029
      }
 
1030
    }
 
1031
    else if (regfield->real_type() == DRIZZLE_TYPE_ENUM &&
 
1032
             (field->flags & NOT_NULL_FLAG))
 
1033
    {
 
1034
      regfield->set_notnull();
 
1035
      regfield->store((int64_t) 1, true);
 
1036
    }
 
1037
    else if (type == Field::YES)                // Old unireg type
 
1038
      regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES)),system_charset_info);
 
1039
    else if (type == Field::NO)                 // Old unireg type
 
1040
      regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),system_charset_info);
 
1041
    else
 
1042
      regfield->reset();
 
1043
  }
 
1044
  assert(data_offset == ((null_count + 7) / 8));
 
1045
 
 
1046
  /*
 
1047
    We need to set the unused bits to 1. If the number of bits is a multiple
 
1048
    of 8 there are no unused bits.
 
1049
  */
 
1050
  if (null_count & 7)
 
1051
    *(null_pos + null_count / 8)|= ~(((unsigned char) 1 << (null_count & 7)) - 1);
 
1052
 
 
1053
  error= my_write(file, buff, (size_t) reclength,MYF_RW) != 0;
 
1054
 
 
1055
err:
 
1056
  free(buff);
 
1057
  session->count_cuted_fields= old_count_cuted_fields;
 
1058
  return(error);
 
1059
} /* make_empty_rec */