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
51
enum TransformSqlError
121
52
transformStatementToSql(const Statement &source,
122
53
vector<string> &sql_strings,
412
324
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());
326
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
423
328
if (should_quote_field_value)
424
329
destination.push_back('\'');
426
if (record.is_null(x))
331
if (field_metadata.type() == Table::Field::BLOB)
428
destination.append("NULL");
334
* We do this here because BLOB data is returned
335
* in a string correctly, but calling append()
336
* without a length will result in only the string
337
* up to a \0 being output here.
339
string raw_data(record.insert_value(x));
340
destination.append(raw_data.c_str(), raw_data.size());
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);
344
destination.append(record.insert_value(x));
451
347
if (should_quote_field_value)
574
468
destination.push_back(quoted_identifier);
575
469
destination.push_back('=');
577
if (record.is_null(x))
579
should_quote_field_value= false;
583
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
471
should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
586
473
if (should_quote_field_value)
587
474
destination.push_back('\'');
589
if (record.is_null(x))
476
if (field_metadata.type() == Table::Field::BLOB)
591
destination.append("NULL");
479
* We do this here because BLOB data is returned
480
* in a string correctly, but calling append()
481
* without a length will result in only the string
482
* up to a \0 being output here.
484
string raw_data(record.after_value(x));
485
destination.append(raw_data.c_str(), raw_data.size());
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);
489
destination.append(record.after_value(x));
614
492
if (should_quote_field_value)
818
692
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
693
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
851
694
string &destination,
852
695
enum TransformSqlVariant sql_variant)
983
826
if (sql_variant == ANSI)
984
827
quoted_identifier= '"';
986
destination.append("CREATE ");
829
destination.append("CREATE ", 7);
988
831
if (table.type() == Table::TEMPORARY)
989
destination.append("TEMPORARY ");
832
destination.append("TEMPORARY ", 10);
991
destination.append("TABLE ");
834
destination.append("TABLE ", 6);
994
append_escaped_string(&destination, table.schema(), quoted_identifier);
837
destination.push_back(quoted_identifier);
838
destination.append(table.schema());
839
destination.push_back(quoted_identifier);
995
840
destination.push_back('.');
997
append_escaped_string(&destination, table.name(), quoted_identifier);
998
destination.append(" (\n");
842
destination.push_back(quoted_identifier);
843
destination.append(table.name());
844
destination.push_back(quoted_identifier);
845
destination.append(" (\n", 3);
1000
847
enum TransformSqlError result= NONE;
1001
848
size_t num_fields= table.field_size();
1017
862
size_t num_indexes= table.indexes_size();
1019
864
if (num_indexes > 0)
1020
destination.append(",\n");
865
destination.append(",\n", 2);
1022
867
for (size_t x= 0; x < num_indexes; ++x)
1024
869
const message::Table::Index &index= table.indexes(x);
1027
destination.append(",\n");
872
destination.append(",\n", 2);
1029
874
result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
1031
876
if (result != NONE)
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)");
879
destination.append("\n)", 2);
1055
881
/* Add ENGINE = " clause */
1056
882
if (table.has_engine())
1058
destination.append(" ENGINE=");
884
destination.append("\nENGINE = ", 10);
1059
885
destination.append(table.engine().name());
1061
887
size_t num_engine_options= table.engine().options_size();
1062
if (num_engine_options > 0)
1063
destination.append(" ", 1);
1064
888
for (size_t x= 0; x < num_engine_options; ++x)
1066
890
const Engine::Option &option= table.engine().options(x);
891
destination.push_back('\n');
1067
892
destination.append(option.name());
1068
destination.append("='");
893
destination.append(" = ", 3);
1069
894
destination.append(option.state());
1070
destination.append("'");
1071
if (x != num_engine_options-1)
1073
destination.append(", ");
895
destination.push_back('\n');
1089
910
if (sql_variant == ANSI)
1090
911
return NONE; /* ANSI does not support table options... */
1092
915
if (options.has_comment())
1094
destination.append(" COMMENT=");
1095
append_escaped_string(&destination, options.comment());
917
destination.append("\nCOMMENT = '", 12);
918
destination.append(options.comment());
919
destination.push_back('\'');
1098
922
if (options.has_collation())
1100
destination.append(" COLLATE = ");
924
destination.append("\nCOLLATE = ", 11);
1101
925
destination.append(options.collation());
928
if (options.has_auto_increment())
930
ss << options.auto_increment();
931
destination.append("\nAUTOINCREMENT_OFFSET = ", 24);
932
destination.append(ss.str());
936
if (options.has_row_type())
938
ss << options.row_type();
939
destination.append("\nROW_TYPE = ", 12);
940
destination.append(ss.str());
1104
944
if (options.has_data_file_name())
1106
destination.append("\nDATA_FILE_NAME = '");
946
destination.append("\nDATA_FILE_NAME = '", 19);
1107
947
destination.append(options.data_file_name());
1108
948
destination.push_back('\'');
1111
951
if (options.has_index_file_name())
1113
destination.append("\nINDEX_FILE_NAME = '");
953
destination.append("\nINDEX_FILE_NAME = '", 20);
1114
954
destination.append(options.index_file_name());
1115
955
destination.push_back('\'');
1118
958
if (options.has_max_rows())
1120
destination.append("\nMAX_ROWS = ");
1121
destination.append(boost::lexical_cast<string>(options.max_rows()));
960
ss << options.max_rows();
961
destination.append("\nMAX_ROWS = ", 12);
962
destination.append(ss.str());
1124
966
if (options.has_min_rows())
1126
destination.append("\nMIN_ROWS = ");
1127
destination.append(boost::lexical_cast<string>(options.min_rows()));
968
ss << options.min_rows();
969
destination.append("\nMIN_ROWS = ", 12);
970
destination.append(ss.str());
1130
if (options.has_user_set_auto_increment_value()
1131
&& options.has_auto_increment_value())
974
if (options.has_auto_increment_value())
1133
destination.append(" AUTO_INCREMENT=");
1134
destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
976
ss << options.auto_increment_value();
977
destination.append("\nAUTO_INCREMENT = ", 18);
978
destination.append(ss.str());
1137
982
if (options.has_avg_row_length())
1139
destination.append("\nAVG_ROW_LENGTH = ");
1140
destination.append(boost::lexical_cast<string>(options.avg_row_length()));
984
ss << options.avg_row_length();
985
destination.append("\nAVG_ROW_LENGTH = ", 18);
986
destination.append(ss.str());
1143
990
if (options.has_checksum() &&
1144
991
options.checksum())
1145
destination.append("\nCHECKSUM = TRUE");
992
destination.append("\nCHECKSUM = TRUE", 16);
1146
993
if (options.has_page_checksum() &&
1147
994
options.page_checksum())
1148
destination.append("\nPAGE_CHECKSUM = TRUE");
995
destination.append("\nPAGE_CHECKSUM = TRUE", 21);
1160
1007
if (sql_variant == ANSI)
1161
1008
quoted_identifier= '"';
1163
destination.append(" ", 2);
1165
1010
if (index.is_primary())
1166
destination.append("PRIMARY ");
1011
destination.append("PRIMARY ", 8);
1167
1012
else if (index.is_unique())
1168
destination.append("UNIQUE ");
1013
destination.append("UNIQUE ", 7);
1170
1015
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);
1016
destination.push_back(quoted_identifier);
1017
destination.append(index.name());
1018
destination.push_back(quoted_identifier);
1019
destination.append(" (", 2);
1181
1021
size_t num_parts= index.index_part_size();
1182
1022
for (size_t x= 0; x < num_parts; ++x)
1213
1062
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);
1330
1070
enum TransformSqlVariant sql_variant)
1332
1072
char quoted_identifier= '`';
1333
char quoted_default;
1335
1073
if (sql_variant == ANSI)
1336
1074
quoted_identifier= '"';
1338
if (sql_variant == DRIZZLE)
1339
quoted_default= '\'';
1341
quoted_default= quoted_identifier;
1343
append_escaped_string(&destination, field.name(), quoted_identifier);
1076
destination.push_back(quoted_identifier);
1077
destination.append(field.name());
1078
destination.push_back(quoted_identifier);
1345
1080
Table::Field::FieldType field_type= field.type();
1347
1082
switch (field_type)
1349
1084
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());
1085
destination.append(" DOUBLE", 7);
1360
1087
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(")");
1089
destination.append(" VARCHAR(", 9);
1091
ss << field.string_options().length() << ")";
1092
destination.append(ss.str());
1372
1095
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");
1096
destination.append(" BLOB", 5);
1381
1098
case Table::Field::ENUM:
1383
1100
size_t num_field_values= field.enumeration_values().field_value_size();
1384
destination.append(" ENUM(");
1101
destination.append(" ENUM(", 6);
1385
1102
for (size_t x= 0; x < num_field_values; ++x)
1387
1104
const string &type= field.enumeration_values().field_value(x);
1396
1113
destination.push_back(')');
1399
case Table::Field::UUID:
1400
destination.append(" UUID");
1402
case Table::Field::BOOLEAN:
1403
destination.append(" BOOLEAN");
1405
1116
case Table::Field::INTEGER:
1406
destination.append(" INT");
1117
destination.append(" INT", 4);
1408
1119
case Table::Field::BIGINT:
1409
if (field.has_constraints() and
1410
field.constraints().is_unsigned())
1412
destination.append(" BIGINT UNSIGNED");
1416
destination.append(" BIGINT");
1120
destination.append(" BIGINT", 7);
1419
1122
case Table::Field::DECIMAL:
1421
destination.append(" DECIMAL(");
1124
destination.append(" DECIMAL(", 9);
1422
1125
stringstream ss;
1423
1126
ss << field.numeric_options().precision() << ",";
1424
1127
ss << field.numeric_options().scale() << ")";
1428
1131
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");
1132
destination.append(" DATE", 5);
1134
case Table::Field::TIMESTAMP:
1135
destination.append(" TIMESTAMP", 10);
1443
1137
case Table::Field::DATETIME:
1444
destination.append(" DATETIME");
1446
case Table::Field::TIME:
1447
destination.append(" TIME");
1138
destination.append(" DATETIME", 9);
1142
if (field.type() == Table::Field::INTEGER ||
1143
field.type() == Table::Field::BIGINT)
1145
if (field.has_constraints() &&
1146
field.constraints().has_is_unsigned() &&
1147
field.constraints().is_unsigned())
1149
destination.append(" UNSIGNED", 9);
1154
if (! (field.has_constraints() &&
1155
field.constraints().is_nullable()))
1157
destination.append(" NOT", 4);
1159
destination.append(" NULL", 5);
1161
if (field.type() == Table::Field::INTEGER ||
1162
field.type() == Table::Field::BIGINT)
1164
/* AUTO_INCREMENT must be after NOT NULL */
1165
if (field.has_numeric_options() &&
1166
field.numeric_options().is_autoincrement())
1168
destination.append(" AUTO_INCREMENT", 15);
1451
1172
if (field.type() == Table::Field::BLOB ||
1452
1173
field.type() == Table::Field::VARCHAR)
1454
if (field.string_options().has_collation()
1455
&& field.string_options().collation().compare("binary"))
1175
if (field.string_options().has_collation())
1457
destination.append(" COLLATE ");
1177
destination.append(" COLLATE ", 9);
1458
1178
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
1182
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())
1184
destination.append(" DEFAULT ", 9);
1185
destination.push_back(quoted_identifier);
1186
destination.append(field.options().default_value());
1187
destination.push_back(quoted_identifier);
1190
if (field.options().has_default_bin_value())
1499
1192
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");
1193
destination.append(" DEFAULT 0x", 11);
1194
for (size_t x= 0; x < v.length(); x++)
1196
printf("%.2x", *(v.c_str() + x));
1522
if (field.has_options() && field.options().has_update_expression())
1524
destination.append(" ON UPDATE ");
1525
destination.append(field.options().update_expression());
1200
if (field.type() == Table::Field::TIMESTAMP)
1201
if (field.timestamp_options().has_auto_updates() &&
1202
field.timestamp_options().auto_updates())
1203
destination.append(" ON UPDATE CURRENT_TIMESTAMP", 28);
1528
1205
if (field.has_comment())
1530
destination.append(" COMMENT ");
1531
append_escaped_string(&destination, field.comment(), quoted_default);
1207
destination.append(" COMMENT ", 9);
1208
destination.push_back(quoted_identifier);
1209
destination.append(field.comment());
1210
destination.push_back(quoted_identifier);