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();
157
if (num_keys > 1 && ! already_in_transaction)
158
sql_strings.push_back("START TRANSACTION");
160
for (x= 0; x < num_keys; ++x)
164
error= transformInsertRecordToSql(insert_header,
165
insert_data.record(x),
171
sql_strings.push_back(destination);
174
if (num_keys > 1 && ! already_in_transaction)
177
sql_strings.push_back("COMMIT");
179
sql_strings.push_back("ROLLBACK");
183
case Statement::UPDATE:
185
if (! source.has_update_header())
187
error= MISSING_HEADER;
190
if (! source.has_update_data())
196
const UpdateHeader &update_header= source.update_header();
197
const UpdateData &update_data= source.update_data();
198
size_t num_keys= update_data.record_size();
201
if (num_keys > 1 && ! already_in_transaction)
202
sql_strings.push_back("START TRANSACTION");
204
for (x= 0; x < num_keys; ++x)
208
error= transformUpdateRecordToSql(update_header,
209
update_data.record(x),
215
sql_strings.push_back(destination);
218
if (num_keys > 1 && ! already_in_transaction)
221
sql_strings.push_back("COMMIT");
223
sql_strings.push_back("ROLLBACK");
227
case Statement::DELETE:
229
if (! source.has_delete_header())
231
error= MISSING_HEADER;
234
if (! source.has_delete_data())
240
const DeleteHeader &delete_header= source.delete_header();
241
const DeleteData &delete_data= source.delete_data();
242
size_t num_keys= delete_data.record_size();
245
if (num_keys > 1 && ! already_in_transaction)
246
sql_strings.push_back("START TRANSACTION");
248
for (x= 0; x < num_keys; ++x)
252
error= transformDeleteRecordToSql(delete_header,
253
delete_data.record(x),
259
sql_strings.push_back(destination);
262
if (num_keys > 1 && ! already_in_transaction)
265
sql_strings.push_back("COMMIT");
267
sql_strings.push_back("ROLLBACK");
271
case Statement::CREATE_TABLE:
273
assert(source.has_create_table_statement());
275
error= transformCreateTableStatementToSql(source.create_table_statement(),
278
sql_strings.push_back(destination);
281
case Statement::TRUNCATE_TABLE:
283
assert(source.has_truncate_table_statement());
285
error= transformTruncateTableStatementToSql(source.truncate_table_statement(),
288
sql_strings.push_back(destination);
291
case Statement::DROP_TABLE:
293
assert(source.has_drop_table_statement());
295
error= transformDropTableStatementToSql(source.drop_table_statement(),
298
sql_strings.push_back(destination);
301
case Statement::CREATE_SCHEMA:
303
assert(source.has_create_schema_statement());
305
error= transformCreateSchemaStatementToSql(source.create_schema_statement(),
308
sql_strings.push_back(destination);
311
case Statement::DROP_SCHEMA:
313
assert(source.has_drop_schema_statement());
315
error= transformDropSchemaStatementToSql(source.drop_schema_statement(),
318
sql_strings.push_back(destination);
321
case Statement::ALTER_SCHEMA:
323
assert(source.has_alter_schema_statement());
325
error= transformAlterSchemaStatementToSql(source.alter_schema_statement(),
328
sql_strings.push_back(destination);
331
case Statement::SET_VARIABLE:
333
assert(source.has_set_variable_statement());
335
error= transformSetVariableStatementToSql(source.set_variable_statement(),
338
sql_strings.push_back(destination);
341
case Statement::RAW_SQL:
343
sql_strings.push_back(source.sql());
349
enum TransformSqlError
350
transformInsertHeaderToSql(const InsertHeader &header,
352
enum TransformSqlVariant sql_variant)
354
char quoted_identifier= '`';
355
if (sql_variant == ANSI)
356
quoted_identifier= '"';
358
destination.assign("INSERT INTO ", 12);
359
destination.push_back(quoted_identifier);
360
destination.append(header.table_metadata().schema_name());
361
destination.push_back(quoted_identifier);
362
destination.push_back('.');
363
destination.push_back(quoted_identifier);
364
destination.append(header.table_metadata().table_name());
365
destination.push_back(quoted_identifier);
366
destination.append(" (", 2);
368
/* Add field list to SQL string... */
369
size_t num_fields= header.field_metadata_size();
372
for (x= 0; x < num_fields; ++x)
374
const FieldMetadata &field_metadata= header.field_metadata(x);
376
destination.push_back(',');
378
destination.push_back(quoted_identifier);
379
destination.append(field_metadata.name());
380
destination.push_back(quoted_identifier);
386
enum TransformSqlError
387
transformInsertRecordToSql(const InsertHeader &header,
388
const InsertRecord &record,
390
enum TransformSqlVariant sql_variant)
392
enum TransformSqlError error= transformInsertHeaderToSql(header,
396
char quoted_identifier= '`';
397
if (sql_variant == ANSI)
398
quoted_identifier= '"';
400
destination.append(") VALUES (");
402
/* Add insert values */
403
size_t num_fields= header.field_metadata_size();
405
bool should_quote_field_value= false;
407
for (x= 0; x < num_fields; ++x)
410
destination.push_back(',');
412
const FieldMetadata &field_metadata= header.field_metadata(x);
414
if (record.is_null(x))
416
should_quote_field_value= false;
420
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
423
if (should_quote_field_value)
424
destination.push_back('\'');
426
if (record.is_null(x))
428
destination.append("NULL");
432
if (field_metadata.type() == Table::Field::BLOB)
435
* We do this here because BLOB data is returned
436
* in a string correctly, but calling append()
437
* without a length will result in only the string
438
* up to a \0 being output here.
440
string raw_data(record.insert_value(x));
441
destination.append(raw_data.c_str(), raw_data.size());
445
string tmp(record.insert_value(x));
446
escapeEmbeddedQuotes(tmp);
447
destination.append(tmp);
451
if (should_quote_field_value)
452
destination.push_back('\'');
454
destination.push_back(')');
459
enum TransformSqlError
460
transformInsertStatementToSql(const InsertHeader &header,
461
const InsertData &data,
463
enum TransformSqlVariant sql_variant)
465
enum TransformSqlError error= transformInsertHeaderToSql(header,
469
char quoted_identifier= '`';
470
if (sql_variant == ANSI)
471
quoted_identifier= '"';
473
destination.append(") VALUES (", 10);
475
/* Add insert values */
476
size_t num_records= data.record_size();
477
size_t num_fields= header.field_metadata_size();
479
bool should_quote_field_value= false;
481
for (x= 0; x < num_records; ++x)
484
destination.append("),(", 3);
486
for (y= 0; y < num_fields; ++y)
489
destination.push_back(',');
491
const FieldMetadata &field_metadata= header.field_metadata(y);
493
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
495
if (should_quote_field_value)
496
destination.push_back('\'');
498
if (field_metadata.type() == Table::Field::BLOB)
501
* We do this here because BLOB data is returned
502
* in a string correctly, but calling append()
503
* without a length will result in only the string
504
* up to a \0 being output here.
506
string raw_data(data.record(x).insert_value(y));
507
destination.append(raw_data.c_str(), raw_data.size());
511
string tmp(data.record(x).insert_value(y));
512
escapeEmbeddedQuotes(tmp);
513
destination.append(tmp);
516
if (should_quote_field_value)
517
destination.push_back('\'');
520
destination.push_back(')');
525
enum TransformSqlError
526
transformUpdateHeaderToSql(const UpdateHeader &header,
528
enum TransformSqlVariant sql_variant)
530
char quoted_identifier= '`';
531
if (sql_variant == ANSI)
532
quoted_identifier= '"';
534
destination.assign("UPDATE ", 7);
535
destination.push_back(quoted_identifier);
536
destination.append(header.table_metadata().schema_name());
537
destination.push_back(quoted_identifier);
538
destination.push_back('.');
539
destination.push_back(quoted_identifier);
540
destination.append(header.table_metadata().table_name());
541
destination.push_back(quoted_identifier);
542
destination.append(" SET ", 5);
547
enum TransformSqlError
548
transformUpdateRecordToSql(const UpdateHeader &header,
549
const UpdateRecord &record,
551
enum TransformSqlVariant sql_variant)
553
enum TransformSqlError error= transformUpdateHeaderToSql(header,
557
char quoted_identifier= '`';
558
if (sql_variant == ANSI)
559
quoted_identifier= '"';
561
/* Add field SET list to SQL string... */
562
size_t num_set_fields= header.set_field_metadata_size();
564
bool should_quote_field_value= false;
566
for (x= 0; x < num_set_fields; ++x)
568
const FieldMetadata &field_metadata= header.set_field_metadata(x);
570
destination.push_back(',');
572
destination.push_back(quoted_identifier);
573
destination.append(field_metadata.name());
574
destination.push_back(quoted_identifier);
575
destination.push_back('=');
577
if (record.is_null(x))
579
should_quote_field_value= false;
583
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
586
if (should_quote_field_value)
587
destination.push_back('\'');
589
if (record.is_null(x))
591
destination.append("NULL");
595
if (field_metadata.type() == Table::Field::BLOB)
598
* We do this here because BLOB data is returned
599
* in a string correctly, but calling append()
600
* without a length will result in only the string
601
* up to a \0 being output here.
603
string raw_data(record.after_value(x));
604
destination.append(raw_data.c_str(), raw_data.size());
608
string tmp(record.after_value(x));
609
escapeEmbeddedQuotes(tmp);
610
destination.append(tmp);
614
if (should_quote_field_value)
615
destination.push_back('\'');
618
size_t num_key_fields= header.key_field_metadata_size();
620
destination.append(" WHERE ", 7);
621
for (x= 0; x < num_key_fields; ++x)
623
const FieldMetadata &field_metadata= header.key_field_metadata(x);
626
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
628
destination.push_back(quoted_identifier);
629
destination.append(field_metadata.name());
630
destination.push_back(quoted_identifier);
632
destination.push_back('=');
634
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
636
if (should_quote_field_value)
637
destination.push_back('\'');
639
if (field_metadata.type() == Table::Field::BLOB)
642
* We do this here because BLOB data is returned
643
* in a string correctly, but calling append()
644
* without a length will result in only the string
645
* up to a \0 being output here.
647
string raw_data(record.key_value(x));
648
destination.append(raw_data.c_str(), raw_data.size());
652
destination.append(record.key_value(x));
655
if (should_quote_field_value)
656
destination.push_back('\'');
662
enum TransformSqlError
663
transformDeleteHeaderToSql(const DeleteHeader &header,
665
enum TransformSqlVariant sql_variant)
667
char quoted_identifier= '`';
668
if (sql_variant == ANSI)
669
quoted_identifier= '"';
671
destination.assign("DELETE FROM ", 12);
672
destination.push_back(quoted_identifier);
673
destination.append(header.table_metadata().schema_name());
674
destination.push_back(quoted_identifier);
675
destination.push_back('.');
676
destination.push_back(quoted_identifier);
677
destination.append(header.table_metadata().table_name());
678
destination.push_back(quoted_identifier);
683
enum TransformSqlError
684
transformDeleteRecordToSql(const DeleteHeader &header,
685
const DeleteRecord &record,
687
enum TransformSqlVariant sql_variant)
689
enum TransformSqlError error= transformDeleteHeaderToSql(header,
692
char quoted_identifier= '`';
693
if (sql_variant == ANSI)
694
quoted_identifier= '"';
696
/* Add WHERE clause to SQL string... */
697
uint32_t num_key_fields= header.key_field_metadata_size();
699
bool should_quote_field_value= false;
701
destination.append(" WHERE ", 7);
702
for (x= 0; x < num_key_fields; ++x)
704
const FieldMetadata &field_metadata= header.key_field_metadata(x);
707
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
709
destination.push_back(quoted_identifier);
710
destination.append(field_metadata.name());
711
destination.push_back(quoted_identifier);
713
destination.push_back('=');
715
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
717
if (should_quote_field_value)
718
destination.push_back('\'');
720
if (field_metadata.type() == Table::Field::BLOB)
723
* We do this here because BLOB data is returned
724
* in a string correctly, but calling append()
725
* without a length will result in only the string
726
* up to a \0 being output here.
728
string raw_data(record.key_value(x));
729
destination.append(raw_data.c_str(), raw_data.size());
733
string tmp(record.key_value(x));
734
escapeEmbeddedQuotes(tmp);
735
destination.append(tmp);
738
if (should_quote_field_value)
739
destination.push_back('\'');
745
enum TransformSqlError
746
transformDeleteStatementToSql(const DeleteHeader &header,
747
const DeleteData &data,
749
enum TransformSqlVariant sql_variant)
751
enum TransformSqlError error= transformDeleteHeaderToSql(header,
754
char quoted_identifier= '`';
755
if (sql_variant == ANSI)
756
quoted_identifier= '"';
758
/* Add WHERE clause to SQL string... */
759
uint32_t num_key_fields= header.key_field_metadata_size();
760
uint32_t num_key_records= data.record_size();
762
bool should_quote_field_value= false;
764
destination.append(" WHERE ", 7);
765
for (x= 0; x < num_key_records; ++x)
768
destination.append(" OR ", 4); /* Always OR condition for multiple key records */
770
if (num_key_fields > 1)
771
destination.push_back('(');
773
for (y= 0; y < num_key_fields; ++y)
775
const FieldMetadata &field_metadata= header.key_field_metadata(y);
778
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
780
destination.push_back(quoted_identifier);
781
destination.append(field_metadata.name());
782
destination.push_back(quoted_identifier);
784
destination.push_back('=');
786
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
788
if (should_quote_field_value)
789
destination.push_back('\'');
791
if (field_metadata.type() == Table::Field::BLOB)
794
* We do this here because BLOB data is returned
795
* in a string correctly, but calling append()
796
* without a length will result in only the string
797
* up to a \0 being output here.
799
string raw_data(data.record(x).key_value(y));
800
destination.append(raw_data.c_str(), raw_data.size());
804
string tmp(data.record(x).key_value(y));
805
escapeEmbeddedQuotes(tmp);
806
destination.append(tmp);
809
if (should_quote_field_value)
810
destination.push_back('\'');
812
if (num_key_fields > 1)
813
destination.push_back(')');
818
enum TransformSqlError
819
transformAlterSchemaStatementToSql(const AlterSchemaStatement &statement,
821
enum TransformSqlVariant sql_variant)
823
const Schema &before= statement.before();
824
const Schema &after= statement.after();
826
/* Make sure we are given the before and after for the same object */
827
if (before.uuid() != after.uuid())
828
return UUID_MISMATCH;
830
char quoted_identifier= '`';
831
if (sql_variant == ANSI)
832
quoted_identifier= '"';
834
destination.append("ALTER SCHEMA ");
835
destination.push_back(quoted_identifier);
836
destination.append(before.name());
837
destination.push_back(quoted_identifier);
840
* Diff our schemas. Currently, only collation can change so a
841
* diff of the two structures is not really necessary.
843
destination.append(" COLLATE = ");
844
destination.append(after.collation());
849
enum TransformSqlError
850
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
852
enum TransformSqlVariant sql_variant)
854
char quoted_identifier= '`';
855
if (sql_variant == ANSI)
856
quoted_identifier= '"';
858
destination.append("DROP SCHEMA ", 12);
859
destination.push_back(quoted_identifier);
860
destination.append(statement.schema_name());
861
destination.push_back(quoted_identifier);
866
enum TransformSqlError
867
transformCreateSchemaStatementToSql(const CreateSchemaStatement &statement,
869
enum TransformSqlVariant sql_variant)
871
char quoted_identifier= '`';
872
if (sql_variant == ANSI)
873
quoted_identifier= '"';
875
const Schema &schema= statement.schema();
877
destination.append("CREATE SCHEMA ");
878
destination.push_back(quoted_identifier);
879
destination.append(schema.name());
880
destination.push_back(quoted_identifier);
882
if (schema.has_collation())
884
destination.append(" COLLATE ");
885
destination.append(schema.collation());
891
enum TransformSqlError
892
transformDropTableStatementToSql(const DropTableStatement &statement,
894
enum TransformSqlVariant sql_variant)
896
char quoted_identifier= '`';
897
if (sql_variant == ANSI)
898
quoted_identifier= '"';
900
const TableMetadata &table_metadata= statement.table_metadata();
902
destination.append("DROP TABLE ");
904
/* Add the IF EXISTS clause if necessary */
905
if (statement.has_if_exists_clause() &&
906
statement.if_exists_clause() == true)
908
destination.append("IF EXISTS ");
911
destination.push_back(quoted_identifier);
912
destination.append(table_metadata.schema_name());
913
destination.push_back(quoted_identifier);
914
destination.push_back('.');
915
destination.push_back(quoted_identifier);
916
destination.append(table_metadata.table_name());
917
destination.push_back(quoted_identifier);
922
enum TransformSqlError
923
transformTruncateTableStatementToSql(const TruncateTableStatement &statement,
925
enum TransformSqlVariant sql_variant)
927
char quoted_identifier= '`';
928
if (sql_variant == ANSI)
929
quoted_identifier= '"';
931
const TableMetadata &table_metadata= statement.table_metadata();
933
destination.append("TRUNCATE TABLE ");
934
destination.push_back(quoted_identifier);
935
destination.append(table_metadata.schema_name());
936
destination.push_back(quoted_identifier);
937
destination.push_back('.');
938
destination.push_back(quoted_identifier);
939
destination.append(table_metadata.table_name());
940
destination.push_back(quoted_identifier);
945
enum TransformSqlError
946
transformSetVariableStatementToSql(const SetVariableStatement &statement,
948
enum TransformSqlVariant sql_variant)
951
const FieldMetadata &variable_metadata= statement.variable_metadata();
952
bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
954
destination.append("SET GLOBAL "); /* Only global variables are replicated */
955
destination.append(variable_metadata.name());
956
destination.push_back('=');
958
if (should_quote_field_value)
959
destination.push_back('\'');
961
destination.append(statement.variable_value());
963
if (should_quote_field_value)
964
destination.push_back('\'');
969
enum TransformSqlError
970
transformCreateTableStatementToSql(const CreateTableStatement &statement,
972
enum TransformSqlVariant sql_variant)
974
return transformTableDefinitionToSql(statement.table(), destination, sql_variant);
977
enum TransformSqlError
978
transformTableDefinitionToSql(const Table &table,
980
enum TransformSqlVariant sql_variant, bool with_schema)
982
char quoted_identifier= '`';
983
if (sql_variant == ANSI)
984
quoted_identifier= '"';
986
destination.append("CREATE ");
988
if (table.type() == Table::TEMPORARY)
989
destination.append("TEMPORARY ");
991
destination.append("TABLE ");
994
append_escaped_string(&destination, table.schema(), quoted_identifier);
995
destination.push_back('.');
997
append_escaped_string(&destination, table.name(), quoted_identifier);
998
destination.append(" (\n");
1000
enum TransformSqlError result= NONE;
1001
size_t num_fields= table.field_size();
1002
for (size_t x= 0; x < num_fields; ++x)
1004
const Table::Field &field= table.field(x);
1007
destination.append(",\n");
1009
destination.append(" ");
1011
result= transformFieldDefinitionToSql(field, destination, sql_variant);
1017
size_t num_indexes= table.indexes_size();
1019
if (num_indexes > 0)
1020
destination.append(",\n");
1022
for (size_t x= 0; x < num_indexes; ++x)
1024
const message::Table::Index &index= table.indexes(x);
1027
destination.append(",\n");
1029
result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
1035
size_t num_foreign_keys= table.fk_constraint_size();
1037
if (num_foreign_keys > 0)
1038
destination.append(",\n");
1040
for (size_t x= 0; x < num_foreign_keys; ++x)
1042
const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
1045
destination.append(",\n");
1047
result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1053
destination.append("\n)");
1055
/* Add ENGINE = " clause */
1056
if (table.has_engine())
1058
destination.append(" ENGINE=");
1059
destination.append(table.engine().name());
1061
size_t num_engine_options= table.engine().options_size();
1062
if (num_engine_options > 0)
1063
destination.append(" ", 1);
1064
for (size_t x= 0; x < num_engine_options; ++x)
1066
const Engine::Option &option= table.engine().options(x);
1067
destination.append(option.name());
1068
destination.append("='");
1069
destination.append(option.state());
1070
destination.append("'");
1071
if (x != num_engine_options-1)
1073
destination.append(", ");
1078
if (table.has_options())
1079
(void) transformTableOptionsToSql(table.options(), destination, sql_variant);
1084
enum TransformSqlError
1085
transformTableOptionsToSql(const Table::TableOptions &options,
1086
string &destination,
1087
enum TransformSqlVariant sql_variant)
1089
if (sql_variant == ANSI)
1090
return NONE; /* ANSI does not support table options... */
1092
if (options.has_comment())
1094
destination.append(" COMMENT=");
1095
append_escaped_string(&destination, options.comment());
1098
if (options.has_collation())
1100
destination.append(" COLLATE = ");
1101
destination.append(options.collation());
1104
if (options.has_data_file_name())
1106
destination.append("\nDATA_FILE_NAME = '");
1107
destination.append(options.data_file_name());
1108
destination.push_back('\'');
1111
if (options.has_index_file_name())
1113
destination.append("\nINDEX_FILE_NAME = '");
1114
destination.append(options.index_file_name());
1115
destination.push_back('\'');
1118
if (options.has_max_rows())
1120
destination.append("\nMAX_ROWS = ");
1121
destination.append(boost::lexical_cast<string>(options.max_rows()));
1124
if (options.has_min_rows())
1126
destination.append("\nMIN_ROWS = ");
1127
destination.append(boost::lexical_cast<string>(options.min_rows()));
1130
if (options.has_user_set_auto_increment_value()
1131
&& options.has_auto_increment_value())
1133
destination.append(" AUTO_INCREMENT=");
1134
destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
1137
if (options.has_avg_row_length())
1139
destination.append("\nAVG_ROW_LENGTH = ");
1140
destination.append(boost::lexical_cast<string>(options.avg_row_length()));
1143
if (options.has_checksum() &&
1145
destination.append("\nCHECKSUM = TRUE");
1146
if (options.has_page_checksum() &&
1147
options.page_checksum())
1148
destination.append("\nPAGE_CHECKSUM = TRUE");
1153
enum TransformSqlError
1154
transformIndexDefinitionToSql(const Table::Index &index,
1156
string &destination,
1157
enum TransformSqlVariant sql_variant)
1159
char quoted_identifier= '`';
1160
if (sql_variant == ANSI)
1161
quoted_identifier= '"';
1163
destination.append(" ", 2);
1165
if (index.is_primary())
1166
destination.append("PRIMARY ");
1167
else if (index.is_unique())
1168
destination.append("UNIQUE ");
1170
destination.append("KEY ", 4);
1171
if (! (index.is_primary() && index.name().compare("PRIMARY")==0))
1173
destination.push_back(quoted_identifier);
1174
destination.append(index.name());
1175
destination.push_back(quoted_identifier);
1176
destination.append(" (", 2);
1179
destination.append("(", 1);
1181
size_t num_parts= index.index_part_size();
1182
for (size_t x= 0; x < num_parts; ++x)
1184
const Table::Index::IndexPart &part= index.index_part(x);
1185
const Table::Field &field= table.field(part.fieldnr());
1188
destination.push_back(',');
1190
destination.push_back(quoted_identifier);
1191
destination.append(field.name());
1192
destination.push_back(quoted_identifier);
1195
* If the index part's field type is VARCHAR or TEXT
1196
* then check for a prefix length then is different
1197
* from the field's full length...
1199
if (field.type() == Table::Field::VARCHAR ||
1200
field.type() == Table::Field::BLOB)
1202
if (part.has_compare_length())
1204
if (part.compare_length() != field.string_options().length())
1206
destination.push_back('(');
1207
destination.append(boost::lexical_cast<string>(part.compare_length()));
1208
destination.push_back(')');
1213
destination.push_back(')');
1215
switch (index.type())
1217
case Table::Index::UNKNOWN_INDEX:
1219
case Table::Index::BTREE:
1220
destination.append(" USING BTREE");
1222
case Table::Index::RTREE:
1223
destination.append(" USING RTREE");
1225
case Table::Index::HASH:
1226
destination.append(" USING HASH");
1228
case Table::Index::FULLTEXT:
1229
destination.append(" USING FULLTEXT");
1233
if (index.has_comment())
1235
destination.append(" COMMENT ");
1236
append_escaped_string(&destination, index.comment());
1242
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
1246
case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1247
destination.append("RESTRICT");
1249
case Table::ForeignKeyConstraint::OPTION_CASCADE:
1250
destination.append("CASCADE");
1252
case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1253
destination.append("SET NULL");
1255
case Table::ForeignKeyConstraint::OPTION_UNDEF:
1256
case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1257
destination.append("NO ACTION");
1259
case Table::ForeignKeyConstraint::OPTION_SET_DEFAULT:
1260
destination.append("SET DEFAULT");
1265
enum TransformSqlError
1266
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
1268
string &destination,
1269
enum TransformSqlVariant sql_variant)
1271
char quoted_identifier= '`';
1272
if (sql_variant == ANSI)
1273
quoted_identifier= '"';
1275
destination.append(" ");
1277
if (fkey.has_name())
1279
destination.append("CONSTRAINT ");
1280
append_escaped_string(&destination, fkey.name(), quoted_identifier);
1281
destination.append(" ", 1);
1284
destination.append("FOREIGN KEY (");
1286
for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1289
destination.append(", ");
1291
append_escaped_string(&destination, fkey.column_names(x),
1295
destination.append(") REFERENCES ");
1297
append_escaped_string(&destination, fkey.references_table_name(),
1299
destination.append(" (");
1301
for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1304
destination.append(", ");
1306
append_escaped_string(&destination, fkey.references_columns(x),
1310
destination.push_back(')');
1312
if (fkey.has_update_option() and fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1314
destination.append(" ON UPDATE ");
1315
transformForeignKeyOptionToSql(fkey.update_option(), destination);
1318
if (fkey.has_delete_option() and fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1320
destination.append(" ON DELETE ");
1321
transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1327
enum TransformSqlError
1328
transformFieldDefinitionToSql(const Table::Field &field,
1329
string &destination,
1330
enum TransformSqlVariant sql_variant)
1332
char quoted_identifier= '`';
1333
char quoted_default;
1335
if (sql_variant == ANSI)
1336
quoted_identifier= '"';
1338
if (sql_variant == DRIZZLE)
1339
quoted_default= '\'';
1341
quoted_default= quoted_identifier;
1343
append_escaped_string(&destination, field.name(), quoted_identifier);
1345
Table::Field::FieldType field_type= field.type();
1349
case Table::Field::DOUBLE:
1350
destination.append(" DOUBLE");
1351
if (field.has_numeric_options()
1352
&& field.numeric_options().has_precision())
1355
ss << "(" << field.numeric_options().precision() << ",";
1356
ss << field.numeric_options().scale() << ")";
1357
destination.append(ss.str());
1360
case Table::Field::VARCHAR:
1362
if (field.string_options().has_collation()
1363
&& field.string_options().collation().compare("binary") == 0)
1364
destination.append(" VARBINARY(");
1366
destination.append(" VARCHAR(");
1368
destination.append(boost::lexical_cast<string>(field.string_options().length()));
1369
destination.append(")");
1372
case Table::Field::BLOB:
1374
if (field.string_options().has_collation()
1375
&& field.string_options().collation().compare("binary") == 0)
1376
destination.append(" BLOB");
1378
destination.append(" TEXT");
1381
case Table::Field::ENUM:
1383
size_t num_field_values= field.enumeration_values().field_value_size();
1384
destination.append(" ENUM(");
1385
for (size_t x= 0; x < num_field_values; ++x)
1387
const string &type= field.enumeration_values().field_value(x);
1390
destination.push_back(',');
1392
destination.push_back('\'');
1393
destination.append(type);
1394
destination.push_back('\'');
1396
destination.push_back(')');
1399
case Table::Field::UUID:
1400
destination.append(" UUID");
1402
case Table::Field::BOOLEAN:
1403
destination.append(" BOOLEAN");
1405
case Table::Field::INTEGER:
1406
destination.append(" INT");
1408
case Table::Field::BIGINT:
1409
if (field.has_constraints() and
1410
field.constraints().is_unsigned())
1412
destination.append(" BIGINT UNSIGNED");
1416
destination.append(" BIGINT");
1419
case Table::Field::DECIMAL:
1421
destination.append(" DECIMAL(");
1423
ss << field.numeric_options().precision() << ",";
1424
ss << field.numeric_options().scale() << ")";
1425
destination.append(ss.str());
1428
case Table::Field::DATE:
1429
destination.append(" DATE");
1432
case Table::Field::EPOCH:
1433
if (field.time_options().microseconds())
1435
destination.append(" TIMESTAMP(6)");
1439
destination.append(" TIMESTAMP");
1443
case Table::Field::DATETIME:
1444
destination.append(" DATETIME");
1446
case Table::Field::TIME:
1447
destination.append(" TIME");
1451
if (field.type() == Table::Field::BLOB ||
1452
field.type() == Table::Field::VARCHAR)
1454
if (field.string_options().has_collation()
1455
&& field.string_options().collation().compare("binary"))
1457
destination.append(" COLLATE ");
1458
destination.append(field.string_options().collation());
1462
if (field.has_constraints() and field.constraints().is_unique())
1464
destination.append(" UNIQUE");
1467
if (field.has_constraints() && field.constraints().is_notnull())
1469
destination.append(" NOT NULL");
1471
else if (field.type() == Table::Field::EPOCH)
1473
destination.append(" NULL");
1476
if (field.type() == Table::Field::INTEGER ||
1477
field.type() == Table::Field::BIGINT)
1479
/* AUTO_INCREMENT must be after NOT NULL */
1480
if (field.has_numeric_options() &&
1481
field.numeric_options().is_autoincrement())
1483
destination.append(" AUTO_INCREMENT");
1487
if (field.options().has_default_value())
1489
destination.append(" DEFAULT ");
1490
append_escaped_string(&destination, field.options().default_value());
1492
else if (field.options().has_default_expression())
1494
destination.append(" DEFAULT ");
1495
destination.append(field.options().default_expression());
1497
else if (field.options().has_default_bin_value())
1499
const string &v= field.options().default_bin_value();
1500
if (v.length() == 0)
1502
destination.append(" DEFAULT ''");
1506
destination.append(" DEFAULT 0x");
1507
for (size_t x= 0; x < v.length(); x++)
1510
snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
1511
destination.append(hex, 2);
1515
else if (field.options().has_default_null()
1516
&& field.options().default_null()
1517
&& field.type() != Table::Field::BLOB)
1519
destination.append(" DEFAULT NULL");
1522
if (field.has_options() && field.options().has_update_expression())
1524
destination.append(" ON UPDATE ");
1525
destination.append(field.options().update_expression());
1528
if (field.has_comment())
1530
destination.append(" COMMENT ");
1531
append_escaped_string(&destination, field.comment(), quoted_default);
1536
bool shouldQuoteFieldValue(Table::Field::FieldType in_type)
1540
case Table::Field::DOUBLE:
1541
case Table::Field::DECIMAL:
1542
case Table::Field::INTEGER:
1543
case Table::Field::BIGINT:
1550
Table::Field::FieldType internalFieldTypeToFieldProtoType(enum enum_field_types type)
1553
case DRIZZLE_TYPE_LONG:
1554
return Table::Field::INTEGER;
1555
case DRIZZLE_TYPE_DOUBLE:
1556
return Table::Field::DOUBLE;
1557
case DRIZZLE_TYPE_NULL:
1558
assert(false); /* Not a user definable type */
1559
return Table::Field::INTEGER; /* unreachable */
1560
case DRIZZLE_TYPE_MICROTIME:
1561
case DRIZZLE_TYPE_TIMESTAMP:
1562
return Table::Field::EPOCH;
1563
case DRIZZLE_TYPE_LONGLONG:
1564
return Table::Field::BIGINT;
1565
case DRIZZLE_TYPE_DATETIME:
1566
return Table::Field::DATETIME;
1567
case DRIZZLE_TYPE_TIME:
1568
return Table::Field::TIME;
1569
case DRIZZLE_TYPE_DATE:
1570
return Table::Field::DATE;
1571
case DRIZZLE_TYPE_VARCHAR:
1572
return Table::Field::VARCHAR;
1573
case DRIZZLE_TYPE_DECIMAL:
1574
return Table::Field::DECIMAL;
1575
case DRIZZLE_TYPE_ENUM:
1576
return Table::Field::ENUM;
1577
case DRIZZLE_TYPE_BLOB:
1578
return Table::Field::BLOB;
1579
case DRIZZLE_TYPE_UUID:
1580
return Table::Field::UUID;
1581
case DRIZZLE_TYPE_BOOLEAN:
1582
return Table::Field::BOOLEAN;
1586
return Table::Field::INTEGER; /* unreachable */
1589
bool transactionContainsBulkSegment(const Transaction &transaction)
1591
size_t num_statements= transaction.statement_size();
1592
if (num_statements == 0)
1596
* Only INSERT, UPDATE, and DELETE statements can possibly
1597
* have bulk segments. So, we loop through the statements
1598
* checking for segment_id > 1 in those specific submessages.
1601
for (x= 0; x < num_statements; ++x)
1603
const Statement &statement= transaction.statement(x);
1604
Statement::Type type= statement.type();
1608
case Statement::INSERT:
1609
if (statement.insert_data().segment_id() > 1)
1612
case Statement::UPDATE:
1613
if (statement.update_data().segment_id() > 1)
1616
case Statement::DELETE:
1617
if (statement.delete_data().segment_id() > 1)
1627
} /* namespace message */
1628
} /* namespace drizzled */