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 */
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"
24
#include "drizzled/internal/my_sys.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>
37
#include <drizzled/table_proto.h>
38
#include <drizzled/charset.h>
40
#include "drizzled/function/time/typecast.h"
46
static int fill_table_proto(message::Table &table_proto,
47
List<CreateField> &create_fields,
48
HA_CREATE_INFO *create_info,
52
CreateField *field_arg;
53
List_iterator<CreateField> it(create_fields);
54
message::Table::TableOptions *table_options= table_proto.mutable_options();
56
if (create_fields.elements > MAX_FIELDS)
58
my_error(ER_TOO_MANY_FIELDS, MYF(0), ER(ER_TOO_MANY_FIELDS));
62
assert(strcmp(table_proto.engine().name().c_str(),
63
create_info->db_type->getName().c_str())==0);
66
bool use_existing_fields= table_proto.field_size() > 0;
67
while ((field_arg= it++))
69
message::Table::Field *attribute;
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 */
75
if (use_existing_fields)
76
attribute= table_proto.mutable_field(field_number++);
79
/* Other code paths still have to fill out the proto */
80
attribute= table_proto.add_field();
82
if (field_arg->flags & NOT_NULL_FLAG)
84
message::Table::Field::FieldConstraints *constraints;
86
constraints= attribute->mutable_constraints();
87
constraints->set_is_nullable(false);
90
attribute->set_name(field_arg->field_name);
93
assert((!(field_arg->flags & NOT_NULL_FLAG)) == attribute->constraints().is_nullable());
94
assert(strcmp(attribute->name().c_str(), field_arg->field_name)==0);
97
message::Table::Field::FieldType parser_type= attribute->type();
99
if (field_arg->sql_type == DRIZZLE_TYPE_NULL)
101
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), table_proto.name().c_str(), -1);
105
attribute->set_type(message::internalFieldTypeToFieldProtoType(field_arg->sql_type));
107
switch (attribute->type()) {
108
default: /* Only deal with types that need extra information */
110
case message::Table::Field::DOUBLE:
113
* For DOUBLE, we only add a specific scale and precision iff
114
* the fixed decimal point has been specified...
116
if (field_arg->decimals != NOT_FIXED_DEC)
118
message::Table::Field::NumericFieldOptions *numeric_field_options;
120
numeric_field_options= attribute->mutable_numeric_options();
122
numeric_field_options->set_precision(field_arg->length);
123
numeric_field_options->set_scale(field_arg->decimals);
127
case message::Table::Field::VARCHAR:
129
message::Table::Field::StringFieldOptions *string_field_options;
131
string_field_options= attribute->mutable_string_options();
133
if (! use_existing_fields || string_field_options->length()==0)
134
string_field_options->set_length(field_arg->length
135
/ field_arg->charset->mbmaxlen);
137
assert((uint32_t)string_field_options->length() == (uint32_t)(field_arg->length / field_arg->charset->mbmaxlen));
139
if (! string_field_options->has_collation())
141
string_field_options->set_collation_id(field_arg->charset->number);
142
string_field_options->set_collation(field_arg->charset->name);
146
case message::Table::Field::DECIMAL:
148
message::Table::Field::NumericFieldOptions *numeric_field_options;
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);
156
case message::Table::Field::ENUM:
158
message::Table::Field::EnumerationValues *enumeration_options;
160
assert(field_arg->interval);
162
enumeration_options= attribute->mutable_enumeration_values();
164
for (uint32_t pos= 0; pos < field_arg->interval->count; pos++)
166
const char *src= field_arg->interval->type_names[pos];
168
enumeration_options->add_field_value(src);
170
enumeration_options->set_collation_id(field_arg->charset->number);
171
enumeration_options->set_collation(field_arg->charset->name);
174
case message::Table::Field::BLOB:
176
message::Table::Field::StringFieldOptions *string_field_options;
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);
186
assert (!use_existing_fields || parser_type == attribute->type());
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 */
18
Functions to create a unireg form-file from a FIELD and a fieldname-fieldinfo
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.
26
#include <drizzled/server_includes.h>
27
#include <drizzled/drizzled_error_messages.h>
29
#define FCOMP 17 /* Bytes for a packed field */
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,
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,
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,
50
An interceptor to hijack ER_TOO_MANY_FIELDS error from
51
pack_screens and retry again without UNIREG screens.
53
XXX: what is a UNIREG screen?
56
struct Pack_header_error_handler: public Internal_error_handler
58
virtual bool handle_error(uint32_t sql_errno,
60
DRIZZLE_ERROR::enum_warning_level level,
63
Pack_header_error_handler() :is_handled(false) {}
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 */)
74
is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
79
Create a frm (table definition) file
83
session Thread handler
84
file_name Path for file (including database and .frm)
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
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,
105
LEX_STRING str_db_type;
106
uint32_t reclength, info_length, screens, key_info_length, maxlength, tmp_len;
107
ulong key_buff_length;
109
ulong filepos, data_offset;
110
unsigned char fileinfo[64],forminfo[288],*keybuff;
112
unsigned char *screen_buff;
114
const uint32_t format_section_header_size= 8;
115
uint32_t format_section_len;
116
Pack_header_error_handler pack_header_error_handler;
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)))
123
assert(db_file != NULL);
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;
130
session->push_internal_handler(&pack_header_error_handler);
132
error= pack_header(forminfo,
133
create_fields,info_length,
134
screens, create_info->table_options,
135
data_offset, db_file);
137
session->pop_internal_handler();
142
if (! pack_header_error_handler.is_handled)
145
// Try again without UNIREG screens (to get more columns)
146
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
148
if (pack_header(forminfo,
149
create_fields,info_length,
150
screens, create_info->table_options, data_offset, db_file))
156
reclength=uint2korr(forminfo+266);
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);
162
create_info->extra_size= (2 + str_db_type.length +
163
2 + create_info->connect_string.length);
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
171
create_info->extra_size+= 6;
173
/* Add space for storage type and field format array of fields */
175
format_section_header_size + 1 + create_fields.elements;
176
create_info->extra_size+= format_section_len;
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);
184
if (tmp_len < create_info->comment.length)
186
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
187
create_info->comment.str,"Table COMMENT",
188
(uint) TABLE_COMMENT_MAXLEN);
193
//if table comment is larger than 180 bytes, store into extra segment.
194
if (create_info->comment.length > 180)
197
create_info->extra_size+= 2 + create_info->comment.length;
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;
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.
209
memset(forminfo+47 + forminfo[46], 0, 61 - forminfo[46]);
193
if (field_arg->comment.length)
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);
202
if (tmp_len < field_arg->comment.length)
204
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
205
field_arg->comment.str,"COLUMN COMMENT",
206
(uint32_t) COLUMN_COMMENT_MAXLEN);
210
if (! use_existing_fields)
211
attribute->set_comment(field_arg->comment.str);
213
assert(strcmp(attribute->comment().c_str(), field_arg->comment.str)==0);
216
if (field_arg->unireg_check == Field::NEXT_NUMBER)
218
message::Table::Field::NumericFieldOptions *field_options;
219
field_options= attribute->mutable_numeric_options();
220
field_options->set_is_autoincrement(true);
223
if (field_arg->unireg_check == Field::TIMESTAMP_DN_FIELD
224
|| field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
226
message::Table::Field::FieldOptions *field_options;
227
field_options= attribute->mutable_options();
228
field_options->set_default_expression("CURRENT_TIMESTAMP");
231
if (field_arg->unireg_check == Field::TIMESTAMP_UN_FIELD
232
|| field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
234
message::Table::Field::FieldOptions *field_options;
235
field_options= attribute->mutable_options();
236
field_options->set_update_expression("CURRENT_TIMESTAMP");
239
if (field_arg->def == NULL && attribute->constraints().is_nullable())
241
message::Table::Field::FieldOptions *field_options;
242
field_options= attribute->mutable_options();
244
field_options->set_default_null(true);
248
message::Table::Field::FieldOptions *field_options;
249
field_options= attribute->mutable_options();
251
if (field_arg->def->is_null())
253
field_options->set_default_null(true);
258
String *default_value= field_arg->def->val_str(&d);
260
assert(default_value);
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()))
267
my_error(ER_INVALID_DEFAULT, MYF(0), field_arg->field_name);
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)
277
if (field_arg->def->get_date(<ime, TIME_FUZZY_DATE))
279
my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR),
280
default_value->c_str());
284
/* We now do the casting down to the appropriate type.
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.
291
the timestamp errors are taken care of elsewhere.
294
if (field_arg->sql_type == DRIZZLE_TYPE_DATETIME)
296
Item *typecast= new Item_datetime_typecast(field_arg->def);
297
typecast->quick_fix_field();
298
typecast->val_str(default_value);
300
else if (field_arg->sql_type == DRIZZLE_TYPE_DATE)
302
Item *typecast= new Item_date_typecast(field_arg->def);
303
typecast->quick_fix_field();
304
typecast->val_str(default_value);
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))
314
bin_default.assign(default_value->c_ptr(),
315
default_value->length());
316
field_options->set_default_bin_value(bin_default);
320
field_options->set_default_value(default_value->c_ptr());
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);
333
assert(! use_existing_fields || (field_number == table_proto.field_size()));
335
if (create_info->table_options & HA_OPTION_PACK_RECORD)
336
table_options->set_pack_record(true);
338
if (table_options->has_comment() && table_options->comment().length() == 0)
339
table_options->clear_comment();
341
if (table_options->has_comment())
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);
350
if (tmp_len < table_options->comment().length())
352
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
353
table_options->comment().c_str(),"Table COMMENT",
354
(uint32_t) TABLE_COMMENT_MAXLEN);
359
if (create_info->default_table_charset)
361
table_options->set_collation_id(
362
create_info->default_table_charset->number);
363
table_options->set_collation(create_info->default_table_charset->name);
366
if (create_info->used_fields & HA_CREATE_USED_AUTO)
367
table_options->set_has_user_set_auto_increment_value(true);
369
table_options->set_has_user_set_auto_increment_value(false);
371
if (create_info->auto_increment_value)
372
table_options->set_auto_increment_value(create_info->auto_increment_value);
374
for (uint32_t i= 0; i < keys; i++)
376
message::Table::Index *idx;
378
idx= table_proto.add_indexes();
380
assert(test(key_info[i].flags & HA_USES_COMMENT) ==
381
(key_info[i].comment.length > 0));
383
idx->set_name(key_info[i].name);
385
idx->set_key_length(key_info[i].key_length);
387
if (is_primary_key_name(key_info[i].name))
388
idx->set_is_primary(true);
390
idx->set_is_primary(false);
392
switch(key_info[i].algorithm)
394
case HA_KEY_ALG_HASH:
395
idx->set_type(message::Table::Index::HASH);
398
case HA_KEY_ALG_BTREE:
399
idx->set_type(message::Table::Index::BTREE);
402
case HA_KEY_ALG_UNDEF:
403
idx->set_type(message::Table::Index::UNKNOWN_INDEX);
407
abort(); /* Somebody's brain broke. haven't added index type to proto */
410
if (key_info[i].flags & HA_NOSAME)
411
idx->set_is_unique(true);
413
idx->set_is_unique(false);
415
message::Table::Index::Options *index_options= idx->mutable_options();
417
if (key_info[i].flags & HA_USES_BLOCK_SIZE)
418
index_options->set_key_block_size(key_info[i].block_size);
420
if (key_info[i].flags & HA_PACK_KEY)
421
index_options->set_pack_key(true);
423
if (key_info[i].flags & HA_BINARY_PACK_KEY)
424
index_options->set_binary_pack_key(true);
426
if (key_info[i].flags & HA_VAR_LENGTH_PART)
427
index_options->set_var_length_key(true);
429
if (key_info[i].flags & HA_NULL_PART_KEY)
430
index_options->set_null_part_key(true);
432
if (key_info[i].flags & HA_KEY_HAS_PART_KEY_SEG)
433
index_options->set_has_partial_segments(true);
435
if (key_info[i].flags & HA_GENERATED_KEY)
436
index_options->set_auto_generated_key(true);
438
if (key_info[i].flags & HA_USES_COMMENT)
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);
447
if (tmp_len < key_info[i].comment.length)
449
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
450
key_info[i].comment.str,"Index COMMENT",
451
(uint32_t) TABLE_COMMENT_MAXLEN);
455
idx->set_comment(key_info[i].comment.str);
457
static const uint64_t unknown_index_flag= (HA_NOSAME | HA_PACK_KEY |
462
HA_KEY_HAS_PART_KEY_SEG |
465
if (key_info[i].flags & ~unknown_index_flag)
466
abort(); // Invalid (unknown) index flag.
468
for(unsigned int j=0; j< key_info[i].key_parts; j++)
470
message::Table::Index::IndexPart *idxpart;
471
const int fieldnr= key_info[i].key_part[j].fieldnr;
474
idxpart= idx->add_index_part();
476
idxpart->set_fieldnr(fieldnr);
478
if (table_proto.field(fieldnr).type() == message::Table::Field::VARCHAR
479
|| table_proto.field(fieldnr).type() == message::Table::Field::BLOB)
481
uint32_t collation_id;
483
if (table_proto.field(fieldnr).string_options().has_collation_id())
484
collation_id= table_proto.field(fieldnr).string_options().collation_id();
486
collation_id= table_proto.options().collation_id();
488
const CHARSET_INFO *cs= get_charset(collation_id);
490
mbmaxlen= cs->mbmaxlen;
493
idxpart->set_compare_length(key_info[i].key_part[j].length / mbmaxlen);
497
if (not table_proto.IsInitialized())
499
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), table_proto.InitializationErrorString().c_str());
504
Here we test to see if we can validate the Table Message before we continue.
505
We do this by serializing the protobuffer.
511
table_proto.SerializeToString(&tmp_string);
516
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
517
table_proto.InitializationErrorString().empty() ? "": table_proto.InitializationErrorString().c_str());
213
if ((file=create_frm(session, file_name, db, table, reclength, fileinfo,
214
create_info, keys, key_info)) < 0)
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,"")))
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);
234
int2store(fileinfo+59,db_file->extra_rec_buf_length());
236
if (pwrite(file, fileinfo, 64, 0L) == 0 ||
237
pwrite(file, keybuff, key_info_length, (ulong) uint2korr(fileinfo+6)) == 0)
240
(ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
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))
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)))
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)))
261
if (my_write(file, (unsigned char*) buff, 6, MYF_RW))
265
if (forminfo[46] == (unsigned char)255)
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)))
275
/* Store storage type and field format array of fields */
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 */
289
if (my_write(file, (const unsigned char*)buff, format_section_header_size, MYF_RW))
292
if (my_write(file, (const unsigned char*)buff, 1, MYF_RW))
294
/* write column info, 1 byte per column */
296
List_iterator<Create_field> it(create_fields);
298
unsigned char column_format, write_byte;
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))
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))
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))))
322
if (my_close(file,MYF(MY_WME)))
327
Restore all UCS2 intervals.
328
HEX representation of them is not needed anymore.
330
List_iterator<Create_field> it(create_fields);
334
if (field->save_interval)
336
field->interval= field->save_interval;
337
field->save_interval= 0;
347
my_close(file,MYF(MY_WME));
349
my_delete(file_name,MYF(0));
351
} /* mysql_create_frm */
527
Create a table definition proto file and the tables
355
Create a frm (table definition) file and the tables
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
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)
552
assert(table_proto.has_name());
553
if (fill_table_proto(table_proto, create_fields, create_info,
557
assert(table_proto.name() == identifier.getTableName());
559
if (plugin::StorageEngine::createTable(*session,
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))
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))
395
if (!create_info->frm_only && ha_create_table(session, path, db, table_name,
401
file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
402
my_delete(frm_name, MYF(0));
568
404
} /* rea_create_table */
570
} /* namespace drizzled */
407
/* Pack screens to a screen for save in a form-file */
409
static unsigned char *pack_screens(List<Create_field> &create_fields,
410
uint32_t *info_length, uint32_t *screens,
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);
421
start_row=4; end_row=22; cols=80; fields_on_screen=end_row+1-start_row;
423
*screens=(fields-1)/fields_on_screen+1;
424
length= (*screens) * (SC_INFO_LENGTH+ (cols>> 1)+4);
428
length+=(uint) strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
430
if (!(info=(unsigned char*) my_malloc(length,MYF(MY_WME))))
437
for (i=0 ; i < fields ; i++)
439
Create_field *cfield=it++;
440
if (row++ == end_row)
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);
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),' ');
458
length=(uint) strlen(cfield->field_name);
464
pos[0]=(unsigned char) row;
466
pos[2]=(unsigned char) (length+1);
467
pos=(unsigned char*) strmake((char*) pos+3,cfield->field_name,length)+1;
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));
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);
478
*info_length=(uint) (pos-info);
483
/* Pack keyinfo and keynames to keybuff for save in form-file. */
485
static uint32_t pack_keys(unsigned char *keybuff, uint32_t key_count, KEY *keyinfo,
488
uint32_t key_parts,length;
489
unsigned char *pos, *keyname_pos;
491
KEY_PART_INFO *key_part,*key_part_end;
496
for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
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);
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 ;
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);
522
*pos++=(unsigned char) NAMES_SEP_CHAR;
523
for (key=keyinfo ; key != end ; key++)
525
unsigned char *tmp=(unsigned char*) my_stpcpy((char*) pos,key->name);
526
*tmp++= (unsigned char) NAMES_SEP_CHAR;
532
for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
534
if (key->flags & HA_USES_COMMENT)
536
int2store(pos, key->comment.length);
537
unsigned char *tmp= (unsigned char*)my_stpncpy((char*) pos+2,key->comment.str,key->comment.length);
542
if (key_count > 127 || key_parts > 127)
544
keybuff[0]= (key_count & 0x7f) | 0x80;
545
keybuff[1]= key_count >> 7;
546
int2store(keybuff+2,key_parts);
550
keybuff[0]=(unsigned char) key_count;
551
keybuff[1]=(unsigned char) key_parts;
552
keybuff[2]= keybuff[3]= 0;
554
length=(uint) (pos-keyname_pos);
555
int2store(keybuff+4,length);
556
return((uint) (pos-keybuff));
560
/* Make formheader */
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)
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;
572
if (create_fields.elements > MAX_FIELDS)
574
my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
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;
586
List_iterator<Create_field> it(create_fields);
590
uint32_t tmp_len= system_charset_info->cset->charpos(system_charset_info,
593
field->comment.length,
594
COLUMN_COMMENT_MAXLEN);
596
if (tmp_len < field->comment.length)
598
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
599
field->comment.str,"COLUMN COMMENT",
600
(uint) COLUMN_COMMENT_MAXLEN);
603
if (field->vcol_info)
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);
611
if (tmp_len < field->vcol_info->expr_str.length)
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);
619
Sum up the length of the expression string and mandatory header bytes
622
vcol_info_length+= field->vcol_info->expr_str.length+(uint)FRM_VCOL_HEADER_SIZE;
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)
630
field->unireg_check= (Field::utype) ((uint) field->unireg_check |
635
We mark first TIMESTAMP field with NOW() in DEFAULT or ON UPDATE
636
as auto-update field.
638
if (field->sql_type == DRIZZLE_TYPE_TIMESTAMP &&
639
MTYP_TYPENR(field->unireg_check) != Field::NONE &&
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;
650
uint32_t old_int_count=int_count;
652
if (field->charset->mbminlen > 1)
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.
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);
672
for (uint32_t pos= 0; pos < field->interval->count; pos++)
675
const char *src= field->save_interval->type_names[pos];
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 +
682
octet2hex(dst, src, length);
686
field->interval_id=get_interval_id(&int_count,create_fields,field);
687
if (old_int_count != int_count)
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;
694
if (f_maybe_null(field->pack_flag))
697
int_length+=int_count*2; // 255 prefix + 0 suffix
699
/* Save values in forminfo */
701
if (reclength > (ulong) file->max_record_length())
703
my_error(ER_TOO_BIG_ROWSIZE, MYF(0), (uint) file->max_record_length());
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 ||
712
my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
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 */
741
/* get each unique interval each own id */
743
static uint32_t get_interval_id(uint32_t *int_count,List<Create_field> &create_fields,
744
Create_field *last_field)
746
List_iterator<Create_field> it(create_fields);
748
TYPELIB *interval=last_field->interval;
750
while ((field=it++) != last_field)
752
if (field->interval_id && field->interval->count == interval->count)
755
for (a=field->interval->type_names, b=interval->type_names ;
756
*a && !strcmp(*a,*b);
761
return field->interval_id; // Re-use last interval
765
return ++*int_count; // New unique interval
769
/* Save fields, fieldnames and intervals */
771
static bool pack_fields(File file, List<Create_field> &create_fields,
775
uint32_t int_count, comment_length=0, vcol_info_length=0;
776
unsigned char buff[MAX_FIELD_WIDTH];
780
/* Write field info */
782
List_iterator<Create_field> it(create_fields);
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;
801
buff[14]= (unsigned char) field->charset->number;
803
buff[14]= 0; // Numerical
804
if (field->vcol_info)
807
Use the interval_id place in the .frm file to store the length of
808
virtual field's data.
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;
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))
822
/* Write fieldnames */
823
buff[0]=(unsigned char) NAMES_SEP_CHAR;
824
if (my_write(file, buff, 1, MYF_RW))
830
char *pos= my_stpcpy((char*) buff,field->field_name);
831
*pos++=NAMES_SEP_CHAR;
832
if (i == create_fields.elements-1)
834
if (my_write(file, buff, (size_t) (pos-(char*) buff),MYF_RW))
839
/* Write intervals */
842
String tmp((char*) buff,sizeof(buff), &my_charset_bin);
848
if (field->interval_id > int_count)
850
unsigned char sep= 0;
851
unsigned char occ[256];
853
unsigned char *val= NULL;
855
memset(occ, 0, sizeof(occ));
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;
861
if (!occ[(unsigned char)NAMES_SEP_CHAR])
862
sep= (unsigned char) NAMES_SEP_CHAR;
863
else if (!occ[(unsigned int)','])
867
for (uint32_t i=1; i<256; i++)
876
if(!sep) /* disaster, enum uses all characters, none left as separator */
878
my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
884
int_count= field->interval_id;
886
for (const char **pos=field->interval->type_names ; *pos ; pos++)
891
tmp.append('\0'); // End of intervall
894
if (my_write(file,(unsigned char*) tmp.ptr(),tmp.length(),MYF_RW))
903
if (field->comment.length)
904
if (my_write(file, (unsigned char*) field->comment.str, field->comment.length,
909
if (vcol_info_length)
916
Pack each virtual field as follows:
917
byte 1 = 1 (always 1 to allow for future extensions)
919
byte 3 = flags (as of now, 0 - no flags, 1 - field is physically stored)
920
byte 4-... = virtual column expression (text data)
922
if (field->vcol_info && field->vcol_info->expr_str.length)
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))
930
(unsigned char*) field->vcol_info->expr_str.str,
931
field->vcol_info->expr_str.length,
941
/* save an empty record on start of formfile */
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,
954
unsigned char *buff,*null_pos;
958
enum_check_fields old_count_cuted_fields= session->count_cuted_fields;
961
/* We need a table to generate columns for default values */
962
memset(&table, 0, sizeof(table));
963
memset(&share, 0, sizeof(share));
966
if (!(buff=(unsigned char*) my_malloc((size_t) reclength,MYF(MY_WME | MY_ZEROFILL))))
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;
976
if (!(table_options & HA_OPTION_PACK_RECORD))
978
null_count++; // Need one bit for delete mark
983
List_iterator<Create_field> it(create_fields);
984
session->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values
988
regfield don't have to be deleted as it's allocated with sql_alloc()
990
Field *regfield= make_field(&share,
991
buff+field->offset + data_offset,
993
null_pos + null_count / 8,
999
field->save_interval ? field->save_interval :
1005
goto err; // End of memory
1008
/* save_in_field() will access regfield->table->in_use */
1009
regfield->init(&table);
1011
if (!(field->flags & NOT_NULL_FLAG))
1013
*regfield->null_ptr|= regfield->null_bit;
1017
type= (Field::utype) MTYP_TYPENR(field->unireg_check);
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)
1025
my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
1027
delete regfield; //To avoid memory leak
1031
else if (regfield->real_type() == DRIZZLE_TYPE_ENUM &&
1032
(field->flags & NOT_NULL_FLAG))
1034
regfield->set_notnull();
1035
regfield->store((int64_t) 1, true);
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);
1044
assert(data_offset == ((null_count + 7) / 8));
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.
1051
*(null_pos + null_count / 8)|= ~(((unsigned char) 1 << (null_count & 7)) - 1);
1053
error= my_write(file, buff, (size_t) reclength,MYF_RW) != 0;
1057
session->count_cuted_fields= old_count_cuted_fields;
1059
} /* make_empty_rec */