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
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::SET_VARIABLE:
323
assert(source.has_set_variable_statement());
325
error= transformSetVariableStatementToSql(source.set_variable_statement(),
328
sql_strings.push_back(destination);
331
case Statement::RAW_SQL:
333
sql_strings.push_back(source.sql());
339
enum TransformSqlError
340
transformInsertHeaderToSql(const InsertHeader &header,
342
enum TransformSqlVariant sql_variant)
344
char quoted_identifier= '`';
345
if (sql_variant == ANSI)
346
quoted_identifier= '"';
348
destination.assign("INSERT INTO ", 12);
349
destination.push_back(quoted_identifier);
350
destination.append(header.table_metadata().schema_name());
351
destination.push_back(quoted_identifier);
352
destination.push_back('.');
353
destination.push_back(quoted_identifier);
354
destination.append(header.table_metadata().table_name());
355
destination.push_back(quoted_identifier);
356
destination.append(" (", 2);
358
/* Add field list to SQL string... */
359
size_t num_fields= header.field_metadata_size();
362
for (x= 0; x < num_fields; ++x)
364
const FieldMetadata &field_metadata= header.field_metadata(x);
366
destination.push_back(',');
368
destination.push_back(quoted_identifier);
369
destination.append(field_metadata.name());
370
destination.push_back(quoted_identifier);
376
enum TransformSqlError
377
transformInsertRecordToSql(const InsertHeader &header,
378
const InsertRecord &record,
380
enum TransformSqlVariant sql_variant)
382
enum TransformSqlError error= transformInsertHeaderToSql(header,
386
char quoted_identifier= '`';
387
if (sql_variant == ANSI)
388
quoted_identifier= '"';
390
destination.append(") VALUES (");
392
/* Add insert values */
393
size_t num_fields= header.field_metadata_size();
395
bool should_quote_field_value= false;
397
for (x= 0; x < num_fields; ++x)
400
destination.push_back(',');
402
const FieldMetadata &field_metadata= header.field_metadata(x);
404
if (record.is_null(x))
406
should_quote_field_value= false;
410
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
413
if (should_quote_field_value)
414
destination.push_back('\'');
416
if (record.is_null(x))
418
destination.append("NULL");
422
if (field_metadata.type() == Table::Field::BLOB)
425
* We do this here because BLOB data is returned
426
* in a string correctly, but calling append()
427
* without a length will result in only the string
428
* up to a \0 being output here.
430
string raw_data(record.insert_value(x));
431
destination.append(raw_data.c_str(), raw_data.size());
435
string tmp(record.insert_value(x));
436
escapeEmbeddedQuotes(tmp);
437
destination.append(tmp);
441
if (should_quote_field_value)
442
destination.push_back('\'');
444
destination.push_back(')');
449
enum TransformSqlError
450
transformInsertStatementToSql(const InsertHeader &header,
451
const InsertData &data,
453
enum TransformSqlVariant sql_variant)
455
enum TransformSqlError error= transformInsertHeaderToSql(header,
459
char quoted_identifier= '`';
460
if (sql_variant == ANSI)
461
quoted_identifier= '"';
463
destination.append(") VALUES (", 10);
465
/* Add insert values */
466
size_t num_records= data.record_size();
467
size_t num_fields= header.field_metadata_size();
469
bool should_quote_field_value= false;
471
for (x= 0; x < num_records; ++x)
474
destination.append("),(", 3);
476
for (y= 0; y < num_fields; ++y)
479
destination.push_back(',');
481
const FieldMetadata &field_metadata= header.field_metadata(y);
483
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
485
if (should_quote_field_value)
486
destination.push_back('\'');
488
if (field_metadata.type() == Table::Field::BLOB)
491
* We do this here because BLOB data is returned
492
* in a string correctly, but calling append()
493
* without a length will result in only the string
494
* up to a \0 being output here.
496
string raw_data(data.record(x).insert_value(y));
497
destination.append(raw_data.c_str(), raw_data.size());
501
string tmp(data.record(x).insert_value(y));
502
escapeEmbeddedQuotes(tmp);
503
destination.append(tmp);
506
if (should_quote_field_value)
507
destination.push_back('\'');
510
destination.push_back(')');
515
enum TransformSqlError
516
transformUpdateHeaderToSql(const UpdateHeader &header,
518
enum TransformSqlVariant sql_variant)
520
char quoted_identifier= '`';
521
if (sql_variant == ANSI)
522
quoted_identifier= '"';
524
destination.assign("UPDATE ", 7);
525
destination.push_back(quoted_identifier);
526
destination.append(header.table_metadata().schema_name());
527
destination.push_back(quoted_identifier);
528
destination.push_back('.');
529
destination.push_back(quoted_identifier);
530
destination.append(header.table_metadata().table_name());
531
destination.push_back(quoted_identifier);
532
destination.append(" SET ", 5);
537
enum TransformSqlError
538
transformUpdateRecordToSql(const UpdateHeader &header,
539
const UpdateRecord &record,
541
enum TransformSqlVariant sql_variant)
543
enum TransformSqlError error= transformUpdateHeaderToSql(header,
547
char quoted_identifier= '`';
548
if (sql_variant == ANSI)
549
quoted_identifier= '"';
551
/* Add field SET list to SQL string... */
552
size_t num_set_fields= header.set_field_metadata_size();
554
bool should_quote_field_value= false;
556
for (x= 0; x < num_set_fields; ++x)
558
const FieldMetadata &field_metadata= header.set_field_metadata(x);
560
destination.push_back(',');
562
destination.push_back(quoted_identifier);
563
destination.append(field_metadata.name());
564
destination.push_back(quoted_identifier);
565
destination.push_back('=');
567
if (record.is_null(x))
569
should_quote_field_value= false;
573
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
576
if (should_quote_field_value)
577
destination.push_back('\'');
579
if (record.is_null(x))
581
destination.append("NULL");
585
if (field_metadata.type() == Table::Field::BLOB)
588
* We do this here because BLOB data is returned
589
* in a string correctly, but calling append()
590
* without a length will result in only the string
591
* up to a \0 being output here.
593
string raw_data(record.after_value(x));
594
destination.append(raw_data.c_str(), raw_data.size());
598
string tmp(record.after_value(x));
599
escapeEmbeddedQuotes(tmp);
600
destination.append(tmp);
604
if (should_quote_field_value)
605
destination.push_back('\'');
608
size_t num_key_fields= header.key_field_metadata_size();
610
destination.append(" WHERE ", 7);
611
for (x= 0; x < num_key_fields; ++x)
613
const FieldMetadata &field_metadata= header.key_field_metadata(x);
616
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
618
destination.push_back(quoted_identifier);
619
destination.append(field_metadata.name());
620
destination.push_back(quoted_identifier);
622
destination.push_back('=');
624
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
626
if (should_quote_field_value)
627
destination.push_back('\'');
629
if (field_metadata.type() == Table::Field::BLOB)
632
* We do this here because BLOB data is returned
633
* in a string correctly, but calling append()
634
* without a length will result in only the string
635
* up to a \0 being output here.
637
string raw_data(record.key_value(x));
638
destination.append(raw_data.c_str(), raw_data.size());
642
destination.append(record.key_value(x));
645
if (should_quote_field_value)
646
destination.push_back('\'');
652
enum TransformSqlError
653
transformDeleteHeaderToSql(const DeleteHeader &header,
655
enum TransformSqlVariant sql_variant)
657
char quoted_identifier= '`';
658
if (sql_variant == ANSI)
659
quoted_identifier= '"';
661
destination.assign("DELETE FROM ", 12);
662
destination.push_back(quoted_identifier);
663
destination.append(header.table_metadata().schema_name());
664
destination.push_back(quoted_identifier);
665
destination.push_back('.');
666
destination.push_back(quoted_identifier);
667
destination.append(header.table_metadata().table_name());
668
destination.push_back(quoted_identifier);
673
enum TransformSqlError
674
transformDeleteRecordToSql(const DeleteHeader &header,
675
const DeleteRecord &record,
677
enum TransformSqlVariant sql_variant)
679
enum TransformSqlError error= transformDeleteHeaderToSql(header,
682
char quoted_identifier= '`';
683
if (sql_variant == ANSI)
684
quoted_identifier= '"';
686
/* Add WHERE clause to SQL string... */
687
uint32_t num_key_fields= header.key_field_metadata_size();
689
bool should_quote_field_value= false;
691
destination.append(" WHERE ", 7);
692
for (x= 0; x < num_key_fields; ++x)
694
const FieldMetadata &field_metadata= header.key_field_metadata(x);
697
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
699
destination.push_back(quoted_identifier);
700
destination.append(field_metadata.name());
701
destination.push_back(quoted_identifier);
703
destination.push_back('=');
705
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
707
if (should_quote_field_value)
708
destination.push_back('\'');
710
if (field_metadata.type() == Table::Field::BLOB)
713
* We do this here because BLOB data is returned
714
* in a string correctly, but calling append()
715
* without a length will result in only the string
716
* up to a \0 being output here.
718
string raw_data(record.key_value(x));
719
destination.append(raw_data.c_str(), raw_data.size());
723
string tmp(record.key_value(x));
724
escapeEmbeddedQuotes(tmp);
725
destination.append(tmp);
728
if (should_quote_field_value)
729
destination.push_back('\'');
735
enum TransformSqlError
736
transformDeleteStatementToSql(const DeleteHeader &header,
737
const DeleteData &data,
739
enum TransformSqlVariant sql_variant)
741
enum TransformSqlError error= transformDeleteHeaderToSql(header,
744
char quoted_identifier= '`';
745
if (sql_variant == ANSI)
746
quoted_identifier= '"';
748
/* Add WHERE clause to SQL string... */
749
uint32_t num_key_fields= header.key_field_metadata_size();
750
uint32_t num_key_records= data.record_size();
752
bool should_quote_field_value= false;
754
destination.append(" WHERE ", 7);
755
for (x= 0; x < num_key_records; ++x)
758
destination.append(" OR ", 4); /* Always OR condition for multiple key records */
760
if (num_key_fields > 1)
761
destination.push_back('(');
763
for (y= 0; y < num_key_fields; ++y)
765
const FieldMetadata &field_metadata= header.key_field_metadata(y);
768
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
770
destination.push_back(quoted_identifier);
771
destination.append(field_metadata.name());
772
destination.push_back(quoted_identifier);
774
destination.push_back('=');
776
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
778
if (should_quote_field_value)
779
destination.push_back('\'');
781
if (field_metadata.type() == Table::Field::BLOB)
784
* We do this here because BLOB data is returned
785
* in a string correctly, but calling append()
786
* without a length will result in only the string
787
* up to a \0 being output here.
789
string raw_data(data.record(x).key_value(y));
790
destination.append(raw_data.c_str(), raw_data.size());
794
string tmp(data.record(x).key_value(y));
795
escapeEmbeddedQuotes(tmp);
796
destination.append(tmp);
799
if (should_quote_field_value)
800
destination.push_back('\'');
802
if (num_key_fields > 1)
803
destination.push_back(')');
808
enum TransformSqlError
809
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
811
enum TransformSqlVariant sql_variant)
813
char quoted_identifier= '`';
814
if (sql_variant == ANSI)
815
quoted_identifier= '"';
817
destination.append("DROP SCHEMA ", 12);
818
destination.push_back(quoted_identifier);
819
destination.append(statement.schema_name());
820
destination.push_back(quoted_identifier);
825
enum TransformSqlError
826
transformCreateSchemaStatementToSql(const CreateSchemaStatement &statement,
828
enum TransformSqlVariant sql_variant)
830
char quoted_identifier= '`';
831
if (sql_variant == ANSI)
832
quoted_identifier= '"';
834
const Schema &schema= statement.schema();
836
destination.append("CREATE SCHEMA ", 14);
837
destination.push_back(quoted_identifier);
838
destination.append(schema.name());
839
destination.push_back(quoted_identifier);
841
if (schema.has_collation())
843
destination.append(" COLLATE ", 9);
844
destination.append(schema.collation());
850
enum TransformSqlError
851
transformDropTableStatementToSql(const DropTableStatement &statement,
853
enum TransformSqlVariant sql_variant)
855
char quoted_identifier= '`';
856
if (sql_variant == ANSI)
857
quoted_identifier= '"';
859
const TableMetadata &table_metadata= statement.table_metadata();
861
destination.append("DROP TABLE ", 11);
863
/* Add the IF EXISTS clause if necessary */
864
if (statement.has_if_exists_clause() &&
865
statement.if_exists_clause() == true)
867
destination.append("IF EXISTS ", 10);
870
destination.push_back(quoted_identifier);
871
destination.append(table_metadata.schema_name());
872
destination.push_back(quoted_identifier);
873
destination.push_back('.');
874
destination.push_back(quoted_identifier);
875
destination.append(table_metadata.table_name());
876
destination.push_back(quoted_identifier);
881
enum TransformSqlError
882
transformTruncateTableStatementToSql(const TruncateTableStatement &statement,
884
enum TransformSqlVariant sql_variant)
886
char quoted_identifier= '`';
887
if (sql_variant == ANSI)
888
quoted_identifier= '"';
890
const TableMetadata &table_metadata= statement.table_metadata();
892
destination.append("TRUNCATE TABLE ", 15);
893
destination.push_back(quoted_identifier);
894
destination.append(table_metadata.schema_name());
895
destination.push_back(quoted_identifier);
896
destination.push_back('.');
897
destination.push_back(quoted_identifier);
898
destination.append(table_metadata.table_name());
899
destination.push_back(quoted_identifier);
904
enum TransformSqlError
905
transformSetVariableStatementToSql(const SetVariableStatement &statement,
907
enum TransformSqlVariant sql_variant)
910
const FieldMetadata &variable_metadata= statement.variable_metadata();
911
bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
913
destination.append("SET GLOBAL ", 11); /* Only global variables are replicated */
914
destination.append(variable_metadata.name());
915
destination.push_back('=');
917
if (should_quote_field_value)
918
destination.push_back('\'');
920
destination.append(statement.variable_value());
922
if (should_quote_field_value)
923
destination.push_back('\'');
928
enum TransformSqlError
929
transformCreateTableStatementToSql(const CreateTableStatement &statement,
931
enum TransformSqlVariant sql_variant)
933
return transformTableDefinitionToSql(statement.table(), destination, sql_variant);
936
enum TransformSqlError
937
transformTableDefinitionToSql(const Table &table,
939
enum TransformSqlVariant sql_variant, bool with_schema)
941
char quoted_identifier= '`';
942
if (sql_variant == ANSI)
943
quoted_identifier= '"';
945
destination.append("CREATE ", 7);
947
if (table.type() == Table::TEMPORARY)
948
destination.append("TEMPORARY ", 10);
950
destination.append("TABLE ", 6);
953
append_escaped_string(&destination, table.schema(), quoted_identifier);
954
destination.push_back('.');
956
append_escaped_string(&destination, table.name(), quoted_identifier);
957
destination.append(" (\n", 3);
959
enum TransformSqlError result= NONE;
960
size_t num_fields= table.field_size();
961
for (size_t x= 0; x < num_fields; ++x)
963
const Table::Field &field= table.field(x);
966
destination.append(",\n", 2);
968
destination.append(" ");
970
result= transformFieldDefinitionToSql(field, destination, sql_variant);
976
size_t num_indexes= table.indexes_size();
979
destination.append(",\n", 2);
981
for (size_t x= 0; x < num_indexes; ++x)
983
const message::Table::Index &index= table.indexes(x);
986
destination.append(",\n", 2);
988
result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
994
size_t num_foreign_keys= table.fk_constraint_size();
996
if (num_foreign_keys > 0)
997
destination.append(",\n", 2);
999
for (size_t x= 0; x < num_foreign_keys; ++x)
1001
const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
1004
destination.append(",\n", 2);
1006
result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1012
destination.append("\n)", 2);
1014
/* Add ENGINE = " clause */
1015
if (table.has_engine())
1017
destination.append(" ENGINE=", 8);
1018
destination.append(table.engine().name());
1020
size_t num_engine_options= table.engine().options_size();
1021
if (num_engine_options > 0)
1022
destination.append(" ", 1);
1023
for (size_t x= 0; x < num_engine_options; ++x)
1025
const Engine::Option &option= table.engine().options(x);
1026
destination.append(option.name());
1027
destination.append("='", 2);
1028
destination.append(option.state());
1029
destination.append("'", 1);
1030
if(x != num_engine_options-1)
1031
destination.append(", ", 2);
1035
if (table.has_options())
1036
(void) transformTableOptionsToSql(table.options(), destination, sql_variant);
1041
enum TransformSqlError
1042
transformTableOptionsToSql(const Table::TableOptions &options,
1043
string &destination,
1044
enum TransformSqlVariant sql_variant)
1046
if (sql_variant == ANSI)
1047
return NONE; /* ANSI does not support table options... */
1049
if (options.has_comment())
1051
destination.append(" COMMENT=", 9);
1052
append_escaped_string(&destination, options.comment());
1055
if (options.has_collation())
1057
destination.append(" COLLATE = ", 11);
1058
destination.append(options.collation());
1061
if (options.has_data_file_name())
1063
destination.append("\nDATA_FILE_NAME = '", 19);
1064
destination.append(options.data_file_name());
1065
destination.push_back('\'');
1068
if (options.has_index_file_name())
1070
destination.append("\nINDEX_FILE_NAME = '", 20);
1071
destination.append(options.index_file_name());
1072
destination.push_back('\'');
1075
if (options.has_max_rows())
1077
destination.append("\nMAX_ROWS = ", 12);
1078
destination.append(boost::lexical_cast<string>(options.max_rows()));
1081
if (options.has_min_rows())
1083
destination.append("\nMIN_ROWS = ", 12);
1084
destination.append(boost::lexical_cast<string>(options.min_rows()));
1087
if (options.has_user_set_auto_increment_value()
1088
&& options.has_auto_increment_value())
1090
destination.append(" AUTO_INCREMENT=", 16);
1091
destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
1094
if (options.has_avg_row_length())
1096
destination.append("\nAVG_ROW_LENGTH = ", 18);
1097
destination.append(boost::lexical_cast<string>(options.avg_row_length()));
1100
if (options.has_checksum() &&
1102
destination.append("\nCHECKSUM = TRUE", 16);
1103
if (options.has_page_checksum() &&
1104
options.page_checksum())
1105
destination.append("\nPAGE_CHECKSUM = TRUE", 21);
1110
enum TransformSqlError
1111
transformIndexDefinitionToSql(const Table::Index &index,
1113
string &destination,
1114
enum TransformSqlVariant sql_variant)
1116
char quoted_identifier= '`';
1117
if (sql_variant == ANSI)
1118
quoted_identifier= '"';
1120
destination.append(" ", 2);
1122
if (index.is_primary())
1123
destination.append("PRIMARY ", 8);
1124
else if (index.is_unique())
1125
destination.append("UNIQUE ", 7);
1127
destination.append("KEY ", 4);
1128
if (! (index.is_primary() && index.name().compare("PRIMARY")==0))
1130
destination.push_back(quoted_identifier);
1131
destination.append(index.name());
1132
destination.push_back(quoted_identifier);
1133
destination.append(" (", 2);
1136
destination.append("(", 1);
1138
size_t num_parts= index.index_part_size();
1139
for (size_t x= 0; x < num_parts; ++x)
1141
const Table::Index::IndexPart &part= index.index_part(x);
1142
const Table::Field &field= table.field(part.fieldnr());
1145
destination.push_back(',');
1147
destination.push_back(quoted_identifier);
1148
destination.append(field.name());
1149
destination.push_back(quoted_identifier);
1152
* If the index part's field type is VARCHAR or TEXT
1153
* then check for a prefix length then is different
1154
* from the field's full length...
1156
if (field.type() == Table::Field::VARCHAR ||
1157
field.type() == Table::Field::BLOB)
1159
if (part.has_compare_length())
1161
if (part.compare_length() != field.string_options().length())
1163
destination.push_back('(');
1164
destination.append(boost::lexical_cast<string>(part.compare_length()));
1165
destination.push_back(')');
1170
destination.push_back(')');
1172
switch (index.type())
1174
case Table::Index::UNKNOWN_INDEX:
1176
case Table::Index::BTREE:
1177
destination.append(" USING BTREE", 12);
1179
case Table::Index::RTREE:
1180
destination.append(" USING RTREE", 12);
1182
case Table::Index::HASH:
1183
destination.append(" USING HASH", 11);
1185
case Table::Index::FULLTEXT:
1186
destination.append(" USING FULLTEXT", 15);
1190
if (index.has_comment())
1192
destination.append(" COMMENT ", 9);
1193
append_escaped_string(&destination, index.comment());
1199
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
1203
case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1204
destination.append("RESTRICT");
1206
case Table::ForeignKeyConstraint::OPTION_CASCADE:
1207
destination.append("CASCADE");
1209
case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1210
destination.append("SET NULL");
1212
case Table::ForeignKeyConstraint::OPTION_UNDEF:
1213
case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1214
destination.append("NO ACTION");
1216
case Table::ForeignKeyConstraint::OPTION_SET_DEFAULT:
1217
destination.append("SET DEFAULT");
1222
enum TransformSqlError
1223
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
1225
string &destination,
1226
enum TransformSqlVariant sql_variant)
1228
char quoted_identifier= '`';
1229
if (sql_variant == ANSI)
1230
quoted_identifier= '"';
1232
destination.append(" ", 2);
1234
if (fkey.has_name())
1236
destination.append("CONSTRAINT ", 11);
1237
append_escaped_string(&destination, fkey.name(), quoted_identifier);
1238
destination.append(" ", 1);
1241
destination.append("FOREIGN KEY (", 13);
1243
for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1246
destination.append(", ");
1248
append_escaped_string(&destination, fkey.column_names(x),
1252
destination.append(") REFERENCES ", 13);
1254
append_escaped_string(&destination, fkey.references_table_name(),
1256
destination.append(" (", 2);
1258
for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1261
destination.append(", ");
1263
append_escaped_string(&destination, fkey.references_columns(x),
1267
destination.push_back(')');
1269
if (fkey.has_update_option() and fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1271
destination.append(" ON UPDATE ", 11);
1272
transformForeignKeyOptionToSql(fkey.update_option(), destination);
1275
if (fkey.has_delete_option() and fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1277
destination.append(" ON DELETE ", 11);
1278
transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1284
enum TransformSqlError
1285
transformFieldDefinitionToSql(const Table::Field &field,
1286
string &destination,
1287
enum TransformSqlVariant sql_variant)
1289
char quoted_identifier= '`';
1290
char quoted_default;
1292
if (sql_variant == ANSI)
1293
quoted_identifier= '"';
1295
if (sql_variant == DRIZZLE)
1296
quoted_default= '\'';
1298
quoted_default= quoted_identifier;
1300
append_escaped_string(&destination, field.name(), quoted_identifier);
1302
Table::Field::FieldType field_type= field.type();
1306
case Table::Field::DOUBLE:
1307
destination.append(" DOUBLE", 7);
1308
if (field.has_numeric_options()
1309
&& field.numeric_options().has_precision())
1312
ss << "(" << field.numeric_options().precision() << ",";
1313
ss << field.numeric_options().scale() << ")";
1314
destination.append(ss.str());
1317
case Table::Field::VARCHAR:
1319
if (field.string_options().has_collation()
1320
&& field.string_options().collation().compare("binary") == 0)
1321
destination.append(" VARBINARY(", 11);
1323
destination.append(" VARCHAR(", 9);
1325
destination.append(boost::lexical_cast<string>(field.string_options().length()));
1326
destination.append(")");
1329
case Table::Field::BLOB:
1331
if (field.string_options().has_collation()
1332
&& field.string_options().collation().compare("binary") == 0)
1333
destination.append(" BLOB", 5);
1335
destination.append(" TEXT", 5);
1338
case Table::Field::ENUM:
1340
size_t num_field_values= field.enumeration_values().field_value_size();
1341
destination.append(" ENUM(", 6);
1342
for (size_t x= 0; x < num_field_values; ++x)
1344
const string &type= field.enumeration_values().field_value(x);
1347
destination.push_back(',');
1349
destination.push_back('\'');
1350
destination.append(type);
1351
destination.push_back('\'');
1353
destination.push_back(')');
1356
case Table::Field::UUID:
1357
destination.append(" UUID", 5);
1359
case Table::Field::INTEGER:
1360
destination.append(" INT", 4);
1362
case Table::Field::BIGINT:
1363
destination.append(" BIGINT", 7);
1365
case Table::Field::DECIMAL:
1367
destination.append(" DECIMAL(", 9);
1369
ss << field.numeric_options().precision() << ",";
1370
ss << field.numeric_options().scale() << ")";
1371
destination.append(ss.str());
1374
case Table::Field::DATE:
1375
destination.append(" DATE", 5);
1377
case Table::Field::TIMESTAMP:
1378
destination.append(" TIMESTAMP", 10);
1380
case Table::Field::DATETIME:
1381
destination.append(" DATETIME", 9);
1385
if (field.type() == Table::Field::INTEGER ||
1386
field.type() == Table::Field::BIGINT)
1388
if (field.has_constraints() &&
1389
field.constraints().has_is_unsigned() &&
1390
field.constraints().is_unsigned())
1392
destination.append(" UNSIGNED", 9);
1396
if (field.type() == Table::Field::BLOB ||
1397
field.type() == Table::Field::VARCHAR)
1399
if (field.string_options().has_collation()
1400
&& field.string_options().collation().compare("binary"))
1402
destination.append(" COLLATE ", 9);
1403
destination.append(field.string_options().collation());
1407
if (field.has_constraints() &&
1408
! field.constraints().is_nullable())
1410
destination.append(" NOT NULL", 9);
1412
else if (field.type() == Table::Field::TIMESTAMP)
1413
destination.append(" NULL", 5);
1415
if (field.type() == Table::Field::INTEGER ||
1416
field.type() == Table::Field::BIGINT)
1418
/* AUTO_INCREMENT must be after NOT NULL */
1419
if (field.has_numeric_options() &&
1420
field.numeric_options().is_autoincrement())
1422
destination.append(" AUTO_INCREMENT", 15);
1426
if (field.options().has_default_value())
1428
destination.append(" DEFAULT ", 9);
1429
append_escaped_string(&destination, field.options().default_value());
1431
else if (field.options().has_default_expression())
1433
destination.append(" DEFAULT ", 9);
1434
destination.append(field.options().default_expression());
1436
else if (field.options().has_default_bin_value())
1438
const string &v= field.options().default_bin_value();
1439
if (v.length() == 0)
1440
destination.append(" DEFAULT ''", 11);
1443
destination.append(" DEFAULT 0x", 11);
1444
for (size_t x= 0; x < v.length(); x++)
1447
snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
1448
destination.append(hex, 2);
1452
else if (field.options().has_default_null()
1453
&& field.options().default_null()
1454
&& field.type() != Table::Field::BLOB)
1456
destination.append(" DEFAULT NULL", 13);
1459
if (field.has_options() && field.options().has_update_expression())
1461
destination.append(" ON UPDATE ", 11);
1462
destination.append(field.options().update_expression());
1465
if (field.has_comment())
1467
destination.append(" COMMENT ", 9);
1468
append_escaped_string(&destination, field.comment(), quoted_default);
1473
bool shouldQuoteFieldValue(Table::Field::FieldType in_type)
1477
case Table::Field::DOUBLE:
1478
case Table::Field::DECIMAL:
1479
case Table::Field::INTEGER:
1480
case Table::Field::BIGINT:
1487
Table::Field::FieldType internalFieldTypeToFieldProtoType(enum enum_field_types type)
1490
case DRIZZLE_TYPE_LONG:
1491
return Table::Field::INTEGER;
1492
case DRIZZLE_TYPE_DOUBLE:
1493
return Table::Field::DOUBLE;
1494
case DRIZZLE_TYPE_NULL:
1495
assert(false); /* Not a user definable type */
1496
return Table::Field::INTEGER; /* unreachable */
1497
case DRIZZLE_TYPE_TIMESTAMP:
1498
return Table::Field::TIMESTAMP;
1499
case DRIZZLE_TYPE_LONGLONG:
1500
return Table::Field::BIGINT;
1501
case DRIZZLE_TYPE_DATETIME:
1502
return Table::Field::DATETIME;
1503
case DRIZZLE_TYPE_DATE:
1504
return Table::Field::DATE;
1505
case DRIZZLE_TYPE_VARCHAR:
1506
return Table::Field::VARCHAR;
1507
case DRIZZLE_TYPE_DECIMAL:
1508
return Table::Field::DECIMAL;
1509
case DRIZZLE_TYPE_ENUM:
1510
return Table::Field::ENUM;
1511
case DRIZZLE_TYPE_BLOB:
1512
return Table::Field::BLOB;
1513
case DRIZZLE_TYPE_UUID:
1514
return Table::Field::UUID;
1518
return Table::Field::INTEGER; /* unreachable */
1521
bool transactionContainsBulkSegment(const Transaction &transaction)
1523
size_t num_statements= transaction.statement_size();
1524
if (num_statements == 0)
1528
* Only INSERT, UPDATE, and DELETE statements can possibly
1529
* have bulk segments. So, we loop through the statements
1530
* checking for segment_id > 1 in those specific submessages.
1533
for (x= 0; x < num_statements; ++x)
1535
const Statement &statement= transaction.statement(x);
1536
Statement::Type type= statement.type();
1540
case Statement::INSERT:
1541
if (statement.insert_data().segment_id() > 1)
1544
case Statement::UPDATE:
1545
if (statement.update_data().segment_id() > 1)
1548
case Statement::DELETE:
1549
if (statement.delete_data().segment_id() > 1)
1559
} /* namespace message */
1560
} /* namespace drizzled */