1
/* Copyright (C) 2000-2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
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)
77
attribute= table_proto.mutable_field(field_number++);
81
/* Other code paths still have to fill out the proto */
82
attribute= table_proto.add_field();
84
if (field_arg->flags & NOT_NULL_FLAG)
86
attribute->mutable_constraints()->set_is_nullable(false);
90
attribute->mutable_constraints()->set_is_nullable(true);
93
if (field_arg->flags & UNSIGNED_FLAG and
94
(field_arg->sql_type == DRIZZLE_TYPE_LONGLONG or field_arg->sql_type == DRIZZLE_TYPE_LONG))
96
field_arg->sql_type= DRIZZLE_TYPE_LONGLONG;
97
attribute->mutable_constraints()->set_is_unsigned(true);
100
attribute->set_name(field_arg->field_name);
103
assert((!(field_arg->flags & NOT_NULL_FLAG)) == attribute->constraints().is_nullable());
104
assert(strcmp(attribute->name().c_str(), field_arg->field_name)==0);
107
message::Table::Field::FieldType parser_type= attribute->type();
109
if (field_arg->sql_type == DRIZZLE_TYPE_NULL)
111
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), table_proto.name().c_str(), -1);
115
if (field_arg->flags & UNSIGNED_FLAG and
116
(field_arg->sql_type == DRIZZLE_TYPE_LONGLONG or field_arg->sql_type == DRIZZLE_TYPE_LONG))
118
message::Table::Field::FieldConstraints *constraints= attribute->mutable_constraints();
120
field_arg->sql_type= DRIZZLE_TYPE_LONGLONG;
121
constraints->set_is_unsigned(true);
123
if (field_arg->flags & NOT_NULL_FLAG)
125
constraints->set_is_nullable(false);
129
constraints->set_is_nullable(true);
133
attribute->set_type(message::internalFieldTypeToFieldProtoType(field_arg->sql_type));
135
switch (attribute->type()) {
136
default: /* Only deal with types that need extra information */
138
case message::Table::Field::DOUBLE:
141
* For DOUBLE, we only add a specific scale and precision iff
142
* the fixed decimal point has been specified...
144
if (field_arg->decimals != NOT_FIXED_DEC)
146
message::Table::Field::NumericFieldOptions *numeric_field_options;
148
numeric_field_options= attribute->mutable_numeric_options();
150
numeric_field_options->set_precision(field_arg->length);
151
numeric_field_options->set_scale(field_arg->decimals);
155
case message::Table::Field::VARCHAR:
157
message::Table::Field::StringFieldOptions *string_field_options;
159
string_field_options= attribute->mutable_string_options();
161
if (! use_existing_fields || string_field_options->length()==0)
162
string_field_options->set_length(field_arg->length
163
/ field_arg->charset->mbmaxlen);
165
assert((uint32_t)string_field_options->length() == (uint32_t)(field_arg->length / field_arg->charset->mbmaxlen));
167
if (! string_field_options->has_collation())
169
string_field_options->set_collation_id(field_arg->charset->number);
170
string_field_options->set_collation(field_arg->charset->name);
174
case message::Table::Field::DECIMAL:
176
message::Table::Field::NumericFieldOptions *numeric_field_options;
178
numeric_field_options= attribute->mutable_numeric_options();
179
/* This is magic, I hate magic numbers -Brian */
180
numeric_field_options->set_precision(field_arg->length + ( field_arg->decimals ? -2 : -1));
181
numeric_field_options->set_scale(field_arg->decimals);
184
case message::Table::Field::ENUM:
186
message::Table::Field::EnumerationValues *enumeration_options;
188
assert(field_arg->interval);
190
enumeration_options= attribute->mutable_enumeration_values();
192
for (uint32_t pos= 0; pos < field_arg->interval->count; pos++)
194
const char *src= field_arg->interval->type_names[pos];
196
enumeration_options->add_field_value(src);
198
enumeration_options->set_collation_id(field_arg->charset->number);
199
enumeration_options->set_collation(field_arg->charset->name);
202
case message::Table::Field::BLOB:
204
message::Table::Field::StringFieldOptions *string_field_options;
206
string_field_options= attribute->mutable_string_options();
207
string_field_options->set_collation_id(field_arg->charset->number);
208
string_field_options->set_collation(field_arg->charset->name);
214
assert (!use_existing_fields || parser_type == attribute->type());
217
field_constraints= attribute->mutable_constraints();
218
constraints->set_is_nullable(field_arg->def->null_value);
221
if (field_arg->comment.length)
224
tmp_len= system_charset_info->cset->charpos(system_charset_info,
225
field_arg->comment.str,
226
field_arg->comment.str +
227
field_arg->comment.length,
228
COLUMN_COMMENT_MAXLEN);
230
if (tmp_len < field_arg->comment.length)
232
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
233
field_arg->comment.str,"COLUMN COMMENT",
234
(uint32_t) COLUMN_COMMENT_MAXLEN);
238
if (! use_existing_fields)
239
attribute->set_comment(field_arg->comment.str);
241
assert(strcmp(attribute->comment().c_str(), field_arg->comment.str)==0);
244
if (field_arg->unireg_check == Field::NEXT_NUMBER)
246
message::Table::Field::NumericFieldOptions *field_options;
247
field_options= attribute->mutable_numeric_options();
248
field_options->set_is_autoincrement(true);
251
if (field_arg->unireg_check == Field::TIMESTAMP_DN_FIELD
252
|| field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
254
message::Table::Field::FieldOptions *field_options;
255
field_options= attribute->mutable_options();
256
field_options->set_default_expression("CURRENT_TIMESTAMP");
259
if (field_arg->unireg_check == Field::TIMESTAMP_UN_FIELD
260
|| field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
262
message::Table::Field::FieldOptions *field_options;
263
field_options= attribute->mutable_options();
264
field_options->set_update_expression("CURRENT_TIMESTAMP");
267
if (field_arg->def == NULL && attribute->constraints().is_nullable())
269
message::Table::Field::FieldOptions *field_options;
270
field_options= attribute->mutable_options();
272
field_options->set_default_null(true);
276
message::Table::Field::FieldOptions *field_options;
277
field_options= attribute->mutable_options();
279
if (field_arg->def->is_null())
281
field_options->set_default_null(true);
286
String *default_value= field_arg->def->val_str(&d);
288
assert(default_value);
290
if ((field_arg->sql_type==DRIZZLE_TYPE_VARCHAR
291
|| field_arg->sql_type==DRIZZLE_TYPE_BLOB)
292
&& ((field_arg->length / field_arg->charset->mbmaxlen)
293
< default_value->length()))
295
my_error(ER_INVALID_DEFAULT, MYF(0), field_arg->field_name);
299
if (field_arg->sql_type == DRIZZLE_TYPE_DATE
300
|| field_arg->sql_type == DRIZZLE_TYPE_DATETIME
301
|| field_arg->sql_type == DRIZZLE_TYPE_TIMESTAMP)
305
if (field_arg->def->get_date(<ime, TIME_FUZZY_DATE))
307
my_error(ER_INVALID_DATETIME_VALUE, MYF(ME_FATALERROR),
308
default_value->c_str());
312
/* We now do the casting down to the appropriate type.
314
Yes, this implicit casting is balls.
315
It was previously done on reading the proto back in,
316
but we really shouldn't store the bogus things in the proto,
317
and instead do the casting behaviour here.
319
the timestamp errors are taken care of elsewhere.
322
if (field_arg->sql_type == DRIZZLE_TYPE_DATETIME)
324
Item *typecast= new Item_datetime_typecast(field_arg->def);
325
typecast->quick_fix_field();
326
typecast->val_str(default_value);
328
else if (field_arg->sql_type == DRIZZLE_TYPE_DATE)
330
Item *typecast= new Item_date_typecast(field_arg->def);
331
typecast->quick_fix_field();
332
typecast->val_str(default_value);
336
if ((field_arg->sql_type==DRIZZLE_TYPE_VARCHAR
337
&& field_arg->charset==&my_charset_bin)
338
|| (field_arg->sql_type==DRIZZLE_TYPE_BLOB
339
&& field_arg->charset==&my_charset_bin))
342
bin_default.assign(default_value->c_ptr(),
343
default_value->length());
344
field_options->set_default_bin_value(bin_default);
348
field_options->set_default_value(default_value->c_ptr());
353
assert(field_arg->unireg_check == Field::NONE
354
|| field_arg->unireg_check == Field::NEXT_NUMBER
355
|| field_arg->unireg_check == Field::TIMESTAMP_DN_FIELD
356
|| field_arg->unireg_check == Field::TIMESTAMP_UN_FIELD
357
|| field_arg->unireg_check == Field::TIMESTAMP_DNUN_FIELD);
361
assert(! use_existing_fields || (field_number == table_proto.field_size()));
363
if (create_info->table_options & HA_OPTION_PACK_RECORD)
364
table_options->set_pack_record(true);
366
if (table_options->has_comment() && table_options->comment().length() == 0)
367
table_options->clear_comment();
369
if (table_options->has_comment())
372
tmp_len= system_charset_info->cset->charpos(system_charset_info,
373
table_options->comment().c_str(),
374
table_options->comment().c_str() +
375
table_options->comment().length(),
376
TABLE_COMMENT_MAXLEN);
378
if (tmp_len < table_options->comment().length())
380
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
381
table_options->comment().c_str(),"Table COMMENT",
382
(uint32_t) TABLE_COMMENT_MAXLEN);
387
if (create_info->default_table_charset)
389
table_options->set_collation_id(
390
create_info->default_table_charset->number);
391
table_options->set_collation(create_info->default_table_charset->name);
394
if (create_info->used_fields & HA_CREATE_USED_AUTO)
395
table_options->set_has_user_set_auto_increment_value(true);
397
table_options->set_has_user_set_auto_increment_value(false);
399
if (create_info->auto_increment_value)
400
table_options->set_auto_increment_value(create_info->auto_increment_value);
402
for (uint32_t i= 0; i < keys; i++)
404
message::Table::Index *idx;
406
idx= table_proto.add_indexes();
408
assert(test(key_info[i].flags & HA_USES_COMMENT) ==
409
(key_info[i].comment.length > 0));
411
idx->set_name(key_info[i].name);
413
idx->set_key_length(key_info[i].key_length);
415
if (is_primary_key_name(key_info[i].name))
416
idx->set_is_primary(true);
418
idx->set_is_primary(false);
420
switch(key_info[i].algorithm)
422
case HA_KEY_ALG_HASH:
423
idx->set_type(message::Table::Index::HASH);
426
case HA_KEY_ALG_BTREE:
427
idx->set_type(message::Table::Index::BTREE);
430
case HA_KEY_ALG_UNDEF:
431
idx->set_type(message::Table::Index::UNKNOWN_INDEX);
435
abort(); /* Somebody's brain broke. haven't added index type to proto */
438
if (key_info[i].flags & HA_NOSAME)
439
idx->set_is_unique(true);
441
idx->set_is_unique(false);
443
message::Table::Index::Options *index_options= idx->mutable_options();
445
if (key_info[i].flags & HA_USES_BLOCK_SIZE)
446
index_options->set_key_block_size(key_info[i].block_size);
448
if (key_info[i].flags & HA_PACK_KEY)
449
index_options->set_pack_key(true);
451
if (key_info[i].flags & HA_BINARY_PACK_KEY)
452
index_options->set_binary_pack_key(true);
454
if (key_info[i].flags & HA_VAR_LENGTH_PART)
455
index_options->set_var_length_key(true);
457
if (key_info[i].flags & HA_NULL_PART_KEY)
458
index_options->set_null_part_key(true);
460
if (key_info[i].flags & HA_KEY_HAS_PART_KEY_SEG)
461
index_options->set_has_partial_segments(true);
463
if (key_info[i].flags & HA_GENERATED_KEY)
464
index_options->set_auto_generated_key(true);
466
if (key_info[i].flags & HA_USES_COMMENT)
469
tmp_len= system_charset_info->cset->charpos(system_charset_info,
470
key_info[i].comment.str,
471
key_info[i].comment.str +
472
key_info[i].comment.length,
473
TABLE_COMMENT_MAXLEN);
475
if (tmp_len < key_info[i].comment.length)
477
my_error(ER_WRONG_STRING_LENGTH, MYF(0),
478
key_info[i].comment.str,"Index COMMENT",
479
(uint32_t) TABLE_COMMENT_MAXLEN);
483
idx->set_comment(key_info[i].comment.str);
485
static const uint64_t unknown_index_flag= (HA_NOSAME | HA_PACK_KEY |
490
HA_KEY_HAS_PART_KEY_SEG |
493
if (key_info[i].flags & ~unknown_index_flag)
494
abort(); // Invalid (unknown) index flag.
496
for(unsigned int j=0; j< key_info[i].key_parts; j++)
498
message::Table::Index::IndexPart *idxpart;
499
const int fieldnr= key_info[i].key_part[j].fieldnr;
502
idxpart= idx->add_index_part();
504
idxpart->set_fieldnr(fieldnr);
506
if (table_proto.field(fieldnr).type() == message::Table::Field::VARCHAR
507
|| table_proto.field(fieldnr).type() == message::Table::Field::BLOB)
509
uint32_t collation_id;
511
if (table_proto.field(fieldnr).string_options().has_collation_id())
512
collation_id= table_proto.field(fieldnr).string_options().collation_id();
514
collation_id= table_proto.options().collation_id();
516
const CHARSET_INFO *cs= get_charset(collation_id);
518
mbmaxlen= cs->mbmaxlen;
521
idxpart->set_compare_length(key_info[i].key_part[j].length / mbmaxlen);
525
if (not table_proto.IsInitialized())
527
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), table_proto.InitializationErrorString().c_str());
532
Here we test to see if we can validate the Table Message before we continue.
533
We do this by serializing the protobuffer.
539
table_proto.SerializeToString(&tmp_string);
544
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
545
table_proto.InitializationErrorString().empty() ? "": table_proto.InitializationErrorString().c_str());
555
Create a table definition proto file and the tables
559
session Thread handler
560
path Name of file (including database, without .frm)
562
table_name Table name
563
create_info create info parameters
564
create_fields Fields to create
565
keys number of keys to create
566
key_info Keys to create
573
bool rea_create_table(Session *session,
574
const TableIdentifier &identifier,
575
message::Table &table_proto,
576
HA_CREATE_INFO *create_info,
577
List<CreateField> &create_fields,
578
uint32_t keys, KeyInfo *key_info)
580
assert(table_proto.has_name());
581
if (fill_table_proto(table_proto, create_fields, create_info,
585
assert(table_proto.name() == identifier.getTableName());
587
if (plugin::StorageEngine::createTable(*session,
596
} /* rea_create_table */
598
} /* namespace drizzled */