1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2009 Sun Microsystems, Inc.
5
* Copyright (C) 2010 Jay Pipes
9
* Jay Pipes <jaypipes@gmail.com>
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; version 2 of the License.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
* Implementation of various routines that can be used to convert
29
* Statement messages to other formats, including SQL strings.
34
#include <boost/lexical_cast.hpp>
35
#include <drizzled/message/statement_transform.h>
36
#include <drizzled/message/transaction.pb.h>
37
#include <drizzled/message/table.pb.h>
38
#include <drizzled/charset.h>
39
#include <drizzled/charset_info.h>
40
#include <drizzled/global_charset_info.h>
55
static void escapeEmbeddedQuotes(string &s, const char quote='\'')
59
for (it= s.begin(); it != s.end(); ++it)
63
it= s.insert(it, quote);
64
++it; // advance back to the quote
69
/* Incredibly similar to append_unescaped() in table.cc, but for std::string */
70
static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
72
const char *pos= input.c_str();
73
const char *end= input.c_str()+input.length();
74
res->push_back(quote);
76
for (; pos != end ; pos++)
79
if (use_mb(default_charset_info) &&
80
(mblen= my_ismbchar(default_charset_info, pos, end)))
82
res->append(pos, mblen);
90
case 0: /* Must be escaped for 'mysql' */
94
case '\n': /* Must be escaped for logs */
99
res->push_back('\\'); /* This gives better readability */
103
res->push_back('\\'); /* Because of the sql syntax */
104
res->push_back('\\');
107
if (*pos == quote) /* SQL syntax for quoting a quote */
109
res->push_back(quote);
110
res->push_back(quote);
113
res->push_back(*pos);
117
res->push_back(quote);
120
enum TransformSqlError
121
transformStatementToSql(const Statement &source,
122
vector<string> &sql_strings,
123
enum TransformSqlVariant sql_variant,
124
bool already_in_transaction)
126
TransformSqlError error= NONE;
128
switch (source.type())
130
case Statement::ROLLBACK_STATEMENT:
134
case Statement::ROLLBACK:
136
sql_strings.push_back("ROLLBACK");
139
case Statement::INSERT:
141
if (! source.has_insert_header())
143
error= MISSING_HEADER;
146
if (! source.has_insert_data())
152
const InsertHeader &insert_header= source.insert_header();
153
const InsertData &insert_data= source.insert_data();
154
size_t num_keys= insert_data.record_size();
156
if (num_keys > 1 && ! already_in_transaction)
157
sql_strings.push_back("START TRANSACTION");
159
for (size_t x= 0; x < num_keys; ++x)
163
error= transformInsertRecordToSql(insert_header,
164
insert_data.record(x),
170
sql_strings.push_back(destination);
173
if (num_keys > 1 && ! already_in_transaction)
176
sql_strings.push_back("COMMIT");
178
sql_strings.push_back("ROLLBACK");
182
case Statement::UPDATE:
184
if (! source.has_update_header())
186
error= MISSING_HEADER;
189
if (! source.has_update_data())
195
const UpdateHeader &update_header= source.update_header();
196
const UpdateData &update_data= source.update_data();
197
size_t num_keys= update_data.record_size();
200
if (num_keys > 1 && ! already_in_transaction)
201
sql_strings.push_back("START TRANSACTION");
203
for (x= 0; x < num_keys; ++x)
207
error= transformUpdateRecordToSql(update_header,
208
update_data.record(x),
214
sql_strings.push_back(destination);
217
if (num_keys > 1 && ! already_in_transaction)
220
sql_strings.push_back("COMMIT");
222
sql_strings.push_back("ROLLBACK");
226
case Statement::DELETE:
228
if (! source.has_delete_header())
230
error= MISSING_HEADER;
233
if (! source.has_delete_data())
239
const DeleteHeader &delete_header= source.delete_header();
240
const DeleteData &delete_data= source.delete_data();
241
size_t num_keys= delete_data.record_size();
244
if (num_keys > 1 && ! already_in_transaction)
245
sql_strings.push_back("START TRANSACTION");
247
for (x= 0; x < num_keys; ++x)
251
error= transformDeleteRecordToSql(delete_header,
252
delete_data.record(x),
258
sql_strings.push_back(destination);
261
if (num_keys > 1 && ! already_in_transaction)
264
sql_strings.push_back("COMMIT");
266
sql_strings.push_back("ROLLBACK");
270
case Statement::CREATE_TABLE:
272
assert(source.has_create_table_statement());
274
error= transformCreateTableStatementToSql(source.create_table_statement(),
277
sql_strings.push_back(destination);
280
case Statement::TRUNCATE_TABLE:
282
assert(source.has_truncate_table_statement());
284
error= transformTruncateTableStatementToSql(source.truncate_table_statement(),
287
sql_strings.push_back(destination);
290
case Statement::DROP_TABLE:
292
assert(source.has_drop_table_statement());
294
error= transformDropTableStatementToSql(source.drop_table_statement(),
297
sql_strings.push_back(destination);
300
case Statement::CREATE_SCHEMA:
302
assert(source.has_create_schema_statement());
304
error= transformCreateSchemaStatementToSql(source.create_schema_statement(),
307
sql_strings.push_back(destination);
310
case Statement::DROP_SCHEMA:
312
assert(source.has_drop_schema_statement());
314
error= transformDropSchemaStatementToSql(source.drop_schema_statement(),
317
sql_strings.push_back(destination);
320
case Statement::ALTER_SCHEMA:
322
assert(source.has_alter_schema_statement());
324
error= transformAlterSchemaStatementToSql(source.alter_schema_statement(),
327
sql_strings.push_back(destination);
330
case Statement::SET_VARIABLE:
332
assert(source.has_set_variable_statement());
334
error= transformSetVariableStatementToSql(source.set_variable_statement(),
337
sql_strings.push_back(destination);
340
case Statement::RAW_SQL:
342
sql_strings.push_back(source.sql());
348
enum TransformSqlError
349
transformInsertHeaderToSql(const InsertHeader &header,
351
enum TransformSqlVariant sql_variant)
353
char quoted_identifier= '`';
354
if (sql_variant == ANSI)
355
quoted_identifier= '"';
357
destination.assign("INSERT INTO ", 12);
358
destination.push_back(quoted_identifier);
359
destination.append(header.table_metadata().schema_name());
360
destination.push_back(quoted_identifier);
361
destination.push_back('.');
362
destination.push_back(quoted_identifier);
363
destination.append(header.table_metadata().table_name());
364
destination.push_back(quoted_identifier);
365
destination.append(" (", 2);
367
/* Add field list to SQL string... */
368
size_t num_fields= header.field_metadata_size();
371
for (x= 0; x < num_fields; ++x)
373
const FieldMetadata &field_metadata= header.field_metadata(x);
375
destination.push_back(',');
377
destination.push_back(quoted_identifier);
378
destination.append(field_metadata.name());
379
destination.push_back(quoted_identifier);
385
enum TransformSqlError
386
transformInsertRecordToSql(const InsertHeader &header,
387
const InsertRecord &record,
389
enum TransformSqlVariant sql_variant)
391
enum TransformSqlError error= transformInsertHeaderToSql(header,
395
char quoted_identifier= '`';
396
if (sql_variant == ANSI)
397
quoted_identifier= '"';
399
destination.append(") VALUES (");
401
/* Add insert values */
402
size_t num_fields= header.field_metadata_size();
404
bool should_quote_field_value= false;
406
for (x= 0; x < num_fields; ++x)
409
destination.push_back(',');
411
const FieldMetadata &field_metadata= header.field_metadata(x);
413
if (record.is_null(x))
415
should_quote_field_value= false;
419
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
422
if (should_quote_field_value)
423
destination.push_back('\'');
425
if (record.is_null(x))
427
destination.append("NULL");
431
if (field_metadata.type() == Table::Field::BLOB)
434
* We do this here because BLOB data is returned
435
* in a string correctly, but calling append()
436
* without a length will result in only the string
437
* up to a \0 being output here.
439
string raw_data(record.insert_value(x));
440
destination.append(raw_data.c_str(), raw_data.size());
444
string tmp(record.insert_value(x));
445
escapeEmbeddedQuotes(tmp);
446
destination.append(tmp);
450
if (should_quote_field_value)
451
destination.push_back('\'');
453
destination.push_back(')');
458
enum TransformSqlError
459
transformInsertStatementToSql(const InsertHeader &header,
460
const InsertData &data,
462
enum TransformSqlVariant sql_variant)
464
enum TransformSqlError error= transformInsertHeaderToSql(header,
468
char quoted_identifier= '`';
469
if (sql_variant == ANSI)
470
quoted_identifier= '"';
472
destination.append(") VALUES (", 10);
474
/* Add insert values */
475
size_t num_records= data.record_size();
476
size_t num_fields= header.field_metadata_size();
478
bool should_quote_field_value= false;
480
for (x= 0; x < num_records; ++x)
483
destination.append("),(", 3);
485
for (y= 0; y < num_fields; ++y)
488
destination.push_back(',');
490
const FieldMetadata &field_metadata= header.field_metadata(y);
492
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
494
if (should_quote_field_value)
495
destination.push_back('\'');
497
if (field_metadata.type() == Table::Field::BLOB)
500
* We do this here because BLOB data is returned
501
* in a string correctly, but calling append()
502
* without a length will result in only the string
503
* up to a \0 being output here.
505
string raw_data(data.record(x).insert_value(y));
506
destination.append(raw_data.c_str(), raw_data.size());
510
string tmp(data.record(x).insert_value(y));
511
escapeEmbeddedQuotes(tmp);
512
destination.append(tmp);
515
if (should_quote_field_value)
516
destination.push_back('\'');
519
destination.push_back(')');
524
enum TransformSqlError
525
transformUpdateHeaderToSql(const UpdateHeader &header,
527
enum TransformSqlVariant sql_variant)
529
char quoted_identifier= '`';
530
if (sql_variant == ANSI)
531
quoted_identifier= '"';
533
destination.assign("UPDATE ", 7);
534
destination.push_back(quoted_identifier);
535
destination.append(header.table_metadata().schema_name());
536
destination.push_back(quoted_identifier);
537
destination.push_back('.');
538
destination.push_back(quoted_identifier);
539
destination.append(header.table_metadata().table_name());
540
destination.push_back(quoted_identifier);
541
destination.append(" SET ", 5);
546
enum TransformSqlError
547
transformUpdateRecordToSql(const UpdateHeader &header,
548
const UpdateRecord &record,
550
enum TransformSqlVariant sql_variant)
552
enum TransformSqlError error= transformUpdateHeaderToSql(header,
556
char quoted_identifier= '`';
557
if (sql_variant == ANSI)
558
quoted_identifier= '"';
560
/* Add field SET list to SQL string... */
561
size_t num_set_fields= header.set_field_metadata_size();
563
bool should_quote_field_value= false;
565
for (x= 0; x < num_set_fields; ++x)
567
const FieldMetadata &field_metadata= header.set_field_metadata(x);
569
destination.push_back(',');
571
destination.push_back(quoted_identifier);
572
destination.append(field_metadata.name());
573
destination.push_back(quoted_identifier);
574
destination.push_back('=');
576
if (record.is_null(x))
578
should_quote_field_value= false;
582
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
585
if (should_quote_field_value)
586
destination.push_back('\'');
588
if (record.is_null(x))
590
destination.append("NULL");
594
if (field_metadata.type() == Table::Field::BLOB)
597
* We do this here because BLOB data is returned
598
* in a string correctly, but calling append()
599
* without a length will result in only the string
600
* up to a \0 being output here.
602
string raw_data(record.after_value(x));
603
destination.append(raw_data.c_str(), raw_data.size());
607
string tmp(record.after_value(x));
608
escapeEmbeddedQuotes(tmp);
609
destination.append(tmp);
613
if (should_quote_field_value)
614
destination.push_back('\'');
617
size_t num_key_fields= header.key_field_metadata_size();
619
destination.append(" WHERE ", 7);
620
for (x= 0; x < num_key_fields; ++x)
622
const FieldMetadata &field_metadata= header.key_field_metadata(x);
625
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
627
destination.push_back(quoted_identifier);
628
destination.append(field_metadata.name());
629
destination.push_back(quoted_identifier);
631
destination.push_back('=');
633
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
635
if (should_quote_field_value)
636
destination.push_back('\'');
638
if (field_metadata.type() == Table::Field::BLOB)
641
* We do this here because BLOB data is returned
642
* in a string correctly, but calling append()
643
* without a length will result in only the string
644
* up to a \0 being output here.
646
string raw_data(record.key_value(x));
647
destination.append(raw_data.c_str(), raw_data.size());
651
destination.append(record.key_value(x));
654
if (should_quote_field_value)
655
destination.push_back('\'');
661
enum TransformSqlError
662
transformDeleteHeaderToSql(const DeleteHeader &header,
664
enum TransformSqlVariant sql_variant)
666
char quoted_identifier= '`';
667
if (sql_variant == ANSI)
668
quoted_identifier= '"';
670
destination.assign("DELETE FROM ", 12);
671
destination.push_back(quoted_identifier);
672
destination.append(header.table_metadata().schema_name());
673
destination.push_back(quoted_identifier);
674
destination.push_back('.');
675
destination.push_back(quoted_identifier);
676
destination.append(header.table_metadata().table_name());
677
destination.push_back(quoted_identifier);
682
enum TransformSqlError
683
transformDeleteRecordToSql(const DeleteHeader &header,
684
const DeleteRecord &record,
686
enum TransformSqlVariant sql_variant)
688
enum TransformSqlError error= transformDeleteHeaderToSql(header,
691
char quoted_identifier= '`';
692
if (sql_variant == ANSI)
693
quoted_identifier= '"';
695
/* Add WHERE clause to SQL string... */
696
uint32_t num_key_fields= header.key_field_metadata_size();
698
bool should_quote_field_value= false;
700
destination.append(" WHERE ", 7);
701
for (x= 0; x < num_key_fields; ++x)
703
const FieldMetadata &field_metadata= header.key_field_metadata(x);
706
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
708
destination.push_back(quoted_identifier);
709
destination.append(field_metadata.name());
710
destination.push_back(quoted_identifier);
712
destination.push_back('=');
714
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
716
if (should_quote_field_value)
717
destination.push_back('\'');
719
if (field_metadata.type() == Table::Field::BLOB)
722
* We do this here because BLOB data is returned
723
* in a string correctly, but calling append()
724
* without a length will result in only the string
725
* up to a \0 being output here.
727
string raw_data(record.key_value(x));
728
destination.append(raw_data.c_str(), raw_data.size());
732
string tmp(record.key_value(x));
733
escapeEmbeddedQuotes(tmp);
734
destination.append(tmp);
737
if (should_quote_field_value)
738
destination.push_back('\'');
744
enum TransformSqlError
745
transformDeleteStatementToSql(const DeleteHeader &header,
746
const DeleteData &data,
748
enum TransformSqlVariant sql_variant)
750
enum TransformSqlError error= transformDeleteHeaderToSql(header,
753
char quoted_identifier= '`';
754
if (sql_variant == ANSI)
755
quoted_identifier= '"';
757
/* Add WHERE clause to SQL string... */
758
uint32_t num_key_fields= header.key_field_metadata_size();
759
uint32_t num_key_records= data.record_size();
761
bool should_quote_field_value= false;
763
destination.append(" WHERE ", 7);
764
for (x= 0; x < num_key_records; ++x)
767
destination.append(" OR ", 4); /* Always OR condition for multiple key records */
769
if (num_key_fields > 1)
770
destination.push_back('(');
772
for (y= 0; y < num_key_fields; ++y)
774
const FieldMetadata &field_metadata= header.key_field_metadata(y);
777
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
779
destination.push_back(quoted_identifier);
780
destination.append(field_metadata.name());
781
destination.push_back(quoted_identifier);
783
destination.push_back('=');
785
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
787
if (should_quote_field_value)
788
destination.push_back('\'');
790
if (field_metadata.type() == Table::Field::BLOB)
793
* We do this here because BLOB data is returned
794
* in a string correctly, but calling append()
795
* without a length will result in only the string
796
* up to a \0 being output here.
798
string raw_data(data.record(x).key_value(y));
799
destination.append(raw_data.c_str(), raw_data.size());
803
string tmp(data.record(x).key_value(y));
804
escapeEmbeddedQuotes(tmp);
805
destination.append(tmp);
808
if (should_quote_field_value)
809
destination.push_back('\'');
811
if (num_key_fields > 1)
812
destination.push_back(')');
817
enum TransformSqlError
818
transformAlterSchemaStatementToSql(const AlterSchemaStatement &statement,
820
enum TransformSqlVariant sql_variant)
822
const Schema &before= statement.before();
823
const Schema &after= statement.after();
825
/* Make sure we are given the before and after for the same object */
826
if (before.uuid() != after.uuid())
827
return UUID_MISMATCH;
829
char quoted_identifier= '`';
830
if (sql_variant == ANSI)
831
quoted_identifier= '"';
833
destination.append("ALTER SCHEMA ");
834
destination.push_back(quoted_identifier);
835
destination.append(before.name());
836
destination.push_back(quoted_identifier);
839
* Diff our schemas. Currently, only collation can change so a
840
* diff of the two structures is not really necessary.
842
destination.append(" COLLATE = ");
843
destination.append(after.collation());
848
enum TransformSqlError
849
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
851
enum TransformSqlVariant sql_variant)
853
char quoted_identifier= '`';
854
if (sql_variant == ANSI)
855
quoted_identifier= '"';
857
destination.append("DROP SCHEMA ", 12);
858
destination.push_back(quoted_identifier);
859
destination.append(statement.schema_name());
860
destination.push_back(quoted_identifier);
865
enum TransformSqlError
866
transformCreateSchemaStatementToSql(const CreateSchemaStatement &statement,
868
enum TransformSqlVariant sql_variant)
870
char quoted_identifier= '`';
871
if (sql_variant == ANSI)
872
quoted_identifier= '"';
874
const Schema &schema= statement.schema();
876
destination.append("CREATE SCHEMA ");
877
destination.push_back(quoted_identifier);
878
destination.append(schema.name());
879
destination.push_back(quoted_identifier);
881
if (schema.has_collation())
883
destination.append(" COLLATE ");
884
destination.append(schema.collation());
887
if (schema.has_replication_options() and schema.replication_options().has_dont_replicate() and schema.replication_options().dont_replicate())
889
destination.append(" REPLICATION = FALSE");
895
enum TransformSqlError
896
transformDropTableStatementToSql(const DropTableStatement &statement,
898
enum TransformSqlVariant sql_variant)
900
char quoted_identifier= '`';
901
if (sql_variant == ANSI)
902
quoted_identifier= '"';
904
const TableMetadata &table_metadata= statement.table_metadata();
906
destination.append("DROP TABLE ");
908
/* Add the IF EXISTS clause if necessary */
909
if (statement.has_if_exists_clause() &&
910
statement.if_exists_clause() == true)
912
destination.append("IF EXISTS ");
915
destination.push_back(quoted_identifier);
916
destination.append(table_metadata.schema_name());
917
destination.push_back(quoted_identifier);
918
destination.push_back('.');
919
destination.push_back(quoted_identifier);
920
destination.append(table_metadata.table_name());
921
destination.push_back(quoted_identifier);
926
enum TransformSqlError
927
transformTruncateTableStatementToSql(const TruncateTableStatement &statement,
929
enum TransformSqlVariant sql_variant)
931
char quoted_identifier= '`';
932
if (sql_variant == ANSI)
933
quoted_identifier= '"';
935
const TableMetadata &table_metadata= statement.table_metadata();
937
destination.append("TRUNCATE TABLE ");
938
destination.push_back(quoted_identifier);
939
destination.append(table_metadata.schema_name());
940
destination.push_back(quoted_identifier);
941
destination.push_back('.');
942
destination.push_back(quoted_identifier);
943
destination.append(table_metadata.table_name());
944
destination.push_back(quoted_identifier);
949
enum TransformSqlError
950
transformSetVariableStatementToSql(const SetVariableStatement &statement,
952
enum TransformSqlVariant sql_variant)
955
const FieldMetadata &variable_metadata= statement.variable_metadata();
956
bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
958
destination.append("SET GLOBAL "); /* Only global variables are replicated */
959
destination.append(variable_metadata.name());
960
destination.push_back('=');
962
if (should_quote_field_value)
963
destination.push_back('\'');
965
destination.append(statement.variable_value());
967
if (should_quote_field_value)
968
destination.push_back('\'');
973
enum TransformSqlError
974
transformCreateTableStatementToSql(const CreateTableStatement &statement,
976
enum TransformSqlVariant sql_variant)
978
return transformTableDefinitionToSql(statement.table(), destination, sql_variant);
981
enum TransformSqlError
982
transformTableDefinitionToSql(const Table &table,
984
enum TransformSqlVariant sql_variant, bool with_schema)
986
char quoted_identifier= '`';
987
if (sql_variant == ANSI)
988
quoted_identifier= '"';
990
destination.append("CREATE ");
992
if (table.type() == Table::TEMPORARY)
993
destination.append("TEMPORARY ");
995
destination.append("TABLE ");
998
append_escaped_string(&destination, table.schema(), quoted_identifier);
999
destination.push_back('.');
1001
append_escaped_string(&destination, table.name(), quoted_identifier);
1002
destination.append(" (\n");
1004
enum TransformSqlError result= NONE;
1005
size_t num_fields= table.field_size();
1006
for (size_t x= 0; x < num_fields; ++x)
1008
const Table::Field &field= table.field(x);
1011
destination.append(",\n");
1013
destination.append(" ");
1015
result= transformFieldDefinitionToSql(field, destination, sql_variant);
1021
size_t num_indexes= table.indexes_size();
1023
if (num_indexes > 0)
1024
destination.append(",\n");
1026
for (size_t x= 0; x < num_indexes; ++x)
1028
const message::Table::Index &index= table.indexes(x);
1031
destination.append(",\n");
1033
result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
1039
size_t num_foreign_keys= table.fk_constraint_size();
1041
if (num_foreign_keys > 0)
1042
destination.append(",\n");
1044
for (size_t x= 0; x < num_foreign_keys; ++x)
1046
const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
1049
destination.append(",\n");
1051
result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1057
destination.append("\n)");
1059
/* Add ENGINE = " clause */
1060
if (table.has_engine())
1062
destination.append(" ENGINE=");
1063
destination.append(table.engine().name());
1065
size_t num_engine_options= table.engine().options_size();
1066
if (num_engine_options > 0)
1067
destination.append(" ", 1);
1068
for (size_t x= 0; x < num_engine_options; ++x)
1070
const Engine::Option &option= table.engine().options(x);
1071
destination.append(option.name());
1072
destination.append("='");
1073
destination.append(option.state());
1074
destination.append("'");
1075
if (x != num_engine_options-1)
1077
destination.append(", ");
1082
if (table.has_options())
1083
(void) transformTableOptionsToSql(table.options(), destination, sql_variant);
1088
enum TransformSqlError
1089
transformTableOptionsToSql(const Table::TableOptions &options,
1090
string &destination,
1091
enum TransformSqlVariant sql_variant)
1093
if (sql_variant == ANSI)
1094
return NONE; /* ANSI does not support table options... */
1096
if (options.has_comment())
1098
destination.append(" COMMENT=");
1099
append_escaped_string(&destination, options.comment());
1102
if (options.has_collation())
1104
destination.append(" COLLATE = ");
1105
destination.append(options.collation());
1108
if (options.has_data_file_name())
1110
destination.append("\nDATA_FILE_NAME = '");
1111
destination.append(options.data_file_name());
1112
destination.push_back('\'');
1115
if (options.has_index_file_name())
1117
destination.append("\nINDEX_FILE_NAME = '");
1118
destination.append(options.index_file_name());
1119
destination.push_back('\'');
1122
if (options.has_max_rows())
1124
destination.append("\nMAX_ROWS = ");
1125
destination.append(boost::lexical_cast<string>(options.max_rows()));
1128
if (options.has_min_rows())
1130
destination.append("\nMIN_ROWS = ");
1131
destination.append(boost::lexical_cast<string>(options.min_rows()));
1134
if (options.has_user_set_auto_increment_value()
1135
&& options.has_auto_increment_value())
1137
destination.append(" AUTO_INCREMENT=");
1138
destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
1141
if (options.has_avg_row_length())
1143
destination.append("\nAVG_ROW_LENGTH = ");
1144
destination.append(boost::lexical_cast<string>(options.avg_row_length()));
1147
if (options.has_checksum() && options.checksum())
1148
destination.append("\nCHECKSUM = TRUE");
1150
if (options.has_page_checksum() && options.page_checksum())
1151
destination.append("\nPAGE_CHECKSUM = TRUE");
1153
if (options.has_dont_replicate() and options.dont_replicate())
1155
destination.append(" REPLICATION = FALSE");
1161
enum TransformSqlError
1162
transformIndexDefinitionToSql(const Table::Index &index,
1164
string &destination,
1165
enum TransformSqlVariant sql_variant)
1167
char quoted_identifier= '`';
1168
if (sql_variant == ANSI)
1169
quoted_identifier= '"';
1171
destination.append(" ", 2);
1173
if (index.is_primary())
1174
destination.append("PRIMARY ");
1175
else if (index.is_unique())
1176
destination.append("UNIQUE ");
1178
destination.append("KEY ", 4);
1179
if (! (index.is_primary() && index.name().compare("PRIMARY")==0))
1181
destination.push_back(quoted_identifier);
1182
destination.append(index.name());
1183
destination.push_back(quoted_identifier);
1184
destination.append(" (", 2);
1187
destination.append("(", 1);
1189
size_t num_parts= index.index_part_size();
1190
for (size_t x= 0; x < num_parts; ++x)
1192
const Table::Index::IndexPart &part= index.index_part(x);
1193
const Table::Field &field= table.field(part.fieldnr());
1196
destination.push_back(',');
1198
destination.push_back(quoted_identifier);
1199
destination.append(field.name());
1200
destination.push_back(quoted_identifier);
1203
* If the index part's field type is VARCHAR or TEXT
1204
* then check for a prefix length then is different
1205
* from the field's full length...
1207
if (field.type() == Table::Field::VARCHAR ||
1208
field.type() == Table::Field::BLOB)
1210
if (part.has_compare_length())
1212
if (part.compare_length() != field.string_options().length())
1214
destination.push_back('(');
1215
destination.append(boost::lexical_cast<string>(part.compare_length()));
1216
destination.push_back(')');
1221
destination.push_back(')');
1223
switch (index.type())
1225
case Table::Index::UNKNOWN_INDEX:
1227
case Table::Index::BTREE:
1228
destination.append(" USING BTREE");
1230
case Table::Index::RTREE:
1231
destination.append(" USING RTREE");
1233
case Table::Index::HASH:
1234
destination.append(" USING HASH");
1236
case Table::Index::FULLTEXT:
1237
destination.append(" USING FULLTEXT");
1241
if (index.has_comment())
1243
destination.append(" COMMENT ");
1244
append_escaped_string(&destination, index.comment());
1250
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
1254
case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1255
destination.append("RESTRICT");
1257
case Table::ForeignKeyConstraint::OPTION_CASCADE:
1258
destination.append("CASCADE");
1260
case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1261
destination.append("SET NULL");
1263
case Table::ForeignKeyConstraint::OPTION_UNDEF:
1264
case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1265
destination.append("NO ACTION");
1267
case Table::ForeignKeyConstraint::OPTION_SET_DEFAULT:
1268
destination.append("SET DEFAULT");
1273
enum TransformSqlError
1274
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
1276
string &destination,
1277
enum TransformSqlVariant sql_variant)
1279
char quoted_identifier= '`';
1280
if (sql_variant == ANSI)
1281
quoted_identifier= '"';
1283
destination.append(" ");
1285
if (fkey.has_name())
1287
destination.append("CONSTRAINT ");
1288
append_escaped_string(&destination, fkey.name(), quoted_identifier);
1289
destination.append(" ", 1);
1292
destination.append("FOREIGN KEY (");
1294
for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1297
destination.append(", ");
1299
append_escaped_string(&destination, fkey.column_names(x),
1303
destination.append(") REFERENCES ");
1305
append_escaped_string(&destination, fkey.references_table_name(),
1307
destination.append(" (");
1309
for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1312
destination.append(", ");
1314
append_escaped_string(&destination, fkey.references_columns(x),
1318
destination.push_back(')');
1320
if (fkey.has_update_option() and fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1322
destination.append(" ON UPDATE ");
1323
transformForeignKeyOptionToSql(fkey.update_option(), destination);
1326
if (fkey.has_delete_option() and fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1328
destination.append(" ON DELETE ");
1329
transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1335
enum TransformSqlError
1336
transformFieldDefinitionToSql(const Table::Field &field,
1337
string &destination,
1338
enum TransformSqlVariant sql_variant)
1340
char quoted_identifier= '`';
1341
char quoted_default;
1343
if (sql_variant == ANSI)
1344
quoted_identifier= '"';
1346
if (sql_variant == DRIZZLE)
1347
quoted_default= '\'';
1349
quoted_default= quoted_identifier;
1351
append_escaped_string(&destination, field.name(), quoted_identifier);
1353
Table::Field::FieldType field_type= field.type();
1357
case Table::Field::DOUBLE:
1358
destination.append(" DOUBLE");
1359
if (field.has_numeric_options()
1360
&& field.numeric_options().has_precision())
1363
ss << "(" << field.numeric_options().precision() << ",";
1364
ss << field.numeric_options().scale() << ")";
1365
destination.append(ss.str());
1368
case Table::Field::VARCHAR:
1370
if (field.string_options().has_collation()
1371
&& field.string_options().collation().compare("binary") == 0)
1372
destination.append(" VARBINARY(");
1374
destination.append(" VARCHAR(");
1376
destination.append(boost::lexical_cast<string>(field.string_options().length()));
1377
destination.append(")");
1380
case Table::Field::BLOB:
1382
if (field.string_options().has_collation()
1383
&& field.string_options().collation().compare("binary") == 0)
1384
destination.append(" BLOB");
1386
destination.append(" TEXT");
1389
case Table::Field::ENUM:
1391
size_t num_field_values= field.enumeration_values().field_value_size();
1392
destination.append(" ENUM(");
1393
for (size_t x= 0; x < num_field_values; ++x)
1395
const string &type= field.enumeration_values().field_value(x);
1398
destination.push_back(',');
1400
destination.push_back('\'');
1401
destination.append(type);
1402
destination.push_back('\'');
1404
destination.push_back(')');
1407
case Table::Field::UUID:
1408
destination.append(" UUID");
1410
case Table::Field::BOOLEAN:
1411
destination.append(" BOOLEAN");
1413
case Table::Field::INTEGER:
1414
destination.append(" INT");
1416
case Table::Field::BIGINT:
1417
if (field.has_constraints() and
1418
field.constraints().is_unsigned())
1420
destination.append(" BIGINT UNSIGNED");
1424
destination.append(" BIGINT");
1427
case Table::Field::DECIMAL:
1429
destination.append(" DECIMAL(");
1431
ss << field.numeric_options().precision() << ",";
1432
ss << field.numeric_options().scale() << ")";
1433
destination.append(ss.str());
1436
case Table::Field::DATE:
1437
destination.append(" DATE");
1440
case Table::Field::EPOCH:
1441
if (field.time_options().microseconds())
1443
destination.append(" TIMESTAMP(6)");
1447
destination.append(" TIMESTAMP");
1451
case Table::Field::DATETIME:
1452
destination.append(" DATETIME");
1454
case Table::Field::TIME:
1455
destination.append(" TIME");
1459
if (field.type() == Table::Field::BLOB ||
1460
field.type() == Table::Field::VARCHAR)
1462
if (field.string_options().has_collation()
1463
&& field.string_options().collation().compare("binary"))
1465
destination.append(" COLLATE ");
1466
destination.append(field.string_options().collation());
1470
if (field.has_constraints() and field.constraints().is_unique())
1472
destination.append(" UNIQUE");
1475
if (field.has_constraints() && field.constraints().is_notnull())
1477
destination.append(" NOT NULL");
1479
else if (field.type() == Table::Field::EPOCH)
1481
destination.append(" NULL");
1484
if (field.type() == Table::Field::INTEGER ||
1485
field.type() == Table::Field::BIGINT)
1487
/* AUTO_INCREMENT must be after NOT NULL */
1488
if (field.has_numeric_options() &&
1489
field.numeric_options().is_autoincrement())
1491
destination.append(" AUTO_INCREMENT");
1495
if (field.options().has_default_value())
1497
destination.append(" DEFAULT ");
1498
append_escaped_string(&destination, field.options().default_value());
1500
else if (field.options().has_default_expression())
1502
destination.append(" DEFAULT ");
1503
destination.append(field.options().default_expression());
1505
else if (field.options().has_default_bin_value())
1507
const string &v= field.options().default_bin_value();
1508
if (v.length() == 0)
1510
destination.append(" DEFAULT ''");
1514
destination.append(" DEFAULT 0x");
1515
for (size_t x= 0; x < v.length(); x++)
1518
snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
1519
destination.append(hex, 2);
1523
else if (field.options().has_default_null()
1524
&& field.options().default_null()
1525
&& field.type() != Table::Field::BLOB)
1527
destination.append(" DEFAULT NULL");
1530
if (field.has_options() && field.options().has_update_expression())
1532
destination.append(" ON UPDATE ");
1533
destination.append(field.options().update_expression());
1536
if (field.has_comment())
1538
destination.append(" COMMENT ");
1539
append_escaped_string(&destination, field.comment(), quoted_default);
1544
bool shouldQuoteFieldValue(Table::Field::FieldType in_type)
1548
case Table::Field::DOUBLE:
1549
case Table::Field::DECIMAL:
1550
case Table::Field::INTEGER:
1551
case Table::Field::BIGINT:
1558
Table::Field::FieldType internalFieldTypeToFieldProtoType(enum enum_field_types type)
1561
case DRIZZLE_TYPE_LONG:
1562
return Table::Field::INTEGER;
1563
case DRIZZLE_TYPE_DOUBLE:
1564
return Table::Field::DOUBLE;
1565
case DRIZZLE_TYPE_NULL:
1566
assert(false); /* Not a user definable type */
1567
return Table::Field::INTEGER; /* unreachable */
1568
case DRIZZLE_TYPE_MICROTIME:
1569
case DRIZZLE_TYPE_TIMESTAMP:
1570
return Table::Field::EPOCH;
1571
case DRIZZLE_TYPE_LONGLONG:
1572
return Table::Field::BIGINT;
1573
case DRIZZLE_TYPE_DATETIME:
1574
return Table::Field::DATETIME;
1575
case DRIZZLE_TYPE_TIME:
1576
return Table::Field::TIME;
1577
case DRIZZLE_TYPE_DATE:
1578
return Table::Field::DATE;
1579
case DRIZZLE_TYPE_VARCHAR:
1580
return Table::Field::VARCHAR;
1581
case DRIZZLE_TYPE_DECIMAL:
1582
return Table::Field::DECIMAL;
1583
case DRIZZLE_TYPE_ENUM:
1584
return Table::Field::ENUM;
1585
case DRIZZLE_TYPE_BLOB:
1586
return Table::Field::BLOB;
1587
case DRIZZLE_TYPE_UUID:
1588
return Table::Field::UUID;
1589
case DRIZZLE_TYPE_BOOLEAN:
1590
return Table::Field::BOOLEAN;
1594
return Table::Field::INTEGER; /* unreachable */
1597
bool transactionContainsBulkSegment(const Transaction &transaction)
1599
size_t num_statements= transaction.statement_size();
1600
if (num_statements == 0)
1604
* Only INSERT, UPDATE, and DELETE statements can possibly
1605
* have bulk segments. So, we loop through the statements
1606
* checking for segment_id > 1 in those specific submessages.
1609
for (x= 0; x < num_statements; ++x)
1611
const Statement &statement= transaction.statement(x);
1612
Statement::Type type= statement.type();
1616
case Statement::INSERT:
1617
if (statement.insert_data().segment_id() > 1)
1620
case Statement::UPDATE:
1621
if (statement.update_data().segment_id() > 1)
1624
case Statement::DELETE:
1625
if (statement.delete_data().segment_id() > 1)
1635
} /* namespace message */
1636
} /* namespace drizzled */