~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/unireg.cc

  • Committer: Brian Aker
  • Date: 2008-07-01 20:33:58 UTC
  • Revision ID: brian@tangent.org-20080701203358-w8b3umnj1609zeyz
Dead files (ssltest removed from vio).

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   along with this program; if not, write to the Free Software
14
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
 
#include <drizzled/server_includes.h>
17
 
#include <drizzled/error.h>
18
 
#include <drizzled/session.h>
19
 
#include <drizzled/unireg.h>
20
 
 
21
 
/* For proto */
22
 
#include <string>
23
 
#include <fstream>
24
 
#include <drizzled/message/schema.pb.h>
25
 
#include <drizzled/message/table.pb.h>
26
 
#include <google/protobuf/io/zero_copy_stream.h>
27
 
#include <google/protobuf/io/zero_copy_stream_impl.h>
28
 
using namespace std;
29
 
 
30
 
int drizzle_read_table_proto(const char* path, drizzled::message::Table* table)
31
 
{
32
 
  int fd= open(path, O_RDONLY);
33
 
 
34
 
  if(fd==-1)
35
 
    return errno;
36
 
 
37
 
  google::protobuf::io::ZeroCopyInputStream* input=
38
 
    new google::protobuf::io::FileInputStream(fd);
39
 
 
40
 
  if (!table->ParseFromZeroCopyStream(input))
41
 
  {
42
 
    delete input;
43
 
    close(fd);
44
 
    return -1;
45
 
  }
46
 
 
47
 
  delete input;
48
 
  close(fd);
49
 
  return 0;
 
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 "mysql_priv.h"
 
27
#include <m_ctype.h>
 
28
#include <assert.h>
 
29
 
 
30
#define FCOMP                   17              /* Bytes for a packed field */
 
31
 
 
32
static uchar * pack_screens(List<Create_field> &create_fields,
 
33
                            uint *info_length, uint *screens, bool small_file);
 
34
static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info,
 
35
                      ulong data_offset);
 
36
static bool pack_header(uchar *forminfo,enum legacy_db_type table_type,
 
37
                        List<Create_field> &create_fields,
 
38
                        uint info_length, uint screens, uint table_options,
 
39
                        ulong data_offset, handler *file);
 
40
static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
 
41
                            Create_field *last_field);
 
42
static bool pack_fields(File file, List<Create_field> &create_fields,
 
43
                        ulong data_offset);
 
44
static bool make_empty_rec(THD *thd, int file, enum legacy_db_type table_type,
 
45
                           uint table_options,
 
46
                           List<Create_field> &create_fields,
 
47
                           uint reclength, ulong data_offset,
 
48
                           handler *handler);
 
49
 
 
50
/**
 
51
  An interceptor to hijack ER_TOO_MANY_FIELDS error from
 
52
  pack_screens and retry again without UNIREG screens.
 
53
 
 
54
  XXX: what is a UNIREG  screen?
 
55
*/
 
56
 
 
57
struct Pack_header_error_handler: public Internal_error_handler
 
58
{
 
59
  virtual bool handle_error(uint sql_errno,
 
60
                            const char *message,
 
61
                            MYSQL_ERROR::enum_warning_level level,
 
62
                            THD *thd);
 
63
  bool is_handled;
 
64
  Pack_header_error_handler() :is_handled(FALSE) {}
 
65
};
 
66
 
 
67
 
 
68
bool
 
69
Pack_header_error_handler::
 
70
handle_error(uint sql_errno,
 
71
             const char * /* message */,
 
72
             MYSQL_ERROR::enum_warning_level /* level */,
 
73
             THD * /* thd */)
 
74
{
 
75
  is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
 
76
  return is_handled;
50
77
}
51
78
 
52
 
static int fill_table_proto(drizzled::message::Table *table_proto,
53
 
                            const char *table_name,
54
 
                            List<CreateField> &create_fields,
55
 
                            HA_CREATE_INFO *create_info,
56
 
                            uint32_t keys,
57
 
                            KEY *key_info)
 
79
/*
 
80
  Create a frm (table definition) file
 
81
 
 
82
  SYNOPSIS
 
83
    mysql_create_frm()
 
84
    thd                 Thread handler
 
85
    file_name           Path for file (including database and .frm)
 
86
    db                  Name of database
 
87
    table               Name of table
 
88
    create_info         create info parameters
 
89
    create_fields       Fields to create
 
90
    keys                number of keys to create
 
91
    key_info            Keys to create
 
92
    db_file             Handler to use. May be zero, in which case we use
 
93
                        create_info->db_type
 
94
  RETURN
 
95
    0  ok
 
96
    1  error
 
97
*/
 
98
 
 
99
bool mysql_create_frm(THD *thd, const char *file_name,
 
100
                      const char *db, const char *table,
 
101
                      HA_CREATE_INFO *create_info,
 
102
                      List<Create_field> &create_fields,
 
103
                      uint keys, KEY *key_info,
 
104
                      handler *db_file)
58
105
{
59
 
  CreateField *field_arg;
60
 
  List_iterator<CreateField> it(create_fields);
61
 
  drizzled::message::Table::TableOptions *table_options= table_proto->mutable_options();
62
 
 
63
 
  if (create_fields.elements > MAX_FIELDS)
64
 
  {
65
 
    my_error(ER_TOO_MANY_FIELDS, MYF(0), ER(ER_TOO_MANY_FIELDS));
66
 
    return(1);
67
 
  }
68
 
 
69
 
  assert(strcmp(table_proto->engine().name().c_str(),
70
 
                create_info->db_type->getName().c_str())==0);
71
 
 
72
 
  assert(strcmp(table_proto->name().c_str(),table_name)==0);
73
 
 
74
 
  while ((field_arg= it++))
75
 
  {
76
 
    drizzled::message::Table::Field *attribute;
77
 
 
78
 
    attribute= table_proto->add_field();
79
 
    attribute->set_name(field_arg->field_name);
80
 
 
81
 
    attribute->set_pack_flag(field_arg->pack_flag); /* TODO: MUST DIE */
82
 
 
83
 
    if(f_maybe_null(field_arg->pack_flag))
 
106
  LEX_STRING str_db_type;
 
107
  uint reclength, info_length, screens, key_info_length, maxlength, tmp_len;
 
108
  ulong key_buff_length;
 
109
  File file;
 
110
  ulong filepos, data_offset;
 
111
  uchar fileinfo[64],forminfo[288],*keybuff;
 
112
  TYPELIB formnames;
 
113
  uchar *screen_buff;
 
114
  char buff[128];
 
115
  const uint format_section_header_size= 8;
 
116
  uint format_section_len;
 
117
  uint tablespace_len= 0;
 
118
  Pack_header_error_handler pack_header_error_handler;
 
119
  int error;
 
120
  DBUG_ENTER("mysql_create_frm");
 
121
 
 
122
  DBUG_ASSERT(*fn_rext((char*)file_name)); // Check .frm extension
 
123
  formnames.type_names=0;
 
124
  if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
 
125
    DBUG_RETURN(1);
 
126
  DBUG_ASSERT(db_file != NULL);
 
127
 
 
128
 /* If fixed row records, we need one bit to check for deleted rows */
 
129
  if (!(create_info->table_options & HA_OPTION_PACK_RECORD))
 
130
    create_info->null_bits++;
 
131
  data_offset= (create_info->null_bits + 7) / 8;
 
132
 
 
133
  thd->push_internal_handler(&pack_header_error_handler);
 
134
 
 
135
  error= pack_header(forminfo, ha_legacy_type(create_info->db_type),
 
136
                     create_fields,info_length,
 
137
                     screens, create_info->table_options,
 
138
                     data_offset, db_file);
 
139
 
 
140
  thd->pop_internal_handler();
 
141
 
 
142
  if (error)
 
143
  {
 
144
    my_free(screen_buff, MYF(0));
 
145
    if (! pack_header_error_handler.is_handled)
 
146
      DBUG_RETURN(1);
 
147
 
 
148
    // Try again without UNIREG screens (to get more columns)
 
149
    if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
 
150
      DBUG_RETURN(1);
 
151
    if (pack_header(forminfo, ha_legacy_type(create_info->db_type),
 
152
                    create_fields,info_length,
 
153
                    screens, create_info->table_options, data_offset, db_file))
84
154
    {
85
 
      drizzled::message::Table::Field::FieldConstraints *constraints;
86
 
 
87
 
      constraints= attribute->mutable_constraints();
88
 
      constraints->set_is_nullable(true);
89
 
    }
90
 
 
91
 
    switch (field_arg->sql_type) {
92
 
    case DRIZZLE_TYPE_TINY:
93
 
      attribute->set_type(drizzled::message::Table::Field::TINYINT);
94
 
      break;
95
 
    case DRIZZLE_TYPE_LONG:
96
 
      attribute->set_type(drizzled::message::Table::Field::INTEGER);
97
 
      break;
98
 
    case DRIZZLE_TYPE_DOUBLE:
99
 
      attribute->set_type(drizzled::message::Table::Field::DOUBLE);
100
 
      break;
101
 
    case DRIZZLE_TYPE_NULL  :
102
 
      assert(1); /* Not a user definable type */
103
 
    case DRIZZLE_TYPE_TIMESTAMP:
104
 
      attribute->set_type(drizzled::message::Table::Field::TIMESTAMP);
105
 
      break;
106
 
    case DRIZZLE_TYPE_LONGLONG:
107
 
      attribute->set_type(drizzled::message::Table::Field::BIGINT);
108
 
      break;
109
 
    case DRIZZLE_TYPE_DATETIME:
110
 
      attribute->set_type(drizzled::message::Table::Field::DATETIME);
111
 
      break;
112
 
    case DRIZZLE_TYPE_DATE:
113
 
      attribute->set_type(drizzled::message::Table::Field::DATE);
114
 
      break;
115
 
    case DRIZZLE_TYPE_VARCHAR:
116
 
      {
117
 
        drizzled::message::Table::Field::StringFieldOptions *string_field_options;
118
 
 
119
 
        string_field_options= attribute->mutable_string_options();
120
 
        attribute->set_type(drizzled::message::Table::Field::VARCHAR);
121
 
        string_field_options->set_length(field_arg->length
122
 
                                         / field_arg->charset->mbmaxlen);
123
 
        string_field_options->set_collation_id(field_arg->charset->number);
124
 
        string_field_options->set_collation(field_arg->charset->name);
125
 
 
126
 
        break;
127
 
      }
128
 
    case DRIZZLE_TYPE_NEWDECIMAL:
129
 
      {
130
 
        drizzled::message::Table::Field::NumericFieldOptions *numeric_field_options;
131
 
 
132
 
        attribute->set_type(drizzled::message::Table::Field::DECIMAL);
133
 
        numeric_field_options= attribute->mutable_numeric_options();
134
 
        /* This is magic, I hate magic numbers -Brian */
135
 
        numeric_field_options->set_precision(field_arg->length + ( field_arg->decimals ? -2 : -1));
136
 
        numeric_field_options->set_scale(field_arg->decimals);
137
 
        break;
138
 
      }
139
 
    case DRIZZLE_TYPE_ENUM:
140
 
      {
141
 
        drizzled::message::Table::Field::SetFieldOptions *set_field_options;
142
 
 
143
 
        assert(field_arg->interval);
144
 
 
145
 
        attribute->set_type(drizzled::message::Table::Field::ENUM);
146
 
        set_field_options= attribute->mutable_set_options();
147
 
 
148
 
        for (uint32_t pos= 0; pos < field_arg->interval->count; pos++)
149
 
        {
150
 
          const char *src= field_arg->interval->type_names[pos];
151
 
 
152
 
          set_field_options->add_field_value(src);
153
 
        }
154
 
        set_field_options->set_count_elements(set_field_options->field_value_size());
155
 
        set_field_options->set_collation_id(field_arg->charset->number);
156
 
        set_field_options->set_collation(field_arg->charset->name);
157
 
        break;
158
 
      }
159
 
    case DRIZZLE_TYPE_BLOB:
160
 
      {
161
 
        attribute->set_type(drizzled::message::Table::Field::BLOB);
162
 
 
163
 
        drizzled::message::Table::Field::StringFieldOptions *string_field_options;
164
 
 
165
 
        string_field_options= attribute->mutable_string_options();
166
 
        string_field_options->set_collation_id(field_arg->charset->number);
167
 
        string_field_options->set_collation(field_arg->charset->name);
168
 
      }
169
 
 
170
 
      break;
171
 
    default:
172
 
      assert(0); /* Tell us, since this shouldn't happend */
173
 
    }
174
 
 
175
 
#ifdef NOTDONE
176
 
    field_constraints= attribute->mutable_constraints();
177
 
    constraints->set_is_nullable(field_arg->def->null_value);
 
155
      my_free(screen_buff, MYF(0));
 
156
      DBUG_RETURN(1);
 
157
    }
 
158
  }
 
159
  reclength=uint2korr(forminfo+266);
 
160
 
 
161
  /* Calculate extra data segment length */
 
162
  str_db_type.str= (char *) ha_resolve_storage_engine_name(create_info->db_type);
 
163
  str_db_type.length= strlen(str_db_type.str);
 
164
  /* str_db_type */
 
165
  create_info->extra_size= (2 + str_db_type.length +
 
166
                            2 + create_info->connect_string.length);
 
167
  /*
 
168
    Partition:
 
169
      Length of partition info = 4 byte
 
170
      Potential NULL byte at end of partition info string = 1 byte
 
171
      Indicator if auto-partitioned table = 1 byte
 
172
      => Total 6 byte
 
173
  */
 
174
  create_info->extra_size+= 6;
 
175
 
 
176
  /* Add space for storage type and field format array of fields */
 
177
  if (create_info->tablespace)
 
178
    tablespace_len= strlen(create_info->tablespace);
 
179
  format_section_len=
 
180
    format_section_header_size +
 
181
    tablespace_len + 1 +
 
182
    create_fields.elements;
 
183
  create_info->extra_size+= format_section_len;
 
184
 
 
185
  tmp_len= system_charset_info->cset->charpos(system_charset_info,
 
186
                                              create_info->comment.str,
 
187
                                              create_info->comment.str +
 
188
                                              create_info->comment.length, 
 
189
                                              TABLE_COMMENT_MAXLEN);
 
190
 
 
191
  if (tmp_len < create_info->comment.length)
 
192
  {
 
193
    my_error(ER_WRONG_STRING_LENGTH, MYF(0),
 
194
             create_info->comment.str,"TABLE COMMENT",
 
195
             (uint) TABLE_COMMENT_MAXLEN);
 
196
    my_free(screen_buff,MYF(0));
 
197
    DBUG_RETURN(1);
 
198
  }
 
199
 
 
200
  //if table comment is larger than 180 bytes, store into extra segment.
 
201
  if (create_info->comment.length > 180)
 
202
  {
 
203
    forminfo[46]=255;
 
204
    create_info->extra_size+= 2 + create_info->comment.length;
 
205
  }
 
206
  else{
 
207
    strmake((char*) forminfo+47, create_info->comment.str ?
 
208
            create_info->comment.str : "", create_info->comment.length);
 
209
    forminfo[46]=(uchar) create_info->comment.length;
 
210
#ifdef EXTRA_DEBUG
 
211
    /*
 
212
      EXTRA_DEBUG causes strmake() to initialize its buffer behind the
 
213
      payload with a magic value to detect wrong buffer-sizes. We
 
214
      explicitly zero that segment again.
 
215
    */
 
216
    memset((char*) forminfo+47 + forminfo[46], 0, 61 - forminfo[46]);
178
217
#endif
179
 
 
180
 
    switch(field_arg->column_format())
181
 
    {
182
 
    case COLUMN_FORMAT_TYPE_NOT_USED:
183
 
      break;
184
 
    case COLUMN_FORMAT_TYPE_DEFAULT:
185
 
      attribute->set_format(drizzled::message::Table::Field::DefaultFormat);
186
 
      break;
187
 
    case COLUMN_FORMAT_TYPE_FIXED:
188
 
      attribute->set_format(drizzled::message::Table::Field::FixedFormat);
189
 
      break;
190
 
    case COLUMN_FORMAT_TYPE_DYNAMIC:
191
 
      attribute->set_format(drizzled::message::Table::Field::DynamicFormat);
192
 
      break;
193
 
    default:
194
 
      assert(0); /* Tell us, since this shouldn't happend */
195
 
    }
196
 
 
197
 
    if (field_arg->comment.length)
198
 
    {
199
 
      uint32_t tmp_len;
200
 
      tmp_len= system_charset_info->cset->charpos(system_charset_info,
201
 
                                                  field_arg->comment.str,
202
 
                                                  field_arg->comment.str +
203
 
                                                  field_arg->comment.length,
204
 
                                                  COLUMN_COMMENT_MAXLEN);
205
 
 
206
 
      if (tmp_len < field_arg->comment.length)
207
 
      {
208
 
        my_error(ER_WRONG_STRING_LENGTH, MYF(0),
209
 
                 field_arg->comment.str,"COLUMN COMMENT",
210
 
                 (uint32_t) COLUMN_COMMENT_MAXLEN);
211
 
        return(1);
212
 
      }
213
 
 
214
 
      attribute->set_comment(field_arg->comment.str);
215
 
    }
216
 
 
217
 
    if(field_arg->unireg_check == Field::NEXT_NUMBER)
218
 
    {
219
 
      drizzled::message::Table::Field::NumericFieldOptions *field_options;
220
 
      field_options= attribute->mutable_numeric_options();
221
 
      field_options->set_is_autoincrement(true);
222
 
    }
223
 
 
224
 
    if(field_arg->unireg_check == Field::TIMESTAMP_DN_FIELD
225
 
       || field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
226
 
    {
227
 
      drizzled::message::Table::Field::FieldOptions *field_options;
228
 
      field_options= attribute->mutable_options();
229
 
      field_options->set_default_value("NOW()");
230
 
    }
231
 
 
232
 
    if(field_arg->unireg_check == Field::TIMESTAMP_UN_FIELD
233
 
       || field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
234
 
    {
235
 
      drizzled::message::Table::Field::FieldOptions *field_options;
236
 
      field_options= attribute->mutable_options();
237
 
      field_options->set_update_value("NOW()");
238
 
    }
239
 
 
240
 
    if(field_arg->def)
241
 
    {
242
 
      drizzled::message::Table::Field::FieldOptions *field_options;
243
 
      field_options= attribute->mutable_options();
244
 
 
245
 
      if(field_arg->def->is_null())
246
 
      {
247
 
        field_options->set_default_null(true);
248
 
      }
249
 
      else
250
 
      {
251
 
        String d;
252
 
        String *default_value= field_arg->def->val_str(&d);
253
 
 
254
 
        assert(default_value);
255
 
 
256
 
        if((field_arg->sql_type==DRIZZLE_TYPE_VARCHAR
257
 
           || field_arg->sql_type==DRIZZLE_TYPE_BLOB)
258
 
           && ((field_arg->length / field_arg->charset->mbmaxlen)
259
 
           < default_value->length()))
260
 
        {
261
 
          my_error(ER_INVALID_DEFAULT, MYF(0), field_arg->field_name);
262
 
          return 1;
263
 
        }
264
 
 
265
 
        if((field_arg->sql_type==DRIZZLE_TYPE_VARCHAR
266
 
            && field_arg->charset==&my_charset_bin)
267
 
           || (field_arg->sql_type==DRIZZLE_TYPE_BLOB
268
 
            && field_arg->charset==&my_charset_bin))
269
 
        {
270
 
          string bin_default;
271
 
          bin_default.assign(default_value->c_ptr(),
272
 
                             default_value->length());
273
 
          field_options->set_default_bin_value(bin_default);
274
 
        }
275
 
        else
276
 
        {
277
 
          field_options->set_default_value(default_value->c_ptr());
278
 
        }
279
 
      }
280
 
    }
281
 
 
282
 
    {
283
 
      drizzled::message::Table::Field::FieldOptions *field_options;
284
 
      field_options= attribute->mutable_options();
285
 
 
286
 
      field_options->set_length(field_arg->length);
287
 
    }
288
 
 
289
 
    assert(field_arg->unireg_check == Field::NONE
290
 
           || field_arg->unireg_check == Field::NEXT_NUMBER
291
 
           || field_arg->unireg_check == Field::TIMESTAMP_DN_FIELD
292
 
           || field_arg->unireg_check == Field::TIMESTAMP_UN_FIELD
293
 
           || field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD);
294
 
 
295
 
  }
296
 
 
297
 
  if (create_info->used_fields & HA_CREATE_USED_PACK_KEYS)
298
 
  {
299
 
    if(create_info->table_options & HA_OPTION_PACK_KEYS)
300
 
      table_options->set_pack_keys(true);
301
 
    else if(create_info->table_options & HA_OPTION_NO_PACK_KEYS)
302
 
      table_options->set_pack_keys(false);
303
 
  }
304
 
  else
305
 
    if(create_info->table_options & HA_OPTION_PACK_KEYS)
306
 
      table_options->set_pack_keys(true);
307
 
 
308
 
 
309
 
  if (create_info->used_fields & HA_CREATE_USED_CHECKSUM)
310
 
  {
311
 
    assert(create_info->table_options & (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM));
312
 
 
313
 
    if(create_info->table_options & HA_OPTION_CHECKSUM)
314
 
      table_options->set_checksum(true);
315
 
    else
316
 
      table_options->set_checksum(false);
317
 
  }
318
 
  else if(create_info->table_options & HA_OPTION_CHECKSUM)
319
 
    table_options->set_checksum(true);
320
 
 
321
 
 
322
 
  if (create_info->used_fields & HA_CREATE_USED_PAGE_CHECKSUM)
323
 
  {
324
 
    if (create_info->page_checksum == HA_CHOICE_YES)
325
 
      table_options->set_page_checksum(true);
326
 
    else if (create_info->page_checksum == HA_CHOICE_NO)
327
 
      table_options->set_page_checksum(false);
328
 
  }
329
 
  else if (create_info->page_checksum == HA_CHOICE_YES)
330
 
    table_options->set_page_checksum(true);
331
 
 
332
 
 
333
 
  if (create_info->used_fields & HA_CREATE_USED_DELAY_KEY_WRITE)
334
 
  {
335
 
    if(create_info->table_options & HA_OPTION_DELAY_KEY_WRITE)
336
 
      table_options->set_delay_key_write(true);
337
 
    else if(create_info->table_options & HA_OPTION_NO_DELAY_KEY_WRITE)
338
 
      table_options->set_delay_key_write(false);
339
 
  }
340
 
  else if(create_info->table_options & HA_OPTION_DELAY_KEY_WRITE)
341
 
    table_options->set_delay_key_write(true);
342
 
 
343
 
 
344
 
  switch(create_info->row_type)
345
 
  {
346
 
  case ROW_TYPE_DEFAULT:
347
 
    table_options->set_row_type(drizzled::message::Table::TableOptions::ROW_TYPE_DEFAULT);
348
 
    break;
349
 
  case ROW_TYPE_FIXED:
350
 
    table_options->set_row_type(drizzled::message::Table::TableOptions::ROW_TYPE_FIXED);
351
 
    break;
352
 
  case ROW_TYPE_DYNAMIC:
353
 
    table_options->set_row_type(drizzled::message::Table::TableOptions::ROW_TYPE_DYNAMIC);
354
 
    break;
355
 
  case ROW_TYPE_COMPRESSED:
356
 
    table_options->set_row_type(drizzled::message::Table::TableOptions::ROW_TYPE_COMPRESSED);
357
 
    break;
358
 
  case ROW_TYPE_REDUNDANT:
359
 
    table_options->set_row_type(drizzled::message::Table::TableOptions::ROW_TYPE_REDUNDANT);
360
 
    break;
361
 
  case ROW_TYPE_COMPACT:
362
 
    table_options->set_row_type(drizzled::message::Table::TableOptions::ROW_TYPE_COMPACT);
363
 
    break;
364
 
  case ROW_TYPE_PAGE:
365
 
    table_options->set_row_type(drizzled::message::Table::TableOptions::ROW_TYPE_PAGE);
366
 
    break;
367
 
  default:
368
 
    abort();
369
 
  }
370
 
 
371
 
  table_options->set_pack_record(create_info->table_options
372
 
                                 & HA_OPTION_PACK_RECORD);
373
 
 
374
 
  if (create_info->comment.length)
375
 
  {
376
 
    uint32_t tmp_len;
377
 
    tmp_len= system_charset_info->cset->charpos(system_charset_info,
378
 
                                                create_info->comment.str,
379
 
                                                create_info->comment.str +
380
 
                                                create_info->comment.length,
381
 
                                                TABLE_COMMENT_MAXLEN);
382
 
 
383
 
    if (tmp_len < create_info->comment.length)
384
 
    {
385
 
      my_error(ER_WRONG_STRING_LENGTH, MYF(0),
386
 
               create_info->comment.str,"Table COMMENT",
387
 
               (uint32_t) TABLE_COMMENT_MAXLEN);
388
 
      return(1);
389
 
    }
390
 
 
391
 
    table_options->set_comment(create_info->comment.str);
392
 
  }
393
 
  if (create_info->default_table_charset)
394
 
  {
395
 
    table_options->set_collation_id(
396
 
                               create_info->default_table_charset->number);
397
 
    table_options->set_collation(create_info->default_table_charset->name);
398
 
  }
399
 
 
400
 
  if (create_info->connect_string.length)
401
 
    table_options->set_connect_string(create_info->connect_string.str);
402
 
 
403
 
  if (create_info->data_file_name)
404
 
    table_options->set_data_file_name(create_info->data_file_name);
405
 
 
406
 
  if (create_info->index_file_name)
407
 
    table_options->set_index_file_name(create_info->index_file_name);
408
 
 
409
 
  if (create_info->max_rows)
410
 
    table_options->set_max_rows(create_info->max_rows);
411
 
 
412
 
  if (create_info->min_rows)
413
 
    table_options->set_min_rows(create_info->min_rows);
414
 
 
415
 
  if (create_info->auto_increment_value)
416
 
    table_options->set_auto_increment_value(create_info->auto_increment_value);
417
 
 
418
 
  if (create_info->avg_row_length)
419
 
    table_options->set_avg_row_length(create_info->avg_row_length);
420
 
 
421
 
  if (create_info->key_block_size)
422
 
    table_options->set_key_block_size(create_info->key_block_size);
423
 
 
424
 
  if (create_info->block_size)
425
 
    table_options->set_block_size(create_info->block_size);
426
 
 
427
 
  for (unsigned int i= 0; i < keys; i++)
428
 
  {
429
 
    drizzled::message::Table::Index *idx;
430
 
 
431
 
    idx= table_proto->add_indexes();
432
 
 
433
 
    assert(test(key_info[i].flags & HA_USES_COMMENT) ==
434
 
           (key_info[i].comment.length > 0));
435
 
 
436
 
    idx->set_name(key_info[i].name);
437
 
 
438
 
    idx->set_key_length(key_info[i].key_length);
439
 
 
440
 
    if(is_primary_key_name(key_info[i].name))
441
 
      idx->set_is_primary(true);
442
 
    else
443
 
      idx->set_is_primary(false);
444
 
 
445
 
    switch(key_info[i].algorithm)
446
 
    {
447
 
    case HA_KEY_ALG_HASH:
448
 
      idx->set_type(drizzled::message::Table::Index::HASH);
449
 
      break;
450
 
 
451
 
    case HA_KEY_ALG_BTREE:
452
 
      idx->set_type(drizzled::message::Table::Index::BTREE);
453
 
      break;
454
 
 
455
 
    case HA_KEY_ALG_RTREE:
456
 
      idx->set_type(drizzled::message::Table::Index::RTREE);
457
 
    case HA_KEY_ALG_FULLTEXT:
458
 
      idx->set_type(drizzled::message::Table::Index::FULLTEXT);
459
 
    case HA_KEY_ALG_UNDEF:
460
 
      idx->set_type(drizzled::message::Table::Index::UNKNOWN_INDEX);
461
 
      break;
462
 
 
463
 
    default:
464
 
      abort(); /* Somebody's brain broke. haven't added index type to proto */
465
 
    }
466
 
 
467
 
    if (key_info[i].flags & HA_NOSAME)
468
 
      idx->set_is_unique(true);
469
 
    else
470
 
      idx->set_is_unique(false);
471
 
 
472
 
    drizzled::message::Table::Index::IndexOptions *index_options= idx->mutable_options();
473
 
 
474
 
    if(key_info[i].flags & HA_USES_BLOCK_SIZE)
475
 
      index_options->set_key_block_size(key_info[i].block_size);
476
 
 
477
 
    if(key_info[i].flags & HA_PACK_KEY)
478
 
      index_options->set_pack_key(true);
479
 
 
480
 
    if(key_info[i].flags & HA_BINARY_PACK_KEY)
481
 
      index_options->set_binary_pack_key(true);
482
 
 
483
 
    if(key_info[i].flags & HA_VAR_LENGTH_PART)
484
 
      index_options->set_var_length_key(true);
485
 
 
486
 
    if(key_info[i].flags & HA_NULL_PART_KEY)
487
 
      index_options->set_null_part_key(true);
488
 
 
489
 
    if(key_info[i].flags & HA_KEY_HAS_PART_KEY_SEG)
490
 
      index_options->set_has_partial_segments(true);
491
 
 
492
 
    if(key_info[i].flags & HA_GENERATED_KEY)
493
 
      index_options->set_auto_generated_key(true);
494
 
 
495
 
    if (key_info[i].flags & HA_USES_COMMENT)
496
 
    {
497
 
      uint32_t tmp_len;
498
 
      tmp_len= system_charset_info->cset->charpos(system_charset_info,
499
 
                                                  key_info[i].comment.str,
500
 
                                                  key_info[i].comment.str +
501
 
                                                  key_info[i].comment.length,
502
 
                                                  TABLE_COMMENT_MAXLEN);
503
 
 
504
 
      if (tmp_len < key_info[i].comment.length)
505
 
      {
506
 
        my_error(ER_WRONG_STRING_LENGTH, MYF(0),
507
 
                 key_info[i].comment.str,"Index COMMENT",
508
 
                 (uint32_t) TABLE_COMMENT_MAXLEN);
509
 
        return(1);
510
 
      }
511
 
 
512
 
      idx->set_comment(key_info[i].comment.str);
513
 
    }
514
 
    if(key_info[i].flags & ~(HA_NOSAME | HA_PACK_KEY | HA_USES_BLOCK_SIZE | HA_BINARY_PACK_KEY | HA_VAR_LENGTH_PART | HA_NULL_PART_KEY | HA_KEY_HAS_PART_KEY_SEG | HA_GENERATED_KEY | HA_USES_COMMENT))
515
 
      abort(); // Invalid (unknown) index flag.
516
 
 
517
 
    for(unsigned int j=0; j< key_info[i].key_parts; j++)
518
 
    {
519
 
      drizzled::message::Table::Index::IndexPart *idxpart;
520
 
 
521
 
      idxpart= idx->add_index_part();
522
 
 
523
 
      idxpart->set_fieldnr(key_info[i].key_part[j].fieldnr);
524
 
 
525
 
      idxpart->set_compare_length(key_info[i].key_part[j].length);
526
 
 
527
 
      idxpart->set_key_type(key_info[i].key_part[j].key_type);
528
 
 
529
 
    }
530
 
  }
531
 
 
532
 
  return 0;
533
 
}
534
 
 
535
 
int copy_table_proto_file(const char *from, const char* to)
536
 
{
537
 
  string dfesrc(from);
538
 
  string dfedst(to);
539
 
  string file_ext = ".dfe";
540
 
 
541
 
  dfesrc.append(file_ext);
542
 
  dfedst.append(file_ext);
543
 
 
544
 
  return my_copy(dfesrc.c_str(), dfedst.c_str(),
545
 
                 MYF(MY_DONT_OVERWRITE_FILE));
546
 
}
547
 
 
548
 
int rename_table_proto_file(const char *from, const char* to)
549
 
{
550
 
  string from_path(from);
551
 
  string to_path(to);
552
 
  string file_ext = ".dfe";
553
 
 
554
 
  from_path.append(file_ext);
555
 
  to_path.append(file_ext);
556
 
 
557
 
  return my_rename(from_path.c_str(),to_path.c_str(),MYF(MY_WME));
558
 
}
559
 
 
560
 
int delete_table_proto_file(const char *file_name)
561
 
{
562
 
  string new_path(file_name);
563
 
  string file_ext = ".dfe";
564
 
 
565
 
  new_path.append(file_ext);
566
 
  return my_delete(new_path.c_str(), MYF(0));
567
 
}
568
 
 
569
 
int table_proto_exists(const char *path)
570
 
{
571
 
  string proto_path(path);
572
 
  string file_ext(".dfe");
573
 
  proto_path.append(file_ext);
574
 
 
575
 
  int error= access(proto_path.c_str(), F_OK);
576
 
 
577
 
  if (error == 0)
578
 
    return EEXIST;
579
 
  else
580
 
    return errno;
581
 
}
582
 
 
583
 
static int create_table_proto_file(const char *file_name,
584
 
                                   const char *db,
585
 
                                   const char *table_name,
586
 
                                   drizzled::message::Table *table_proto,
587
 
                                   HA_CREATE_INFO *create_info,
588
 
                                   List<CreateField> &create_fields,
589
 
                                   uint32_t keys,
590
 
                                   KEY *key_info)
591
 
{
592
 
  string new_path(file_name);
593
 
  string file_ext = ".dfe";
594
 
 
595
 
  if(fill_table_proto(table_proto, table_name, create_fields, create_info,
596
 
                      keys, key_info))
597
 
    return -1;
598
 
 
599
 
  new_path.append(file_ext);
600
 
 
601
 
  int fd= open(new_path.c_str(), O_RDWR|O_CREAT|O_TRUNC, my_umask);
602
 
 
603
 
  if(fd==-1)
604
 
  {
605
 
    if(errno==ENOENT)
606
 
      my_error(ER_BAD_DB_ERROR,MYF(0),db);
607
 
    else
608
 
      my_error(ER_CANT_CREATE_TABLE,MYF(0),table_name,errno);
609
 
    return errno;
610
 
  }
611
 
 
612
 
  google::protobuf::io::ZeroCopyOutputStream* output=
613
 
    new google::protobuf::io::FileOutputStream(fd);
614
 
 
615
 
  if (!table_proto->SerializeToZeroCopyStream(output))
616
 
  {
617
 
    delete output;
618
 
    close(fd);
619
 
    return errno;
620
 
  }
621
 
 
622
 
  delete output;
623
 
  close(fd);
624
 
  return 0;
625
 
}
 
218
  }
 
219
 
 
220
  if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
 
221
                       create_info, keys, key_info)) < 0)
 
222
  {
 
223
    my_free(screen_buff, MYF(0));
 
224
    DBUG_RETURN(1);
 
225
  }
 
226
 
 
227
  key_buff_length= uint4korr(fileinfo+47);
 
228
  keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
 
229
  key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
 
230
  VOID(get_form_pos(file,fileinfo,&formnames));
 
231
  if (!(filepos=make_new_entry(file,fileinfo,&formnames,"")))
 
232
    goto err;
 
233
  maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
 
234
  int2store(forminfo+2,maxlength);
 
235
  int4store(fileinfo+10,(ulong) (filepos+maxlength));
 
236
  fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
 
237
                             (create_info->min_rows == 1) && (keys == 0));
 
238
  int2store(fileinfo+28,key_info_length);
 
239
 
 
240
 
 
241
  int2store(fileinfo+59,db_file->extra_rec_buf_length());
 
242
 
 
243
  if (pwrite(file, fileinfo, 64, 0L) == 0 ||
 
244
      pwrite(file, keybuff, key_info_length, (ulong) uint2korr(fileinfo+6)) == 0)
 
245
    goto err;
 
246
  VOID(my_seek(file,
 
247
               (ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
 
248
               MY_SEEK_SET,MYF(0)));
 
249
  if (make_empty_rec(thd,file,ha_legacy_type(create_info->db_type),
 
250
                     create_info->table_options,
 
251
                     create_fields,reclength, data_offset, db_file))
 
252
    goto err;
 
253
 
 
254
  int2store(buff, create_info->connect_string.length);
 
255
  if (my_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
 
256
      my_write(file, (const uchar*)create_info->connect_string.str,
 
257
               create_info->connect_string.length, MYF(MY_NABP)))
 
258
      goto err;
 
259
 
 
260
  int2store(buff, str_db_type.length);
 
261
  if (my_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
 
262
      my_write(file, (const uchar*)str_db_type.str,
 
263
               str_db_type.length, MYF(MY_NABP)))
 
264
    goto err;
 
265
 
 
266
  {
 
267
    bzero((uchar*) buff, 6);
 
268
    if (my_write(file, (uchar*) buff, 6, MYF_RW))
 
269
      goto err;
 
270
  }
 
271
 
 
272
  if (forminfo[46] == (uchar)255)
 
273
  {
 
274
    uchar comment_length_buff[2];
 
275
    int2store(comment_length_buff,create_info->comment.length);
 
276
    if (my_write(file, comment_length_buff, 2, MYF(MY_NABP)) ||
 
277
        my_write(file, (uchar*)create_info->comment.str,
 
278
                  create_info->comment.length, MYF(MY_NABP)))
 
279
      goto err;
 
280
  }
 
281
 
 
282
  /* Store storage type and field format array of fields */
 
283
  {
 
284
    /* prepare header */
 
285
    {
 
286
      uint flags= 0;
 
287
      flags|= create_info->default_storage_media; //3 bits
 
288
 
 
289
      bzero(buff, format_section_header_size);
 
290
      /* length of section 2 bytes*/
 
291
      int2store(buff+0, format_section_len);
 
292
      /* flags of section 4 bytes*/
 
293
      int4store(buff+2, flags);
 
294
      /* 2 bytes left for future use */
 
295
    }
 
296
    /* write header */
 
297
    if (my_write(file, (const uchar*)buff, format_section_header_size, MYF_RW))
 
298
      goto err;
 
299
    /* write tablespace name */
 
300
    if (tablespace_len > 0)
 
301
      if (my_write(file, (const uchar*)create_info->tablespace, tablespace_len, MYF_RW))
 
302
        goto err;
 
303
    buff[0]= 0;
 
304
    if (my_write(file, (const uchar*)buff, 1, MYF_RW))
 
305
      goto err;
 
306
    /* write column info, 1 byte per column */
 
307
    {
 
308
      List_iterator<Create_field> it(create_fields);
 
309
      Create_field *field;
 
310
      uchar storage_type, column_format, write_byte;
 
311
      while ((field=it++))
 
312
      {
 
313
        storage_type= (uchar)field->field_storage_type();
 
314
        column_format= (uchar)field->column_format();
 
315
        write_byte= storage_type + (column_format << COLUMN_FORMAT_SHIFT);
 
316
        if (my_write(file, &write_byte, 1, MYF_RW))
 
317
          goto err;
 
318
      }
 
319
    }
 
320
  }
 
321
  VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
 
322
  if (my_write(file, forminfo, 288, MYF_RW) ||
 
323
      my_write(file, screen_buff, info_length, MYF_RW) ||
 
324
      pack_fields(file, create_fields, data_offset))
 
325
    goto err;
 
326
 
 
327
  my_free(screen_buff,MYF(0));
 
328
  my_free(keybuff, MYF(0));
 
329
 
 
330
  if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
 
331
      (my_sync(file, MYF(MY_WME)) ||
 
332
       my_sync_dir_by_file(file_name, MYF(MY_WME))))
 
333
      goto err2;
 
334
 
 
335
  if (my_close(file,MYF(MY_WME)))
 
336
    goto err3;
 
337
 
 
338
  {
 
339
    /* 
 
340
      Restore all UCS2 intervals.
 
341
      HEX representation of them is not needed anymore.
 
342
    */
 
343
    List_iterator<Create_field> it(create_fields);
 
344
    Create_field *field;
 
345
    while ((field=it++))
 
346
    {
 
347
      if (field->save_interval)
 
348
      {
 
349
        field->interval= field->save_interval;
 
350
        field->save_interval= 0;
 
351
      }
 
352
    }
 
353
  }
 
354
  DBUG_RETURN(0);
 
355
 
 
356
err:
 
357
  my_free(screen_buff, MYF(0));
 
358
  my_free(keybuff, MYF(0));
 
359
err2:
 
360
  VOID(my_close(file,MYF(MY_WME)));
 
361
err3:
 
362
  my_delete(file_name,MYF(0));
 
363
  DBUG_RETURN(1);
 
364
} /* mysql_create_frm */
 
365
 
626
366
 
627
367
/*
628
 
  Create a table definition proto file and the tables
 
368
  Create a frm (table definition) file and the tables
629
369
 
630
370
  SYNOPSIS
631
371
    rea_create_table()
632
 
    session                     Thread handler
 
372
    thd                 Thread handler
633
373
    path                Name of file (including database, without .frm)
634
374
    db                  Data base name
635
375
    table_name          Table name
638
378
    keys                number of keys to create
639
379
    key_info            Keys to create
640
380
    file                Handler to use
641
 
    is_like             is true for mysql_create_like_schema_frm
642
381
 
643
382
  RETURN
644
383
    0  ok
645
384
    1  error
646
385
*/
647
386
 
648
 
int rea_create_table(Session *session, const char *path,
 
387
int rea_create_table(THD *thd, const char *path,
649
388
                     const char *db, const char *table_name,
650
 
                     drizzled::message::Table *table_proto,
651
389
                     HA_CREATE_INFO *create_info,
652
 
                     List<CreateField> &create_fields,
653
 
                     uint32_t keys, KEY *key_info,
654
 
                     bool is_like)
 
390
                     List<Create_field> &create_fields,
 
391
                     uint keys, KEY *key_info, handler *file)
655
392
{
656
 
  /* Proto will blow up unless we give a name */
657
 
  assert(table_name);
658
 
 
659
 
  /* For is_like we return once the file has been created */
660
 
  if (is_like)
661
 
  {
662
 
    if (create_table_proto_file(path, db, table_name, table_proto,
663
 
                                create_info,
664
 
                                create_fields, keys, key_info)!=0)
665
 
      return 1;
666
 
 
667
 
    return 0;
668
 
  }
669
 
  /* Here we need to build the full frm from the path */
670
 
  else
671
 
  {
672
 
    if (create_table_proto_file(path, db, table_name, table_proto,
673
 
                                create_info,
674
 
                                create_fields, keys, key_info))
675
 
      return 1;
676
 
  }
677
 
 
678
 
  if (ha_create_table(session, path, db, table_name,
679
 
                      create_info,0))
680
 
    goto err_handler;
681
 
  return 0;
 
393
  DBUG_ENTER("rea_create_table");
 
394
 
 
395
  char frm_name[FN_REFLEN];
 
396
  strxmov(frm_name, path, reg_ext, NullS);
 
397
  if (mysql_create_frm(thd, frm_name, db, table_name, create_info,
 
398
                       create_fields, keys, key_info, file))
 
399
 
 
400
    DBUG_RETURN(1);
 
401
 
 
402
  // Make sure mysql_create_frm din't remove extension
 
403
  DBUG_ASSERT(*fn_rext(frm_name));
 
404
  if (thd->variables.keep_files_on_create)
 
405
    create_info->options|= HA_CREATE_KEEP_FILES;
 
406
  if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info))
 
407
    goto err_handler;
 
408
  if (!create_info->frm_only && ha_create_table(thd, path, db, table_name,
 
409
                                                create_info,0))
 
410
    goto err_handler;
 
411
  DBUG_RETURN(0);
682
412
 
683
413
err_handler:
684
 
  delete_table_proto_file(path);
685
 
 
686
 
  return 1;
 
414
  VOID(file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info));
 
415
  my_delete(frm_name, MYF(0));
 
416
  DBUG_RETURN(1);
687
417
} /* rea_create_table */
 
418
 
 
419
 
 
420
        /* Pack screens to a screen for save in a form-file */
 
421
 
 
422
static uchar *pack_screens(List<Create_field> &create_fields,
 
423
                           uint *info_length, uint *screens,
 
424
                           bool small_file)
 
425
{
 
426
  register uint i;
 
427
  uint row,start_row,end_row,fields_on_screen;
 
428
  uint length,cols;
 
429
  uchar *info,*pos,*start_screen;
 
430
  uint fields=create_fields.elements;
 
431
  List_iterator<Create_field> it(create_fields);
 
432
  DBUG_ENTER("pack_screens");
 
433
 
 
434
  start_row=4; end_row=22; cols=80; fields_on_screen=end_row+1-start_row;
 
435
 
 
436
  *screens=(fields-1)/fields_on_screen+1;
 
437
  length= (*screens) * (SC_INFO_LENGTH+ (cols>> 1)+4);
 
438
 
 
439
  Create_field *field;
 
440
  while ((field=it++))
 
441
    length+=(uint) strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
 
442
 
 
443
  if (!(info=(uchar*) my_malloc(length,MYF(MY_WME))))
 
444
    DBUG_RETURN(0);
 
445
 
 
446
  start_screen=0;
 
447
  row=end_row;
 
448
  pos=info;
 
449
  it.rewind();
 
450
  for (i=0 ; i < fields ; i++)
 
451
  {
 
452
    Create_field *cfield=it++;
 
453
    if (row++ == end_row)
 
454
    {
 
455
      if (i)
 
456
      {
 
457
        length=(uint) (pos-start_screen);
 
458
        int2store(start_screen,length);
 
459
        start_screen[2]=(uchar) (fields_on_screen+1);
 
460
        start_screen[3]=(uchar) (fields_on_screen);
 
461
      }
 
462
      row=start_row;
 
463
      start_screen=pos;
 
464
      pos+=4;
 
465
      pos[0]= (uchar) start_row-2;      /* Header string */
 
466
      pos[1]= (uchar) (cols >> 2);
 
467
      pos[2]= (uchar) (cols >> 1) +1;
 
468
      strfill((char *) pos+3,(uint) (cols >> 1),' ');
 
469
      pos+=(cols >> 1)+4;
 
470
    }
 
471
    length=(uint) strlen(cfield->field_name);
 
472
    if (length > cols-3)
 
473
      length=cols-3;
 
474
 
 
475
    if (!small_file)
 
476
    {
 
477
      pos[0]=(uchar) row;
 
478
      pos[1]=0;
 
479
      pos[2]=(uchar) (length+1);
 
480
      pos=(uchar*) strmake((char*) pos+3,cfield->field_name,length)+1;
 
481
    }
 
482
    cfield->row=(uint8) row;
 
483
    cfield->col=(uint8) (length+1);
 
484
    cfield->sc_length=(uint8) min(cfield->length,cols-(length+2));
 
485
  }
 
486
  length=(uint) (pos-start_screen);
 
487
  int2store(start_screen,length);
 
488
  start_screen[2]=(uchar) (row-start_row+2);
 
489
  start_screen[3]=(uchar) (row-start_row+1);
 
490
 
 
491
  *info_length=(uint) (pos-info);
 
492
  DBUG_RETURN(info);
 
493
} /* pack_screens */
 
494
 
 
495
 
 
496
        /* Pack keyinfo and keynames to keybuff for save in form-file. */
 
497
 
 
498
static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
 
499
                      ulong data_offset)
 
500
{
 
501
  uint key_parts,length;
 
502
  uchar *pos, *keyname_pos;
 
503
  KEY *key,*end;
 
504
  KEY_PART_INFO *key_part,*key_part_end;
 
505
  DBUG_ENTER("pack_keys");
 
506
 
 
507
  pos=keybuff+6;
 
508
  key_parts=0;
 
509
  for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
 
510
  {
 
511
    int2store(pos, (key->flags ^ HA_NOSAME));
 
512
    int2store(pos+2,key->key_length);
 
513
    pos[4]= (uchar) key->key_parts;
 
514
    pos[5]= (uchar) key->algorithm;
 
515
    int2store(pos+6, key->block_size);
 
516
    pos+=8;
 
517
    key_parts+=key->key_parts;
 
518
    DBUG_PRINT("loop", ("flags: %lu  key_parts: %d at 0x%lx",
 
519
                        key->flags, key->key_parts,
 
520
                        (long) key->key_part));
 
521
    for (key_part=key->key_part,key_part_end=key_part+key->key_parts ;
 
522
         key_part != key_part_end ;
 
523
         key_part++)
 
524
 
 
525
    {
 
526
      uint offset;
 
527
      DBUG_PRINT("loop",("field: %d  startpos: %lu  length: %d",
 
528
                         key_part->fieldnr, key_part->offset + data_offset,
 
529
                         key_part->length));
 
530
      int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED);
 
531
      offset= (uint) (key_part->offset+data_offset+1);
 
532
      int2store(pos+2, offset);
 
533
      pos[4]=0;                                 // Sort order
 
534
      int2store(pos+5,key_part->key_type);
 
535
      int2store(pos+7,key_part->length);
 
536
      pos+=9;
 
537
    }
 
538
  }
 
539
        /* Save keynames */
 
540
  keyname_pos=pos;
 
541
  *pos++=(uchar) NAMES_SEP_CHAR;
 
542
  for (key=keyinfo ; key != end ; key++)
 
543
  {
 
544
    uchar *tmp=(uchar*) strmov((char*) pos,key->name);
 
545
    *tmp++= (uchar) NAMES_SEP_CHAR;
 
546
    *tmp=0;
 
547
    pos=tmp;
 
548
  }
 
549
  *(pos++)=0;
 
550
 
 
551
  for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
 
552
  {
 
553
    if (key->flags & HA_USES_COMMENT)
 
554
    {
 
555
      int2store(pos, key->comment.length);
 
556
      uchar *tmp= (uchar*)strnmov((char*) pos+2,key->comment.str,key->comment.length);
 
557
      pos= tmp;
 
558
    }
 
559
  }
 
560
 
 
561
  if (key_count > 127 || key_parts > 127)
 
562
  {
 
563
    keybuff[0]= (key_count & 0x7f) | 0x80;
 
564
    keybuff[1]= key_count >> 7;
 
565
    int2store(keybuff+2,key_parts);
 
566
  }
 
567
  else
 
568
  {
 
569
    keybuff[0]=(uchar) key_count;
 
570
    keybuff[1]=(uchar) key_parts;
 
571
    keybuff[2]= keybuff[3]= 0;
 
572
  }
 
573
  length=(uint) (pos-keyname_pos);
 
574
  int2store(keybuff+4,length);
 
575
  DBUG_RETURN((uint) (pos-keybuff));
 
576
} /* pack_keys */
 
577
 
 
578
 
 
579
        /* Make formheader */
 
580
 
 
581
static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
 
582
                        List<Create_field> &create_fields,
 
583
                        uint info_length, uint screens, uint table_options,
 
584
                        ulong data_offset, handler *file)
 
585
{
 
586
  uint length,int_count,int_length,no_empty, int_parts;
 
587
  uint time_stamp_pos,null_fields;
 
588
  ulong reclength, totlength, n_length, com_length;
 
589
  DBUG_ENTER("pack_header");
 
590
 
 
591
  if (create_fields.elements > MAX_FIELDS)
 
592
  {
 
593
    my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
 
594
    DBUG_RETURN(1);
 
595
  }
 
596
 
 
597
  totlength= 0L;
 
598
  reclength= data_offset;
 
599
  no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=
 
600
    com_length=0;
 
601
  n_length=2L;
 
602
 
 
603
        /* Check fields */
 
604
 
 
605
  List_iterator<Create_field> it(create_fields);
 
606
  Create_field *field;
 
607
  while ((field=it++))
 
608
  {
 
609
    uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
 
610
                                                     field->comment.str,
 
611
                                                     field->comment.str +
 
612
                                                     field->comment.length,
 
613
                                                     COLUMN_COMMENT_MAXLEN);
 
614
 
 
615
    if (tmp_len < field->comment.length)
 
616
    {
 
617
      my_error(ER_WRONG_STRING_LENGTH, MYF(0),
 
618
               field->comment.str,"COLUMN COMMENT",
 
619
               (uint) COLUMN_COMMENT_MAXLEN);
 
620
      DBUG_RETURN(1);
 
621
    }
 
622
 
 
623
    totlength+= field->length;
 
624
    com_length+= field->comment.length;
 
625
    if (MTYP_TYPENR(field->unireg_check) == Field::NOEMPTY ||
 
626
        field->unireg_check & MTYP_NOEMPTY_BIT)
 
627
    {
 
628
      field->unireg_check= (Field::utype) ((uint) field->unireg_check |
 
629
                                           MTYP_NOEMPTY_BIT);
 
630
      no_empty++;
 
631
    }
 
632
    /* 
 
633
      We mark first TIMESTAMP field with NOW() in DEFAULT or ON UPDATE 
 
634
      as auto-update field.
 
635
    */
 
636
    if (field->sql_type == MYSQL_TYPE_TIMESTAMP &&
 
637
        MTYP_TYPENR(field->unireg_check) != Field::NONE &&
 
638
        !time_stamp_pos)
 
639
      time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1;
 
640
    length=field->pack_length;
 
641
    /* Ensure we don't have any bugs when generating offsets */
 
642
    DBUG_ASSERT(reclength == field->offset + data_offset);
 
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
      uint 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
          (uint *) sql_alloc(sizeof(uint) * field->interval->count);
 
671
 
 
672
        for (uint pos= 0; pos < field->interval->count; pos++)
 
673
        {
 
674
          char *dst;
 
675
          const char *src= field->save_interval->type_names[pos];
 
676
          uint 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
    DBUG_RETURN(1);
 
705
  }
 
706
  /* Hack to avoid bugs with small static rows in MySQL */
 
707
  reclength=max(file->min_record_length(table_options),reclength);
 
708
  if (info_length+(ulong) create_fields.elements*FCOMP+288+
 
709
      n_length+int_length+com_length > 65535L || int_count > 255)
 
710
  {
 
711
    my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
 
712
    DBUG_RETURN(1);
 
713
  }
 
714
 
 
715
  bzero((char*)forminfo,288);
 
716
  length=(info_length+create_fields.elements*FCOMP+288+n_length+int_length+
 
717
          com_length);
 
718
  int2store(forminfo,length);
 
719
  forminfo[256] = (uint8) screens;
 
720
  int2store(forminfo+258,create_fields.elements);
 
721
  int2store(forminfo+260,info_length);
 
722
  int2store(forminfo+262,totlength);
 
723
  int2store(forminfo+264,no_empty);
 
724
  int2store(forminfo+266,reclength);
 
725
  int2store(forminfo+268,n_length);
 
726
  int2store(forminfo+270,int_count);
 
727
  int2store(forminfo+272,int_parts);
 
728
  int2store(forminfo+274,int_length);
 
729
  int2store(forminfo+276,time_stamp_pos);
 
730
  int2store(forminfo+278,80);                   /* Columns needed */
 
731
  int2store(forminfo+280,22);                   /* Rows needed */
 
732
  int2store(forminfo+282,null_fields);
 
733
  int2store(forminfo+284,com_length);
 
734
  /* Up to forminfo+288 is free to use for additional information */
 
735
  DBUG_RETURN(0);
 
736
} /* pack_header */
 
737
 
 
738
 
 
739
        /* get each unique interval each own id */
 
740
 
 
741
static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
 
742
                            Create_field *last_field)
 
743
{
 
744
  List_iterator<Create_field> it(create_fields);
 
745
  Create_field *field;
 
746
  TYPELIB *interval=last_field->interval;
 
747
 
 
748
  while ((field=it++) != last_field)
 
749
  {
 
750
    if (field->interval_id && field->interval->count == interval->count)
 
751
    {
 
752
      const char **a,**b;
 
753
      for (a=field->interval->type_names, b=interval->type_names ;
 
754
           *a && !strcmp(*a,*b);
 
755
           a++,b++) ;
 
756
 
 
757
      if (! *a)
 
758
      {
 
759
        return field->interval_id;              // Re-use last interval
 
760
      }
 
761
    }
 
762
  }
 
763
  return ++*int_count;                          // New unique interval
 
764
}
 
765
 
 
766
 
 
767
        /* Save fields, fieldnames and intervals */
 
768
 
 
769
static bool pack_fields(File file, List<Create_field> &create_fields,
 
770
                        ulong data_offset)
 
771
{
 
772
  register uint i;
 
773
  uint int_count, comment_length=0;
 
774
  uchar buff[MAX_FIELD_WIDTH];
 
775
  Create_field *field;
 
776
  DBUG_ENTER("pack_fields");
 
777
 
 
778
        /* Write field info */
 
779
 
 
780
  List_iterator<Create_field> it(create_fields);
 
781
 
 
782
  int_count=0;
 
783
  while ((field=it++))
 
784
  {
 
785
    uint recpos;
 
786
    buff[0]= (uchar) field->row;
 
787
    buff[1]= (uchar) field->col;
 
788
    buff[2]= (uchar) field->sc_length;
 
789
    int2store(buff+3, field->length);
 
790
    /* The +1 is here becasue the col offset in .frm file have offset 1 */
 
791
    recpos= field->offset+1 + (uint) data_offset;
 
792
    int3store(buff+5,recpos);
 
793
    int2store(buff+8,field->pack_flag);
 
794
    int2store(buff+10,field->unireg_check);
 
795
    buff[12]= (uchar) field->interval_id;
 
796
    buff[13]= (uchar) field->sql_type; 
 
797
    if (field->charset) 
 
798
      buff[14]= (uchar) field->charset->number;
 
799
    else
 
800
      buff[14]= 0;                              // Numerical
 
801
    int2store(buff+15, field->comment.length);
 
802
    comment_length+= field->comment.length;
 
803
    set_if_bigger(int_count,field->interval_id);
 
804
    if (my_write(file, buff, FCOMP, MYF_RW))
 
805
      DBUG_RETURN(1);
 
806
  }
 
807
 
 
808
        /* Write fieldnames */
 
809
  buff[0]=(uchar) NAMES_SEP_CHAR;
 
810
  if (my_write(file, buff, 1, MYF_RW))
 
811
    DBUG_RETURN(1);
 
812
  i=0;
 
813
  it.rewind();
 
814
  while ((field=it++))
 
815
  {
 
816
    char *pos= strmov((char*) buff,field->field_name);
 
817
    *pos++=NAMES_SEP_CHAR;
 
818
    if (i == create_fields.elements-1)
 
819
      *pos++=0;
 
820
    if (my_write(file, buff, (size_t) (pos-(char*) buff),MYF_RW))
 
821
      DBUG_RETURN(1);
 
822
    i++;
 
823
  }
 
824
 
 
825
        /* Write intervals */
 
826
  if (int_count)
 
827
  {
 
828
    String tmp((char*) buff,sizeof(buff), &my_charset_bin);
 
829
    tmp.length(0);
 
830
    it.rewind();
 
831
    int_count=0;
 
832
    while ((field=it++))
 
833
    {
 
834
      if (field->interval_id > int_count)
 
835
      {
 
836
        unsigned char  sep= 0;
 
837
        unsigned char  occ[256];
 
838
        uint           i;
 
839
        unsigned char *val= NULL;
 
840
 
 
841
        bzero(occ, sizeof(occ));
 
842
 
 
843
        for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++)
 
844
          for (uint j = 0; j < field->interval->type_lengths[i]; j++)
 
845
            occ[(unsigned int) (val[j])]= 1;
 
846
 
 
847
        if (!occ[(unsigned char)NAMES_SEP_CHAR])
 
848
          sep= (unsigned char) NAMES_SEP_CHAR;
 
849
        else if (!occ[(unsigned int)','])
 
850
          sep= ',';
 
851
        else
 
852
        {
 
853
          for (uint i=1; i<256; i++)
 
854
          {
 
855
            if(!occ[i])
 
856
            {
 
857
              sep= i;
 
858
              break;
 
859
            }
 
860
          }
 
861
 
 
862
          if(!sep)    /* disaster, enum uses all characters, none left as separator */
 
863
          {
 
864
            my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
 
865
                       MYF(0));
 
866
            DBUG_RETURN(1);
 
867
          }
 
868
        }
 
869
 
 
870
        int_count= field->interval_id;
 
871
        tmp.append(sep);
 
872
        for (const char **pos=field->interval->type_names ; *pos ; pos++)
 
873
        {
 
874
          tmp.append(*pos);
 
875
          tmp.append(sep);
 
876
        }
 
877
        tmp.append('\0');                      // End of intervall
 
878
      }
 
879
    }
 
880
    if (my_write(file,(uchar*) tmp.ptr(),tmp.length(),MYF_RW))
 
881
      DBUG_RETURN(1);
 
882
  }
 
883
  if (comment_length)
 
884
  {
 
885
    it.rewind();
 
886
    int_count=0;
 
887
    while ((field=it++))
 
888
    {
 
889
      if (field->comment.length)
 
890
        if (my_write(file, (uchar*) field->comment.str, field->comment.length,
 
891
                     MYF_RW))
 
892
          DBUG_RETURN(1);
 
893
    }
 
894
  }
 
895
  DBUG_RETURN(0);
 
896
}
 
897
 
 
898
 
 
899
        /* save an empty record on start of formfile */
 
900
 
 
901
static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
 
902
                           uint table_options,
 
903
                           List<Create_field> &create_fields,
 
904
                           uint reclength,
 
905
                           ulong data_offset,
 
906
                           handler *handler)
 
907
{
 
908
  int error= 0;
 
909
  Field::utype type;
 
910
  uint null_count;
 
911
  uchar *buff,*null_pos;
 
912
  TABLE table;
 
913
  TABLE_SHARE share;
 
914
  Create_field *field;
 
915
  enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
 
916
  DBUG_ENTER("make_empty_rec");
 
917
 
 
918
  /* We need a table to generate columns for default values */
 
919
  bzero((char*) &table, sizeof(table));
 
920
  bzero((char*) &share, sizeof(share));
 
921
  table.s= &share;
 
922
 
 
923
  if (!(buff=(uchar*) my_malloc((size_t) reclength,MYF(MY_WME | MY_ZEROFILL))))
 
924
  {
 
925
    DBUG_RETURN(1);
 
926
  }
 
927
 
 
928
  table.in_use= thd;
 
929
  table.s->db_low_byte_first= handler->low_byte_first();
 
930
  table.s->blob_ptr_size= portable_sizeof_char_ptr;
 
931
 
 
932
  null_count=0;
 
933
  if (!(table_options & HA_OPTION_PACK_RECORD))
 
934
  {
 
935
    null_count++;                       // Need one bit for delete mark
 
936
    *buff|= 1;
 
937
  }
 
938
  null_pos= buff;
 
939
 
 
940
  List_iterator<Create_field> it(create_fields);
 
941
  thd->count_cuted_fields= CHECK_FIELD_WARN;    // To find wrong default values
 
942
  while ((field=it++))
 
943
  {
 
944
    /*
 
945
      regfield don't have to be deleted as it's allocated with sql_alloc()
 
946
    */
 
947
    Field *regfield= make_field(&share,
 
948
                                buff+field->offset + data_offset,
 
949
                                field->length,
 
950
                                null_pos + null_count / 8,
 
951
                                null_count & 7,
 
952
                                field->pack_flag,
 
953
                                field->sql_type,
 
954
                                field->charset,
 
955
                                field->unireg_check,
 
956
                                field->save_interval ? field->save_interval :
 
957
                                field->interval, 
 
958
                                field->field_name);
 
959
    if (!regfield)
 
960
    {
 
961
      error= 1;
 
962
      goto err;                                 // End of memory
 
963
    }
 
964
 
 
965
    /* save_in_field() will access regfield->table->in_use */
 
966
    regfield->init(&table);
 
967
 
 
968
    if (!(field->flags & NOT_NULL_FLAG))
 
969
    {
 
970
      *regfield->null_ptr|= regfield->null_bit;
 
971
      null_count++;
 
972
    }
 
973
 
 
974
    if (field->sql_type == MYSQL_TYPE_BIT && !f_bit_as_char(field->pack_flag))
 
975
      null_count+= field->length & 7;
 
976
 
 
977
    type= (Field::utype) MTYP_TYPENR(field->unireg_check);
 
978
 
 
979
    if (field->def)
 
980
    {
 
981
      int res= field->def->save_in_field(regfield, 1);
 
982
      /* If not ok or warning of level 'note' */
 
983
      if (res != 0 && res != 3)
 
984
      {
 
985
        my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
 
986
        error= 1;
 
987
        delete regfield; //To avoid memory leak
 
988
        goto err;
 
989
      }
 
990
    }
 
991
    else if (regfield->real_type() == MYSQL_TYPE_ENUM &&
 
992
             (field->flags & NOT_NULL_FLAG))
 
993
    {
 
994
      regfield->set_notnull();
 
995
      regfield->store((longlong) 1, TRUE);
 
996
    }
 
997
    else if (type == Field::YES)                // Old unireg type
 
998
      regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES)),system_charset_info);
 
999
    else if (type == Field::NO)                 // Old unireg type
 
1000
      regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),system_charset_info);
 
1001
    else
 
1002
      regfield->reset();
 
1003
  }
 
1004
  DBUG_ASSERT(data_offset == ((null_count + 7) / 8));
 
1005
 
 
1006
  /*
 
1007
    We need to set the unused bits to 1. If the number of bits is a multiple
 
1008
    of 8 there are no unused bits.
 
1009
  */
 
1010
  if (null_count & 7)
 
1011
    *(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);
 
1012
 
 
1013
  error= my_write(file, buff, (size_t) reclength,MYF_RW) != 0;
 
1014
 
 
1015
err:
 
1016
  my_free(buff, MYF(MY_FAE));
 
1017
  thd->count_cuted_fields= old_count_cuted_fields;
 
1018
  DBUG_RETURN(error);
 
1019
} /* make_empty_rec */