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 "drizzled/message/statement_transform.h"
35
#include "drizzled/message/transaction.pb.h"
36
#include "drizzled/message/table.pb.h"
37
#include "drizzled/charset.h"
38
#include "drizzled/charset_info.h"
39
#include "drizzled/global_charset_info.h"
54
static void escapeEmbeddedQuotes(string &s, const char quote='\'')
58
for (it= s.begin(); it != s.end(); ++it)
62
it= s.insert(it, quote);
63
++it; // advance back to the quote
68
/* Incredibly similar to append_unescaped() in table.cc, but for std::string */
69
static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
71
const char *pos= input.c_str();
72
const char *end= input.c_str()+input.length();
73
res->push_back(quote);
75
for (; pos != end ; pos++)
78
if (use_mb(default_charset_info) &&
79
(mblen= my_ismbchar(default_charset_info, pos, end)))
81
res->append(pos, mblen);
89
case 0: /* Must be escaped for 'mysql' */
93
case '\n': /* Must be escaped for logs */
98
res->push_back('\\'); /* This gives better readability */
102
res->push_back('\\'); /* Because of the sql syntax */
103
res->push_back('\\');
106
if (*pos == quote) /* SQL syntax for quoting a quote */
108
res->push_back(quote);
109
res->push_back(quote);
112
res->push_back(*pos);
116
res->push_back(quote);
119
enum TransformSqlError
120
transformStatementToSql(const Statement &source,
121
vector<string> &sql_strings,
122
enum TransformSqlVariant sql_variant,
123
bool already_in_transaction)
125
TransformSqlError error= NONE;
127
switch (source.type())
129
case Statement::INSERT:
131
if (! source.has_insert_header())
133
error= MISSING_HEADER;
136
if (! source.has_insert_data())
142
const InsertHeader &insert_header= source.insert_header();
143
const InsertData &insert_data= source.insert_data();
144
size_t num_keys= insert_data.record_size();
147
if (num_keys > 1 && ! already_in_transaction)
148
sql_strings.push_back("START TRANSACTION");
150
for (x= 0; x < num_keys; ++x)
154
error= transformInsertRecordToSql(insert_header,
155
insert_data.record(x),
161
sql_strings.push_back(destination);
164
if (num_keys > 1 && ! already_in_transaction)
167
sql_strings.push_back("COMMIT");
169
sql_strings.push_back("ROLLBACK");
173
case Statement::UPDATE:
175
if (! source.has_update_header())
177
error= MISSING_HEADER;
180
if (! source.has_update_data())
186
const UpdateHeader &update_header= source.update_header();
187
const UpdateData &update_data= source.update_data();
188
size_t num_keys= update_data.record_size();
191
if (num_keys > 1 && ! already_in_transaction)
192
sql_strings.push_back("START TRANSACTION");
194
for (x= 0; x < num_keys; ++x)
198
error= transformUpdateRecordToSql(update_header,
199
update_data.record(x),
205
sql_strings.push_back(destination);
208
if (num_keys > 1 && ! already_in_transaction)
211
sql_strings.push_back("COMMIT");
213
sql_strings.push_back("ROLLBACK");
217
case Statement::DELETE:
219
if (! source.has_delete_header())
221
error= MISSING_HEADER;
224
if (! source.has_delete_data())
230
const DeleteHeader &delete_header= source.delete_header();
231
const DeleteData &delete_data= source.delete_data();
232
size_t num_keys= delete_data.record_size();
235
if (num_keys > 1 && ! already_in_transaction)
236
sql_strings.push_back("START TRANSACTION");
238
for (x= 0; x < num_keys; ++x)
242
error= transformDeleteRecordToSql(delete_header,
243
delete_data.record(x),
249
sql_strings.push_back(destination);
252
if (num_keys > 1 && ! already_in_transaction)
255
sql_strings.push_back("COMMIT");
257
sql_strings.push_back("ROLLBACK");
261
case Statement::CREATE_TABLE:
263
assert(source.has_create_table_statement());
265
error= transformCreateTableStatementToSql(source.create_table_statement(),
268
sql_strings.push_back(destination);
271
case Statement::TRUNCATE_TABLE:
273
assert(source.has_truncate_table_statement());
275
error= transformTruncateTableStatementToSql(source.truncate_table_statement(),
278
sql_strings.push_back(destination);
281
case Statement::DROP_TABLE:
283
assert(source.has_drop_table_statement());
285
error= transformDropTableStatementToSql(source.drop_table_statement(),
288
sql_strings.push_back(destination);
291
case Statement::CREATE_SCHEMA:
293
assert(source.has_create_schema_statement());
295
error= transformCreateSchemaStatementToSql(source.create_schema_statement(),
298
sql_strings.push_back(destination);
301
case Statement::DROP_SCHEMA:
303
assert(source.has_drop_schema_statement());
305
error= transformDropSchemaStatementToSql(source.drop_schema_statement(),
308
sql_strings.push_back(destination);
311
case Statement::SET_VARIABLE:
313
assert(source.has_set_variable_statement());
315
error= transformSetVariableStatementToSql(source.set_variable_statement(),
318
sql_strings.push_back(destination);
321
case Statement::RAW_SQL:
323
sql_strings.push_back(source.sql());
329
enum TransformSqlError
330
transformInsertHeaderToSql(const InsertHeader &header,
332
enum TransformSqlVariant sql_variant)
334
char quoted_identifier= '`';
335
if (sql_variant == ANSI)
336
quoted_identifier= '"';
338
destination.assign("INSERT INTO ", 12);
339
destination.push_back(quoted_identifier);
340
destination.append(header.table_metadata().schema_name());
341
destination.push_back(quoted_identifier);
342
destination.push_back('.');
343
destination.push_back(quoted_identifier);
344
destination.append(header.table_metadata().table_name());
345
destination.push_back(quoted_identifier);
346
destination.append(" (", 2);
348
/* Add field list to SQL string... */
349
size_t num_fields= header.field_metadata_size();
352
for (x= 0; x < num_fields; ++x)
354
const FieldMetadata &field_metadata= header.field_metadata(x);
356
destination.push_back(',');
358
destination.push_back(quoted_identifier);
359
destination.append(field_metadata.name());
360
destination.push_back(quoted_identifier);
366
enum TransformSqlError
367
transformInsertRecordToSql(const InsertHeader &header,
368
const InsertRecord &record,
370
enum TransformSqlVariant sql_variant)
372
enum TransformSqlError error= transformInsertHeaderToSql(header,
376
char quoted_identifier= '`';
377
if (sql_variant == ANSI)
378
quoted_identifier= '"';
380
destination.append(") VALUES (");
382
/* Add insert values */
383
size_t num_fields= header.field_metadata_size();
385
bool should_quote_field_value= false;
387
for (x= 0; x < num_fields; ++x)
390
destination.push_back(',');
392
const FieldMetadata &field_metadata= header.field_metadata(x);
394
if (record.is_null(x))
396
should_quote_field_value= false;
400
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
403
if (should_quote_field_value)
404
destination.push_back('\'');
406
if (record.is_null(x))
408
destination.append("NULL");
412
if (field_metadata.type() == Table::Field::BLOB)
415
* We do this here because BLOB data is returned
416
* in a string correctly, but calling append()
417
* without a length will result in only the string
418
* up to a \0 being output here.
420
string raw_data(record.insert_value(x));
421
destination.append(raw_data.c_str(), raw_data.size());
425
string tmp(record.insert_value(x));
426
escapeEmbeddedQuotes(tmp);
427
destination.append(tmp);
431
if (should_quote_field_value)
432
destination.push_back('\'');
434
destination.push_back(')');
439
enum TransformSqlError
440
transformInsertStatementToSql(const InsertHeader &header,
441
const InsertData &data,
443
enum TransformSqlVariant sql_variant)
445
enum TransformSqlError error= transformInsertHeaderToSql(header,
449
char quoted_identifier= '`';
450
if (sql_variant == ANSI)
451
quoted_identifier= '"';
453
destination.append(") VALUES (", 10);
455
/* Add insert values */
456
size_t num_records= data.record_size();
457
size_t num_fields= header.field_metadata_size();
459
bool should_quote_field_value= false;
461
for (x= 0; x < num_records; ++x)
464
destination.append("),(", 3);
466
for (y= 0; y < num_fields; ++y)
469
destination.push_back(',');
471
const FieldMetadata &field_metadata= header.field_metadata(y);
473
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
475
if (should_quote_field_value)
476
destination.push_back('\'');
478
if (field_metadata.type() == Table::Field::BLOB)
481
* We do this here because BLOB data is returned
482
* in a string correctly, but calling append()
483
* without a length will result in only the string
484
* up to a \0 being output here.
486
string raw_data(data.record(x).insert_value(y));
487
destination.append(raw_data.c_str(), raw_data.size());
491
string tmp(data.record(x).insert_value(y));
492
escapeEmbeddedQuotes(tmp);
493
destination.append(tmp);
496
if (should_quote_field_value)
497
destination.push_back('\'');
500
destination.push_back(')');
505
enum TransformSqlError
506
transformUpdateHeaderToSql(const UpdateHeader &header,
508
enum TransformSqlVariant sql_variant)
510
char quoted_identifier= '`';
511
if (sql_variant == ANSI)
512
quoted_identifier= '"';
514
destination.assign("UPDATE ", 7);
515
destination.push_back(quoted_identifier);
516
destination.append(header.table_metadata().schema_name());
517
destination.push_back(quoted_identifier);
518
destination.push_back('.');
519
destination.push_back(quoted_identifier);
520
destination.append(header.table_metadata().table_name());
521
destination.push_back(quoted_identifier);
522
destination.append(" SET ", 5);
527
enum TransformSqlError
528
transformUpdateRecordToSql(const UpdateHeader &header,
529
const UpdateRecord &record,
531
enum TransformSqlVariant sql_variant)
533
enum TransformSqlError error= transformUpdateHeaderToSql(header,
537
char quoted_identifier= '`';
538
if (sql_variant == ANSI)
539
quoted_identifier= '"';
541
/* Add field SET list to SQL string... */
542
size_t num_set_fields= header.set_field_metadata_size();
544
bool should_quote_field_value= false;
546
for (x= 0; x < num_set_fields; ++x)
548
const FieldMetadata &field_metadata= header.set_field_metadata(x);
550
destination.push_back(',');
552
destination.push_back(quoted_identifier);
553
destination.append(field_metadata.name());
554
destination.push_back(quoted_identifier);
555
destination.push_back('=');
557
if (record.is_null(x))
559
should_quote_field_value= false;
563
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
566
if (should_quote_field_value)
567
destination.push_back('\'');
569
if (record.is_null(x))
571
destination.append("NULL");
575
if (field_metadata.type() == Table::Field::BLOB)
578
* We do this here because BLOB data is returned
579
* in a string correctly, but calling append()
580
* without a length will result in only the string
581
* up to a \0 being output here.
583
string raw_data(record.after_value(x));
584
destination.append(raw_data.c_str(), raw_data.size());
588
string tmp(record.after_value(x));
589
escapeEmbeddedQuotes(tmp);
590
destination.append(tmp);
594
if (should_quote_field_value)
595
destination.push_back('\'');
598
size_t num_key_fields= header.key_field_metadata_size();
600
destination.append(" WHERE ", 7);
601
for (x= 0; x < num_key_fields; ++x)
603
const FieldMetadata &field_metadata= header.key_field_metadata(x);
606
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
608
destination.push_back(quoted_identifier);
609
destination.append(field_metadata.name());
610
destination.push_back(quoted_identifier);
612
destination.push_back('=');
614
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
616
if (should_quote_field_value)
617
destination.push_back('\'');
619
if (field_metadata.type() == Table::Field::BLOB)
622
* We do this here because BLOB data is returned
623
* in a string correctly, but calling append()
624
* without a length will result in only the string
625
* up to a \0 being output here.
627
string raw_data(record.key_value(x));
628
destination.append(raw_data.c_str(), raw_data.size());
632
destination.append(record.key_value(x));
635
if (should_quote_field_value)
636
destination.push_back('\'');
642
enum TransformSqlError
643
transformDeleteHeaderToSql(const DeleteHeader &header,
645
enum TransformSqlVariant sql_variant)
647
char quoted_identifier= '`';
648
if (sql_variant == ANSI)
649
quoted_identifier= '"';
651
destination.assign("DELETE FROM ", 12);
652
destination.push_back(quoted_identifier);
653
destination.append(header.table_metadata().schema_name());
654
destination.push_back(quoted_identifier);
655
destination.push_back('.');
656
destination.push_back(quoted_identifier);
657
destination.append(header.table_metadata().table_name());
658
destination.push_back(quoted_identifier);
663
enum TransformSqlError
664
transformDeleteRecordToSql(const DeleteHeader &header,
665
const DeleteRecord &record,
667
enum TransformSqlVariant sql_variant)
669
enum TransformSqlError error= transformDeleteHeaderToSql(header,
672
char quoted_identifier= '`';
673
if (sql_variant == ANSI)
674
quoted_identifier= '"';
676
/* Add WHERE clause to SQL string... */
677
uint32_t num_key_fields= header.key_field_metadata_size();
679
bool should_quote_field_value= false;
681
destination.append(" WHERE ", 7);
682
for (x= 0; x < num_key_fields; ++x)
684
const FieldMetadata &field_metadata= header.key_field_metadata(x);
687
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
689
destination.push_back(quoted_identifier);
690
destination.append(field_metadata.name());
691
destination.push_back(quoted_identifier);
693
destination.push_back('=');
695
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
697
if (should_quote_field_value)
698
destination.push_back('\'');
700
if (field_metadata.type() == Table::Field::BLOB)
703
* We do this here because BLOB data is returned
704
* in a string correctly, but calling append()
705
* without a length will result in only the string
706
* up to a \0 being output here.
708
string raw_data(record.key_value(x));
709
destination.append(raw_data.c_str(), raw_data.size());
713
string tmp(record.key_value(x));
714
escapeEmbeddedQuotes(tmp);
715
destination.append(tmp);
718
if (should_quote_field_value)
719
destination.push_back('\'');
725
enum TransformSqlError
726
transformDeleteStatementToSql(const DeleteHeader &header,
727
const DeleteData &data,
729
enum TransformSqlVariant sql_variant)
731
enum TransformSqlError error= transformDeleteHeaderToSql(header,
734
char quoted_identifier= '`';
735
if (sql_variant == ANSI)
736
quoted_identifier= '"';
738
/* Add WHERE clause to SQL string... */
739
uint32_t num_key_fields= header.key_field_metadata_size();
740
uint32_t num_key_records= data.record_size();
742
bool should_quote_field_value= false;
744
destination.append(" WHERE ", 7);
745
for (x= 0; x < num_key_records; ++x)
748
destination.append(" OR ", 4); /* Always OR condition for multiple key records */
750
if (num_key_fields > 1)
751
destination.push_back('(');
753
for (y= 0; y < num_key_fields; ++y)
755
const FieldMetadata &field_metadata= header.key_field_metadata(y);
758
destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
760
destination.push_back(quoted_identifier);
761
destination.append(field_metadata.name());
762
destination.push_back(quoted_identifier);
764
destination.push_back('=');
766
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
768
if (should_quote_field_value)
769
destination.push_back('\'');
771
if (field_metadata.type() == Table::Field::BLOB)
774
* We do this here because BLOB data is returned
775
* in a string correctly, but calling append()
776
* without a length will result in only the string
777
* up to a \0 being output here.
779
string raw_data(data.record(x).key_value(y));
780
destination.append(raw_data.c_str(), raw_data.size());
784
string tmp(data.record(x).key_value(y));
785
escapeEmbeddedQuotes(tmp);
786
destination.append(tmp);
789
if (should_quote_field_value)
790
destination.push_back('\'');
792
if (num_key_fields > 1)
793
destination.push_back(')');
798
enum TransformSqlError
799
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
801
enum TransformSqlVariant sql_variant)
803
char quoted_identifier= '`';
804
if (sql_variant == ANSI)
805
quoted_identifier= '"';
807
destination.append("DROP SCHEMA ", 12);
808
destination.push_back(quoted_identifier);
809
destination.append(statement.schema_name());
810
destination.push_back(quoted_identifier);
815
enum TransformSqlError
816
transformCreateSchemaStatementToSql(const CreateSchemaStatement &statement,
818
enum TransformSqlVariant sql_variant)
820
char quoted_identifier= '`';
821
if (sql_variant == ANSI)
822
quoted_identifier= '"';
824
const Schema &schema= statement.schema();
826
destination.append("CREATE SCHEMA ", 14);
827
destination.push_back(quoted_identifier);
828
destination.append(schema.name());
829
destination.push_back(quoted_identifier);
831
if (schema.has_collation())
833
destination.append(" COLLATE ", 9);
834
destination.append(schema.collation());
840
enum TransformSqlError
841
transformDropTableStatementToSql(const DropTableStatement &statement,
843
enum TransformSqlVariant sql_variant)
845
char quoted_identifier= '`';
846
if (sql_variant == ANSI)
847
quoted_identifier= '"';
849
const TableMetadata &table_metadata= statement.table_metadata();
851
destination.append("DROP TABLE ", 11);
853
/* Add the IF EXISTS clause if necessary */
854
if (statement.has_if_exists_clause() &&
855
statement.if_exists_clause() == true)
857
destination.append("IF EXISTS ", 10);
860
destination.push_back(quoted_identifier);
861
destination.append(table_metadata.schema_name());
862
destination.push_back(quoted_identifier);
863
destination.push_back('.');
864
destination.push_back(quoted_identifier);
865
destination.append(table_metadata.table_name());
866
destination.push_back(quoted_identifier);
871
enum TransformSqlError
872
transformTruncateTableStatementToSql(const TruncateTableStatement &statement,
874
enum TransformSqlVariant sql_variant)
876
char quoted_identifier= '`';
877
if (sql_variant == ANSI)
878
quoted_identifier= '"';
880
const TableMetadata &table_metadata= statement.table_metadata();
882
destination.append("TRUNCATE TABLE ", 15);
883
destination.push_back(quoted_identifier);
884
destination.append(table_metadata.schema_name());
885
destination.push_back(quoted_identifier);
886
destination.push_back('.');
887
destination.push_back(quoted_identifier);
888
destination.append(table_metadata.table_name());
889
destination.push_back(quoted_identifier);
894
enum TransformSqlError
895
transformSetVariableStatementToSql(const SetVariableStatement &statement,
897
enum TransformSqlVariant sql_variant)
900
const FieldMetadata &variable_metadata= statement.variable_metadata();
901
bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
903
destination.append("SET GLOBAL ", 11); /* Only global variables are replicated */
904
destination.append(variable_metadata.name());
905
destination.push_back('=');
907
if (should_quote_field_value)
908
destination.push_back('\'');
910
destination.append(statement.variable_value());
912
if (should_quote_field_value)
913
destination.push_back('\'');
918
enum TransformSqlError
919
transformCreateTableStatementToSql(const CreateTableStatement &statement,
921
enum TransformSqlVariant sql_variant)
923
return transformTableDefinitionToSql(statement.table(), destination, sql_variant);
926
enum TransformSqlError
927
transformTableDefinitionToSql(const Table &table,
929
enum TransformSqlVariant sql_variant, bool with_schema)
931
char quoted_identifier= '`';
932
if (sql_variant == ANSI)
933
quoted_identifier= '"';
935
destination.append("CREATE ", 7);
937
if (table.type() == Table::TEMPORARY)
938
destination.append("TEMPORARY ", 10);
940
destination.append("TABLE ", 6);
943
append_escaped_string(&destination, table.schema(), quoted_identifier);
944
destination.push_back('.');
946
append_escaped_string(&destination, table.name(), quoted_identifier);
947
destination.append(" (\n", 3);
949
enum TransformSqlError result= NONE;
950
size_t num_fields= table.field_size();
951
for (size_t x= 0; x < num_fields; ++x)
953
const Table::Field &field= table.field(x);
956
destination.append(",\n", 2);
958
destination.append(" ");
960
result= transformFieldDefinitionToSql(field, destination, sql_variant);
966
size_t num_indexes= table.indexes_size();
969
destination.append(",\n", 2);
971
for (size_t x= 0; x < num_indexes; ++x)
973
const message::Table::Index &index= table.indexes(x);
976
destination.append(",\n", 2);
978
result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
984
size_t num_foreign_keys= table.fk_constraint_size();
986
if (num_foreign_keys > 0)
987
destination.append(",\n", 2);
989
for (size_t x= 0; x < num_foreign_keys; ++x)
991
const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
994
destination.append(",\n", 2);
996
result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1002
destination.append("\n)", 2);
1004
/* Add ENGINE = " clause */
1005
if (table.has_engine())
1007
destination.append(" ENGINE=", 8);
1008
destination.append(table.engine().name());
1010
size_t num_engine_options= table.engine().options_size();
1011
if (num_engine_options > 0)
1012
destination.append(" ", 1);
1013
for (size_t x= 0; x < num_engine_options; ++x)
1015
const Engine::Option &option= table.engine().options(x);
1016
destination.append(option.name());
1017
destination.append("='", 2);
1018
destination.append(option.state());
1019
destination.append("'", 1);
1020
if(x != num_engine_options-1)
1021
destination.append(", ", 2);
1025
if (table.has_options())
1026
(void) transformTableOptionsToSql(table.options(), destination, sql_variant);
1031
enum TransformSqlError
1032
transformTableOptionsToSql(const Table::TableOptions &options,
1033
string &destination,
1034
enum TransformSqlVariant sql_variant)
1036
if (sql_variant == ANSI)
1037
return NONE; /* ANSI does not support table options... */
1041
if (options.has_comment())
1043
destination.append(" COMMENT=", 9);
1044
append_escaped_string(&destination, options.comment());
1047
if (options.has_collation())
1049
destination.append(" COLLATE = ", 11);
1050
destination.append(options.collation());
1053
if (options.has_data_file_name())
1055
destination.append("\nDATA_FILE_NAME = '", 19);
1056
destination.append(options.data_file_name());
1057
destination.push_back('\'');
1060
if (options.has_index_file_name())
1062
destination.append("\nINDEX_FILE_NAME = '", 20);
1063
destination.append(options.index_file_name());
1064
destination.push_back('\'');
1067
if (options.has_max_rows())
1069
ss << options.max_rows();
1070
destination.append("\nMAX_ROWS = ", 12);
1071
destination.append(ss.str());
1075
if (options.has_min_rows())
1077
ss << options.min_rows();
1078
destination.append("\nMIN_ROWS = ", 12);
1079
destination.append(ss.str());
1083
if (options.has_user_set_auto_increment_value()
1084
&& options.has_auto_increment_value())
1086
ss << options.auto_increment_value();
1087
destination.append(" AUTO_INCREMENT=", 16);
1088
destination.append(ss.str());
1092
if (options.has_avg_row_length())
1094
ss << options.avg_row_length();
1095
destination.append("\nAVG_ROW_LENGTH = ", 18);
1096
destination.append(ss.str());
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())
1164
destination.push_back('(');
1165
ss << part.compare_length();
1166
destination.append(ss.str());
1167
destination.push_back(')');
1172
destination.push_back(')');
1174
switch (index.type())
1176
case Table::Index::UNKNOWN_INDEX:
1178
case Table::Index::BTREE:
1179
destination.append(" USING BTREE", 12);
1181
case Table::Index::RTREE:
1182
destination.append(" USING RTREE", 12);
1184
case Table::Index::HASH:
1185
destination.append(" USING HASH", 11);
1187
case Table::Index::FULLTEXT:
1188
destination.append(" USING FULLTEXT", 15);
1192
if (index.has_comment())
1194
destination.append(" COMMENT ", 9);
1195
append_escaped_string(&destination, index.comment());
1201
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
1205
case Table::ForeignKeyConstraint::OPTION_UNDEF:
1207
case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1208
destination.append("RESTRICT");
1210
case Table::ForeignKeyConstraint::OPTION_CASCADE:
1211
destination.append("CASCADE");
1213
case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1214
destination.append("SET NULL");
1216
case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1217
destination.append("NO ACTION");
1219
case Table::ForeignKeyConstraint::OPTION_DEFAULT:
1220
destination.append("SET DEFAULT");
1225
enum TransformSqlError
1226
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
1228
string &destination,
1229
enum TransformSqlVariant sql_variant)
1231
char quoted_identifier= '`';
1232
if (sql_variant == ANSI)
1233
quoted_identifier= '"';
1235
destination.append(" ", 2);
1237
if (fkey.has_name())
1239
destination.append("CONSTRAINT ", 11);
1240
append_escaped_string(&destination, fkey.name(), quoted_identifier);
1241
destination.append(" ", 1);
1244
destination.append("FOREIGN KEY (", 13);
1246
for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1249
destination.append(", ");
1251
append_escaped_string(&destination, fkey.column_names(x),
1255
destination.append(") REFERENCES ", 13);
1257
append_escaped_string(&destination, fkey.references_table_name(),
1259
destination.append(" (", 2);
1261
for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1264
destination.append(", ");
1266
append_escaped_string(&destination, fkey.references_columns(x),
1270
destination.push_back(')');
1272
if (fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1274
destination.append(" ON UPDATE ", 11);
1275
transformForeignKeyOptionToSql(fkey.update_option(), destination);
1278
if (fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1280
destination.append(" ON DELETE ", 11);
1281
transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1287
enum TransformSqlError
1288
transformFieldDefinitionToSql(const Table::Field &field,
1289
string &destination,
1290
enum TransformSqlVariant sql_variant)
1292
char quoted_identifier= '`';
1293
char quoted_default;
1295
if (sql_variant == ANSI)
1296
quoted_identifier= '"';
1298
if (sql_variant == DRIZZLE)
1299
quoted_default= '\'';
1301
quoted_default= quoted_identifier;
1303
append_escaped_string(&destination, field.name(), quoted_identifier);
1305
Table::Field::FieldType field_type= field.type();
1309
case Table::Field::DOUBLE:
1310
destination.append(" DOUBLE", 7);
1311
if (field.has_numeric_options()
1312
&& field.numeric_options().has_precision())
1315
ss << "(" << field.numeric_options().precision() << ",";
1316
ss << field.numeric_options().scale() << ")";
1317
destination.append(ss.str());
1320
case Table::Field::VARCHAR:
1322
if (field.string_options().has_collation()
1323
&& field.string_options().collation().compare("binary") == 0)
1324
destination.append(" VARBINARY(", 11);
1326
destination.append(" VARCHAR(", 9);
1329
ss << field.string_options().length() << ")";
1330
destination.append(ss.str());
1333
case Table::Field::BLOB:
1335
if (field.string_options().has_collation()
1336
&& field.string_options().collation().compare("binary") == 0)
1337
destination.append(" BLOB", 5);
1339
destination.append(" TEXT", 5);
1342
case Table::Field::ENUM:
1344
size_t num_field_values= field.enumeration_values().field_value_size();
1345
destination.append(" ENUM(", 6);
1346
for (size_t x= 0; x < num_field_values; ++x)
1348
const string &type= field.enumeration_values().field_value(x);
1351
destination.push_back(',');
1353
destination.push_back('\'');
1354
destination.append(type);
1355
destination.push_back('\'');
1357
destination.push_back(')');
1360
case Table::Field::INTEGER:
1361
destination.append(" INT", 4);
1363
case Table::Field::BIGINT:
1364
destination.append(" BIGINT", 7);
1366
case Table::Field::DECIMAL:
1368
destination.append(" DECIMAL(", 9);
1370
ss << field.numeric_options().precision() << ",";
1371
ss << field.numeric_options().scale() << ")";
1372
destination.append(ss.str());
1375
case Table::Field::DATE:
1376
destination.append(" DATE", 5);
1378
case Table::Field::TIMESTAMP:
1379
destination.append(" TIMESTAMP", 10);
1381
case Table::Field::DATETIME:
1382
destination.append(" DATETIME", 9);
1386
if (field.type() == Table::Field::INTEGER ||
1387
field.type() == Table::Field::BIGINT)
1389
if (field.has_constraints() &&
1390
field.constraints().has_is_unsigned() &&
1391
field.constraints().is_unsigned())
1393
destination.append(" UNSIGNED", 9);
1397
if (field.type() == Table::Field::BLOB ||
1398
field.type() == Table::Field::VARCHAR)
1400
if (field.string_options().has_collation()
1401
&& field.string_options().collation().compare("binary"))
1403
destination.append(" COLLATE ", 9);
1404
destination.append(field.string_options().collation());
1408
if (field.has_constraints() &&
1409
! field.constraints().is_nullable())
1411
destination.append(" NOT NULL", 9);
1413
else if (field.type() == Table::Field::TIMESTAMP)
1414
destination.append(" NULL", 5);
1416
if (field.type() == Table::Field::INTEGER ||
1417
field.type() == Table::Field::BIGINT)
1419
/* AUTO_INCREMENT must be after NOT NULL */
1420
if (field.has_numeric_options() &&
1421
field.numeric_options().is_autoincrement())
1423
destination.append(" AUTO_INCREMENT", 15);
1427
if (field.options().has_default_value())
1429
destination.append(" DEFAULT ", 9);
1430
append_escaped_string(&destination, field.options().default_value());
1432
else if (field.options().has_default_expression())
1434
destination.append(" DEFAULT ", 9);
1435
destination.append(field.options().default_expression());
1437
else if (field.options().has_default_bin_value())
1439
const string &v= field.options().default_bin_value();
1440
if (v.length() == 0)
1441
destination.append(" DEFAULT ''", 11);
1444
destination.append(" DEFAULT 0x", 11);
1445
for (size_t x= 0; x < v.length(); x++)
1448
snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
1449
destination.append(hex, 2);
1453
else if (field.options().has_default_null()
1454
&& field.options().default_null()
1455
&& field.type() != Table::Field::BLOB)
1457
destination.append(" DEFAULT NULL", 13);
1460
if (field.has_options() && field.options().has_update_expression())
1462
destination.append(" ON UPDATE ", 11);
1463
destination.append(field.options().update_expression());
1466
if (field.has_comment())
1468
destination.append(" COMMENT ", 9);
1469
append_escaped_string(&destination, field.comment(), quoted_default);
1474
bool shouldQuoteFieldValue(Table::Field::FieldType in_type)
1478
case Table::Field::DOUBLE:
1479
case Table::Field::DECIMAL:
1480
case Table::Field::INTEGER:
1481
case Table::Field::BIGINT:
1488
Table::Field::FieldType internalFieldTypeToFieldProtoType(enum enum_field_types type)
1491
case DRIZZLE_TYPE_LONG:
1492
return Table::Field::INTEGER;
1493
case DRIZZLE_TYPE_DOUBLE:
1494
return Table::Field::DOUBLE;
1495
case DRIZZLE_TYPE_NULL:
1496
assert(false); /* Not a user definable type */
1497
return Table::Field::INTEGER; /* unreachable */
1498
case DRIZZLE_TYPE_TIMESTAMP:
1499
return Table::Field::TIMESTAMP;
1500
case DRIZZLE_TYPE_LONGLONG:
1501
return Table::Field::BIGINT;
1502
case DRIZZLE_TYPE_DATETIME:
1503
return Table::Field::DATETIME;
1504
case DRIZZLE_TYPE_DATE:
1505
return Table::Field::DATE;
1506
case DRIZZLE_TYPE_VARCHAR:
1507
return Table::Field::VARCHAR;
1508
case DRIZZLE_TYPE_DECIMAL:
1509
return Table::Field::DECIMAL;
1510
case DRIZZLE_TYPE_ENUM:
1511
return Table::Field::ENUM;
1512
case DRIZZLE_TYPE_BLOB:
1513
return Table::Field::BLOB;
1517
return Table::Field::INTEGER; /* unreachable */
1520
bool transactionContainsBulkSegment(const Transaction &transaction)
1522
size_t num_statements= transaction.statement_size();
1523
if (num_statements == 0)
1527
* Only INSERT, UPDATE, and DELETE statements can possibly
1528
* have bulk segments. So, we loop through the statements
1529
* checking for segment_id > 1 in those specific submessages.
1532
for (x= 0; x < num_statements; ++x)
1534
const Statement &statement= transaction.statement(x);
1535
Statement::Type type= statement.type();
1539
case Statement::INSERT:
1540
if (statement.insert_data().segment_id() > 1)
1543
case Statement::UPDATE:
1544
if (statement.update_data().segment_id() > 1)
1547
case Statement::DELETE:
1548
if (statement.delete_data().segment_id() > 1)
1558
} /* namespace message */
1559
} /* namespace drizzled */