00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00032 #include <config.h>
00033
00034 #include <boost/lexical_cast.hpp>
00035
00036 #include <drizzled/charset.h>
00037 #include <drizzled/message.h>
00038 #include <drizzled/message/statement_transform.h>
00039 #include <drizzled/message/transaction.pb.h>
00040 #include <drizzled/message/access.h>
00041
00042 #include <string>
00043 #include <vector>
00044 #include <sstream>
00045 #include <cstdio>
00046
00047 using namespace std;
00048
00049 namespace drizzled
00050 {
00051
00052 namespace message
00053 {
00054
00055 static void escapeEmbeddedQuotes(string &s, const char quote='\'')
00056 {
00057 string::iterator it;
00058
00059 for (it= s.begin(); it != s.end(); ++it)
00060 {
00061 if (*it == quote)
00062 {
00063 it= s.insert(it, quote);
00064 ++it;
00065 }
00066 }
00067 }
00068
00069
00070 static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
00071 {
00072 const char *pos= input.c_str();
00073 const char *end= input.c_str()+input.length();
00074 res->push_back(quote);
00075
00076 for (; pos != end ; pos++)
00077 {
00078 uint32_t mblen;
00079 if (use_mb(default_charset_info) &&
00080 (mblen= my_ismbchar(default_charset_info, pos, end)))
00081 {
00082 res->append(pos, mblen);
00083 pos+= mblen - 1;
00084 if (pos >= end)
00085 break;
00086 continue;
00087 }
00088
00089 switch (*pos) {
00090 case 0:
00091 res->push_back('\\');
00092 res->push_back('0');
00093 break;
00094 case '\n':
00095 res->push_back('\\');
00096 res->push_back('n');
00097 break;
00098 case '\r':
00099 res->push_back('\\');
00100 res->push_back('r');
00101 break;
00102 case '\\':
00103 res->push_back('\\');
00104 res->push_back('\\');
00105 break;
00106 default:
00107 if (*pos == quote)
00108 {
00109 res->push_back(quote);
00110 res->push_back(quote);
00111 }
00112 else
00113 res->push_back(*pos);
00114 break;
00115 }
00116 }
00117 res->push_back(quote);
00118 }
00119
00120 enum TransformSqlError
00121 transformStatementToSql(const Statement &source,
00122 vector<string> &sql_strings,
00123 enum TransformSqlVariant sql_variant,
00124 bool already_in_transaction)
00125 {
00126 TransformSqlError error= NONE;
00127
00128 switch (source.type())
00129 {
00130 case Statement::ROLLBACK_STATEMENT:
00131 {
00132 break;
00133 }
00134 case Statement::ROLLBACK:
00135 {
00136 sql_strings.push_back("ROLLBACK");
00137 break;
00138 }
00139 case Statement::INSERT:
00140 {
00141 if (! source.has_insert_header())
00142 {
00143 error= MISSING_HEADER;
00144 return error;
00145 }
00146 if (! source.has_insert_data())
00147 {
00148 error= MISSING_DATA;
00149 return error;
00150 }
00151
00152 const InsertHeader &insert_header= source.insert_header();
00153 const InsertData &insert_data= source.insert_data();
00154 size_t num_keys= insert_data.record_size();
00155
00156 if (num_keys > 1 && ! already_in_transaction)
00157 sql_strings.push_back("START TRANSACTION");
00158
00159 for (size_t x= 0; x < num_keys; ++x)
00160 {
00161 string destination;
00162
00163 error= transformInsertRecordToSql(insert_header,
00164 insert_data.record(x),
00165 destination,
00166 sql_variant);
00167 if (error != NONE)
00168 break;
00169
00170 sql_strings.push_back(destination);
00171 }
00172
00173 if (num_keys > 1 && ! already_in_transaction)
00174 {
00175 if (error == NONE)
00176 sql_strings.push_back("COMMIT");
00177 else
00178 sql_strings.push_back("ROLLBACK");
00179 }
00180 }
00181 break;
00182 case Statement::UPDATE:
00183 {
00184 if (! source.has_update_header())
00185 {
00186 error= MISSING_HEADER;
00187 return error;
00188 }
00189 if (! source.has_update_data())
00190 {
00191 error= MISSING_DATA;
00192 return error;
00193 }
00194
00195 const UpdateHeader &update_header= source.update_header();
00196 const UpdateData &update_data= source.update_data();
00197 size_t num_keys= update_data.record_size();
00198 size_t x;
00199
00200 if (num_keys > 1 && ! already_in_transaction)
00201 sql_strings.push_back("START TRANSACTION");
00202
00203 for (x= 0; x < num_keys; ++x)
00204 {
00205 string destination;
00206
00207 error= transformUpdateRecordToSql(update_header,
00208 update_data.record(x),
00209 destination,
00210 sql_variant);
00211 if (error != NONE)
00212 break;
00213
00214 sql_strings.push_back(destination);
00215 }
00216
00217 if (num_keys > 1 && ! already_in_transaction)
00218 {
00219 if (error == NONE)
00220 sql_strings.push_back("COMMIT");
00221 else
00222 sql_strings.push_back("ROLLBACK");
00223 }
00224 }
00225 break;
00226 case Statement::DELETE:
00227 {
00228 if (! source.has_delete_header())
00229 {
00230 error= MISSING_HEADER;
00231 return error;
00232 }
00233 if (! source.has_delete_data())
00234 {
00235 error= MISSING_DATA;
00236 return error;
00237 }
00238
00239 const DeleteHeader &delete_header= source.delete_header();
00240 const DeleteData &delete_data= source.delete_data();
00241 size_t num_keys= delete_data.record_size();
00242 size_t x;
00243
00244 if (num_keys > 1 && ! already_in_transaction)
00245 sql_strings.push_back("START TRANSACTION");
00246
00247 for (x= 0; x < num_keys; ++x)
00248 {
00249 string destination;
00250
00251 error= transformDeleteRecordToSql(delete_header,
00252 delete_data.record(x),
00253 destination,
00254 sql_variant);
00255 if (error != NONE)
00256 break;
00257
00258 sql_strings.push_back(destination);
00259 }
00260
00261 if (num_keys > 1 && ! already_in_transaction)
00262 {
00263 if (error == NONE)
00264 sql_strings.push_back("COMMIT");
00265 else
00266 sql_strings.push_back("ROLLBACK");
00267 }
00268 }
00269 break;
00270 case Statement::CREATE_TABLE:
00271 {
00272 assert(source.has_create_table_statement());
00273 string destination;
00274 error= transformCreateTableStatementToSql(source.create_table_statement(),
00275 destination,
00276 sql_variant);
00277 sql_strings.push_back(destination);
00278 }
00279 break;
00280 case Statement::TRUNCATE_TABLE:
00281 {
00282 assert(source.has_truncate_table_statement());
00283 string destination;
00284 error= transformTruncateTableStatementToSql(source.truncate_table_statement(),
00285 destination,
00286 sql_variant);
00287 sql_strings.push_back(destination);
00288 }
00289 break;
00290 case Statement::DROP_TABLE:
00291 {
00292 assert(source.has_drop_table_statement());
00293 string destination;
00294 error= transformDropTableStatementToSql(source.drop_table_statement(),
00295 destination,
00296 sql_variant);
00297 sql_strings.push_back(destination);
00298 }
00299 break;
00300 case Statement::CREATE_SCHEMA:
00301 {
00302 assert(source.has_create_schema_statement());
00303 string destination;
00304 error= transformCreateSchemaStatementToSql(source.create_schema_statement(),
00305 destination,
00306 sql_variant);
00307 sql_strings.push_back(destination);
00308 }
00309 break;
00310 case Statement::DROP_SCHEMA:
00311 {
00312 assert(source.has_drop_schema_statement());
00313 string destination;
00314 error= transformDropSchemaStatementToSql(source.drop_schema_statement(),
00315 destination,
00316 sql_variant);
00317 sql_strings.push_back(destination);
00318 }
00319 break;
00320 case Statement::ALTER_SCHEMA:
00321 {
00322 assert(source.has_alter_schema_statement());
00323 string destination;
00324 error= transformAlterSchemaStatementToSql(source.alter_schema_statement(),
00325 destination,
00326 sql_variant);
00327 sql_strings.push_back(destination);
00328 }
00329 break;
00330 case Statement::SET_VARIABLE:
00331 {
00332 assert(source.has_set_variable_statement());
00333 string destination;
00334 error= transformSetVariableStatementToSql(source.set_variable_statement(),
00335 destination,
00336 sql_variant);
00337 sql_strings.push_back(destination);
00338 }
00339 break;
00340 case Statement::RAW_SQL:
00341 {
00342 if (source.has_raw_sql_schema())
00343 {
00344 string destination("USE ");
00345 destination.append(source.raw_sql_schema());
00346 sql_strings.push_back(destination);
00347 }
00348 sql_strings.push_back(source.sql());
00349 }
00350 break;
00351 default:
00352 sql_strings.push_back(source.sql());
00353 break;
00354 }
00355 return error;
00356 }
00357
00358 enum TransformSqlError
00359 transformInsertHeaderToSql(const InsertHeader &header,
00360 string &destination,
00361 enum TransformSqlVariant sql_variant)
00362 {
00363 char quoted_identifier= '`';
00364 if (sql_variant == ANSI)
00365 quoted_identifier= '"';
00366
00367 destination.assign("INSERT INTO ", 12);
00368 destination.push_back(quoted_identifier);
00369 destination.append(header.table_metadata().schema_name());
00370 destination.push_back(quoted_identifier);
00371 destination.push_back('.');
00372 destination.push_back(quoted_identifier);
00373 destination.append(header.table_metadata().table_name());
00374 destination.push_back(quoted_identifier);
00375 destination.append(" (", 2);
00376
00377
00378 size_t num_fields= header.field_metadata_size();
00379 size_t x;
00380
00381 for (x= 0; x < num_fields; ++x)
00382 {
00383 const FieldMetadata &field_metadata= header.field_metadata(x);
00384 if (x != 0)
00385 destination.push_back(',');
00386
00387 destination.push_back(quoted_identifier);
00388 destination.append(field_metadata.name());
00389 destination.push_back(quoted_identifier);
00390 }
00391
00392 return NONE;
00393 }
00394
00395 enum TransformSqlError
00396 transformInsertRecordToSql(const InsertHeader &header,
00397 const InsertRecord &record,
00398 string &destination,
00399 enum TransformSqlVariant sql_variant)
00400 {
00401 enum TransformSqlError error= transformInsertHeaderToSql(header,
00402 destination,
00403 sql_variant);
00404
00405 destination.append(") VALUES (");
00406
00407
00408 size_t num_fields= header.field_metadata_size();
00409 size_t x;
00410 bool should_quote_field_value= false;
00411
00412 for (x= 0; x < num_fields; ++x)
00413 {
00414 if (x != 0)
00415 destination.push_back(',');
00416
00417 const FieldMetadata &field_metadata= header.field_metadata(x);
00418
00419 if (record.is_null(x))
00420 {
00421 should_quote_field_value= false;
00422 }
00423 else
00424 {
00425 should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
00426 }
00427
00428 if (should_quote_field_value)
00429 destination.push_back('\'');
00430
00431 if (record.is_null(x))
00432 {
00433 destination.append("NULL");
00434 }
00435 else
00436 {
00437 if (field_metadata.type() == Table::Field::BLOB)
00438 {
00439
00440
00441
00442
00443
00444
00445 string raw_data(record.insert_value(x));
00446 destination.append(raw_data.c_str(), raw_data.size());
00447 }
00448 else
00449 {
00450 string tmp(record.insert_value(x));
00451 escapeEmbeddedQuotes(tmp);
00452 destination.append(tmp);
00453 }
00454 }
00455
00456 if (should_quote_field_value)
00457 destination.push_back('\'');
00458 }
00459 destination.push_back(')');
00460
00461 return error;
00462 }
00463
00464 enum TransformSqlError
00465 transformInsertStatementToSql(const InsertHeader &header,
00466 const InsertData &data,
00467 string &destination,
00468 enum TransformSqlVariant sql_variant)
00469 {
00470 enum TransformSqlError error= transformInsertHeaderToSql(header,
00471 destination,
00472 sql_variant);
00473
00474 destination.append(") VALUES (", 10);
00475
00476
00477 size_t num_records= data.record_size();
00478 size_t num_fields= header.field_metadata_size();
00479 size_t x, y;
00480 bool should_quote_field_value= false;
00481
00482 for (x= 0; x < num_records; ++x)
00483 {
00484 if (x != 0)
00485 destination.append("),(", 3);
00486
00487 for (y= 0; y < num_fields; ++y)
00488 {
00489 if (y != 0)
00490 destination.push_back(',');
00491
00492 const FieldMetadata &field_metadata= header.field_metadata(y);
00493
00494 should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
00495
00496 if (should_quote_field_value)
00497 destination.push_back('\'');
00498
00499 if (field_metadata.type() == Table::Field::BLOB)
00500 {
00501
00502
00503
00504
00505
00506
00507 string raw_data(data.record(x).insert_value(y));
00508 destination.append(raw_data.c_str(), raw_data.size());
00509 }
00510 else
00511 {
00512 string tmp(data.record(x).insert_value(y));
00513 escapeEmbeddedQuotes(tmp);
00514 destination.append(tmp);
00515 }
00516
00517 if (should_quote_field_value)
00518 destination.push_back('\'');
00519 }
00520 }
00521 destination.push_back(')');
00522
00523 return error;
00524 }
00525
00526 enum TransformSqlError
00527 transformUpdateHeaderToSql(const UpdateHeader &header,
00528 string &destination,
00529 enum TransformSqlVariant sql_variant)
00530 {
00531 char quoted_identifier= '`';
00532 if (sql_variant == ANSI)
00533 quoted_identifier= '"';
00534
00535 destination.assign("UPDATE ", 7);
00536 destination.push_back(quoted_identifier);
00537 destination.append(header.table_metadata().schema_name());
00538 destination.push_back(quoted_identifier);
00539 destination.push_back('.');
00540 destination.push_back(quoted_identifier);
00541 destination.append(header.table_metadata().table_name());
00542 destination.push_back(quoted_identifier);
00543 destination.append(" SET ", 5);
00544
00545 return NONE;
00546 }
00547
00548 enum TransformSqlError
00549 transformUpdateRecordToSql(const UpdateHeader &header,
00550 const UpdateRecord &record,
00551 string &destination,
00552 enum TransformSqlVariant sql_variant)
00553 {
00554 enum TransformSqlError error= transformUpdateHeaderToSql(header,
00555 destination,
00556 sql_variant);
00557
00558 char quoted_identifier= '`';
00559 if (sql_variant == ANSI)
00560 quoted_identifier= '"';
00561
00562
00563 size_t num_set_fields= header.set_field_metadata_size();
00564 size_t x;
00565 bool should_quote_field_value= false;
00566
00567 for (x= 0; x < num_set_fields; ++x)
00568 {
00569 const FieldMetadata &field_metadata= header.set_field_metadata(x);
00570 if (x != 0)
00571 destination.push_back(',');
00572
00573 destination.push_back(quoted_identifier);
00574 destination.append(field_metadata.name());
00575 destination.push_back(quoted_identifier);
00576 destination.push_back('=');
00577
00578 if (record.is_null(x))
00579 {
00580 should_quote_field_value= false;
00581 }
00582 else
00583 {
00584 should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
00585 }
00586
00587 if (should_quote_field_value)
00588 destination.push_back('\'');
00589
00590 if (record.is_null(x))
00591 {
00592 destination.append("NULL");
00593 }
00594 else
00595 {
00596 if (field_metadata.type() == Table::Field::BLOB)
00597 {
00598
00599
00600
00601
00602
00603
00604 string raw_data(record.after_value(x));
00605 destination.append(raw_data.c_str(), raw_data.size());
00606 }
00607 else
00608 {
00609 string tmp(record.after_value(x));
00610 escapeEmbeddedQuotes(tmp);
00611 destination.append(tmp);
00612 }
00613 }
00614
00615 if (should_quote_field_value)
00616 destination.push_back('\'');
00617 }
00618
00619 size_t num_key_fields= header.key_field_metadata_size();
00620
00621 destination.append(" WHERE ", 7);
00622 for (x= 0; x < num_key_fields; ++x)
00623 {
00624 const FieldMetadata &field_metadata= header.key_field_metadata(x);
00625
00626 if (x != 0)
00627 destination.append(" AND ", 5);
00628
00629 destination.push_back(quoted_identifier);
00630 destination.append(field_metadata.name());
00631 destination.push_back(quoted_identifier);
00632
00633 destination.push_back('=');
00634
00635 should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
00636
00637 if (should_quote_field_value)
00638 destination.push_back('\'');
00639
00640 if (field_metadata.type() == Table::Field::BLOB)
00641 {
00642
00643
00644
00645
00646
00647
00648 string raw_data(record.key_value(x));
00649 destination.append(raw_data.c_str(), raw_data.size());
00650 }
00651 else
00652 {
00653 destination.append(record.key_value(x));
00654 }
00655
00656 if (should_quote_field_value)
00657 destination.push_back('\'');
00658 }
00659
00660 return error;
00661 }
00662
00663 enum TransformSqlError
00664 transformDeleteHeaderToSql(const DeleteHeader &header,
00665 string &destination,
00666 enum TransformSqlVariant sql_variant)
00667 {
00668 char quoted_identifier= '`';
00669 if (sql_variant == ANSI)
00670 quoted_identifier= '"';
00671
00672 destination.assign("DELETE FROM ", 12);
00673 destination.push_back(quoted_identifier);
00674 destination.append(header.table_metadata().schema_name());
00675 destination.push_back(quoted_identifier);
00676 destination.push_back('.');
00677 destination.push_back(quoted_identifier);
00678 destination.append(header.table_metadata().table_name());
00679 destination.push_back(quoted_identifier);
00680
00681 return NONE;
00682 }
00683
00684 enum TransformSqlError
00685 transformDeleteRecordToSql(const DeleteHeader &header,
00686 const DeleteRecord &record,
00687 string &destination,
00688 enum TransformSqlVariant sql_variant)
00689 {
00690 enum TransformSqlError error= transformDeleteHeaderToSql(header,
00691 destination,
00692 sql_variant);
00693 char quoted_identifier= '`';
00694 if (sql_variant == ANSI)
00695 quoted_identifier= '"';
00696
00697
00698 uint32_t num_key_fields= header.key_field_metadata_size();
00699 uint32_t x;
00700 bool should_quote_field_value= false;
00701
00702 destination.append(" WHERE ", 7);
00703 for (x= 0; x < num_key_fields; ++x)
00704 {
00705 const FieldMetadata &field_metadata= header.key_field_metadata(x);
00706
00707 if (x != 0)
00708 destination.append(" AND ", 5);
00709
00710 destination.push_back(quoted_identifier);
00711 destination.append(field_metadata.name());
00712 destination.push_back(quoted_identifier);
00713
00714 destination.push_back('=');
00715
00716 should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
00717
00718 if (should_quote_field_value)
00719 destination.push_back('\'');
00720
00721 if (field_metadata.type() == Table::Field::BLOB)
00722 {
00723
00724
00725
00726
00727
00728
00729 string raw_data(record.key_value(x));
00730 destination.append(raw_data.c_str(), raw_data.size());
00731 }
00732 else
00733 {
00734 string tmp(record.key_value(x));
00735 escapeEmbeddedQuotes(tmp);
00736 destination.append(tmp);
00737 }
00738
00739 if (should_quote_field_value)
00740 destination.push_back('\'');
00741 }
00742
00743 return error;
00744 }
00745
00746 enum TransformSqlError
00747 transformDeleteStatementToSql(const DeleteHeader &header,
00748 const DeleteData &data,
00749 string &destination,
00750 enum TransformSqlVariant sql_variant)
00751 {
00752 enum TransformSqlError error= transformDeleteHeaderToSql(header,
00753 destination,
00754 sql_variant);
00755 char quoted_identifier= '`';
00756 if (sql_variant == ANSI)
00757 quoted_identifier= '"';
00758
00759
00760 uint32_t num_key_fields= header.key_field_metadata_size();
00761 uint32_t num_key_records= data.record_size();
00762 uint32_t x, y;
00763 bool should_quote_field_value= false;
00764
00765 destination.append(" WHERE ", 7);
00766 for (x= 0; x < num_key_records; ++x)
00767 {
00768 if (x != 0)
00769 destination.append(" OR ", 4);
00770
00771 if (num_key_fields > 1)
00772 destination.push_back('(');
00773
00774 for (y= 0; y < num_key_fields; ++y)
00775 {
00776 const FieldMetadata &field_metadata= header.key_field_metadata(y);
00777
00778 if (y != 0)
00779 destination.append(" AND ", 5);
00780
00781 destination.push_back(quoted_identifier);
00782 destination.append(field_metadata.name());
00783 destination.push_back(quoted_identifier);
00784
00785 destination.push_back('=');
00786
00787 should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
00788
00789 if (should_quote_field_value)
00790 destination.push_back('\'');
00791
00792 if (field_metadata.type() == Table::Field::BLOB)
00793 {
00794
00795
00796
00797
00798
00799
00800 string raw_data(data.record(x).key_value(y));
00801 destination.append(raw_data.c_str(), raw_data.size());
00802 }
00803 else
00804 {
00805 string tmp(data.record(x).key_value(y));
00806 escapeEmbeddedQuotes(tmp);
00807 destination.append(tmp);
00808 }
00809
00810 if (should_quote_field_value)
00811 destination.push_back('\'');
00812 }
00813 if (num_key_fields > 1)
00814 destination.push_back(')');
00815 }
00816 return error;
00817 }
00818
00819 enum TransformSqlError
00820 transformAlterSchemaStatementToSql(const AlterSchemaStatement &statement,
00821 string &destination,
00822 enum TransformSqlVariant sql_variant)
00823 {
00824 const Schema &before= statement.before();
00825 const Schema &after= statement.after();
00826
00827
00828 if (before.uuid() != after.uuid())
00829 return UUID_MISMATCH;
00830
00831 char quoted_identifier= '`';
00832 if (sql_variant == ANSI)
00833 quoted_identifier= '"';
00834
00835 destination.append("ALTER SCHEMA ");
00836 destination.push_back(quoted_identifier);
00837 destination.append(before.name());
00838 destination.push_back(quoted_identifier);
00839
00840
00841
00842
00843
00844 destination.append(" COLLATE = ");
00845 destination.append(after.collation());
00846
00847 return NONE;
00848 }
00849
00850 enum TransformSqlError
00851 transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
00852 string &destination,
00853 enum TransformSqlVariant sql_variant)
00854 {
00855 char quoted_identifier= '`';
00856 if (sql_variant == ANSI)
00857 quoted_identifier= '"';
00858
00859 destination.append("DROP SCHEMA ", 12);
00860 destination.push_back(quoted_identifier);
00861 destination.append(statement.schema_name());
00862 destination.push_back(quoted_identifier);
00863
00864 return NONE;
00865 }
00866
00867 enum TransformSqlError
00868 transformCreateSchemaStatementToSql(const CreateSchemaStatement &statement,
00869 string &destination,
00870 enum TransformSqlVariant sql_variant)
00871 {
00872 char quoted_identifier= '`';
00873 if (sql_variant == ANSI)
00874 quoted_identifier= '"';
00875
00876 const Schema &schema= statement.schema();
00877
00878 destination.append("CREATE SCHEMA ");
00879 destination.push_back(quoted_identifier);
00880 destination.append(schema.name());
00881 destination.push_back(quoted_identifier);
00882
00883 if (schema.has_collation())
00884 {
00885 destination.append(" COLLATE ");
00886 destination.append(schema.collation());
00887 }
00888
00889 if (not message::is_replicated(schema))
00890 {
00891 destination.append(" REPLICATE = FALSE");
00892 }
00893
00894 if (message::has_definer(schema))
00895 {
00896 destination.append(" DEFINER ");
00897 destination.push_back('\'');
00898 destination.append(message::definer(schema));
00899 destination.push_back('\'');
00900 }
00901
00902 return NONE;
00903 }
00904
00905 enum TransformSqlError
00906 transformDropTableStatementToSql(const DropTableStatement &statement,
00907 string &destination,
00908 enum TransformSqlVariant sql_variant)
00909 {
00910 char quoted_identifier= '`';
00911 if (sql_variant == ANSI)
00912 quoted_identifier= '"';
00913
00914 const TableMetadata &table_metadata= statement.table_metadata();
00915
00916 destination.append("DROP TABLE ");
00917
00918
00919 if (statement.has_if_exists_clause() &&
00920 statement.if_exists_clause() == true)
00921 {
00922 destination.append("IF EXISTS ");
00923 }
00924
00925 destination.push_back(quoted_identifier);
00926 destination.append(table_metadata.schema_name());
00927 destination.push_back(quoted_identifier);
00928 destination.push_back('.');
00929 destination.push_back(quoted_identifier);
00930 destination.append(table_metadata.table_name());
00931 destination.push_back(quoted_identifier);
00932
00933 return NONE;
00934 }
00935
00936 enum TransformSqlError
00937 transformTruncateTableStatementToSql(const TruncateTableStatement &statement,
00938 string &destination,
00939 enum TransformSqlVariant sql_variant)
00940 {
00941 char quoted_identifier= '`';
00942 if (sql_variant == ANSI)
00943 quoted_identifier= '"';
00944
00945 const TableMetadata &table_metadata= statement.table_metadata();
00946
00947 destination.append("TRUNCATE TABLE ");
00948 destination.push_back(quoted_identifier);
00949 destination.append(table_metadata.schema_name());
00950 destination.push_back(quoted_identifier);
00951 destination.push_back('.');
00952 destination.push_back(quoted_identifier);
00953 destination.append(table_metadata.table_name());
00954 destination.push_back(quoted_identifier);
00955
00956 return NONE;
00957 }
00958
00959 enum TransformSqlError
00960 transformSetVariableStatementToSql(const SetVariableStatement &statement,
00961 string &destination,
00962 enum TransformSqlVariant sql_variant)
00963 {
00964 (void) sql_variant;
00965 const FieldMetadata &variable_metadata= statement.variable_metadata();
00966 bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
00967
00968 destination.append("SET GLOBAL ");
00969 destination.append(variable_metadata.name());
00970 destination.push_back('=');
00971
00972 if (should_quote_field_value)
00973 destination.push_back('\'');
00974
00975 destination.append(statement.variable_value());
00976
00977 if (should_quote_field_value)
00978 destination.push_back('\'');
00979
00980 return NONE;
00981 }
00982
00983 enum TransformSqlError
00984 transformCreateTableStatementToSql(const CreateTableStatement &statement,
00985 string &destination,
00986 enum TransformSqlVariant sql_variant)
00987 {
00988 return transformTableDefinitionToSql(statement.table(), destination, sql_variant);
00989 }
00990
00991 enum TransformSqlError
00992 transformTableDefinitionToSql(const Table &table,
00993 string &destination,
00994 enum TransformSqlVariant sql_variant, bool with_schema)
00995 {
00996 char quoted_identifier= '`';
00997 if (sql_variant == ANSI)
00998 quoted_identifier= '"';
00999
01000 destination.append("CREATE ");
01001
01002 if (table.type() == Table::TEMPORARY)
01003 destination.append("TEMPORARY ");
01004
01005 destination.append("TABLE ");
01006 if (with_schema)
01007 {
01008 append_escaped_string(&destination, table.schema(), quoted_identifier);
01009 destination.push_back('.');
01010 }
01011 append_escaped_string(&destination, table.name(), quoted_identifier);
01012 destination.append(" (\n");
01013
01014 enum TransformSqlError result= NONE;
01015 size_t num_fields= table.field_size();
01016 for (size_t x= 0; x < num_fields; ++x)
01017 {
01018 const Table::Field &field= table.field(x);
01019
01020 if (x != 0)
01021 destination.append(",\n");
01022
01023 destination.append(" ");
01024
01025 result= transformFieldDefinitionToSql(field, destination, sql_variant);
01026
01027 if (result != NONE)
01028 return result;
01029 }
01030
01031 size_t num_indexes= table.indexes_size();
01032
01033 if (num_indexes > 0)
01034 destination.append(",\n");
01035
01036 for (size_t x= 0; x < num_indexes; ++x)
01037 {
01038 const message::Table::Index &index= table.indexes(x);
01039
01040 if (x != 0)
01041 destination.append(",\n");
01042
01043 result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
01044
01045 if (result != NONE)
01046 return result;
01047 }
01048
01049 size_t num_foreign_keys= table.fk_constraint_size();
01050
01051 if (num_foreign_keys > 0)
01052 destination.append(",\n");
01053
01054 for (size_t x= 0; x < num_foreign_keys; ++x)
01055 {
01056 const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
01057
01058 if (x != 0)
01059 destination.append(",\n");
01060
01061 result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
01062
01063 if (result != NONE)
01064 return result;
01065 }
01066
01067 destination.append("\n)");
01068
01069
01070 if (table.has_engine())
01071 {
01072 destination.append(" ENGINE=");
01073 destination.append(table.engine().name());
01074
01075 size_t num_engine_options= table.engine().options_size();
01076 if (num_engine_options > 0)
01077 destination.append(" ", 1);
01078 for (size_t x= 0; x < num_engine_options; ++x)
01079 {
01080 const Engine::Option &option= table.engine().options(x);
01081 destination.append(option.name());
01082 destination.append("='");
01083 destination.append(option.state());
01084 destination.append("'");
01085 if (x != num_engine_options-1)
01086 {
01087 destination.append(", ");
01088 }
01089 }
01090 }
01091
01092 if (table.has_options())
01093 (void) transformTableOptionsToSql(table.options(), destination, sql_variant);
01094
01095 if (not message::is_replicated(table))
01096 {
01097 destination.append(" REPLICATE = FALSE");
01098 }
01099
01100 if (message::has_definer(table))
01101 {
01102 destination.append(" DEFINER ");
01103 destination.push_back('\'');
01104 destination.append(message::definer(table));
01105 destination.push_back('\'');
01106 }
01107
01108 return NONE;
01109 }
01110
01111 enum TransformSqlError
01112 transformTableOptionsToSql(const Table::TableOptions &options,
01113 string &destination,
01114 enum TransformSqlVariant sql_variant)
01115 {
01116 if (sql_variant == ANSI)
01117 return NONE;
01118
01119 if (options.has_comment())
01120 {
01121 destination.append(" COMMENT=");
01122 append_escaped_string(&destination, options.comment());
01123 }
01124
01125 if (options.has_collation())
01126 {
01127 destination.append(" COLLATE = ");
01128 destination.append(options.collation());
01129 }
01130
01131 if (options.has_data_file_name())
01132 {
01133 destination.append("\nDATA_FILE_NAME = '");
01134 destination.append(options.data_file_name());
01135 destination.push_back('\'');
01136 }
01137
01138 if (options.has_index_file_name())
01139 {
01140 destination.append("\nINDEX_FILE_NAME = '");
01141 destination.append(options.index_file_name());
01142 destination.push_back('\'');
01143 }
01144
01145 if (options.has_max_rows())
01146 {
01147 destination.append("\nMAX_ROWS = ");
01148 destination.append(boost::lexical_cast<string>(options.max_rows()));
01149 }
01150
01151 if (options.has_min_rows())
01152 {
01153 destination.append("\nMIN_ROWS = ");
01154 destination.append(boost::lexical_cast<string>(options.min_rows()));
01155 }
01156
01157 if (options.has_user_set_auto_increment_value()
01158 && options.has_auto_increment_value())
01159 {
01160 destination.append(" AUTO_INCREMENT=");
01161 destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
01162 }
01163
01164 if (options.has_avg_row_length())
01165 {
01166 destination.append("\nAVG_ROW_LENGTH = ");
01167 destination.append(boost::lexical_cast<string>(options.avg_row_length()));
01168 }
01169
01170 if (options.has_checksum() && options.checksum())
01171 destination.append("\nCHECKSUM = TRUE");
01172
01173 if (options.has_page_checksum() && options.page_checksum())
01174 destination.append("\nPAGE_CHECKSUM = TRUE");
01175
01176 return NONE;
01177 }
01178
01179 enum TransformSqlError
01180 transformIndexDefinitionToSql(const Table::Index &index,
01181 const Table &table,
01182 string &destination,
01183 enum TransformSqlVariant sql_variant)
01184 {
01185 char quoted_identifier= '`';
01186 if (sql_variant == ANSI)
01187 quoted_identifier= '"';
01188
01189 destination.append(" ", 2);
01190
01191 if (index.is_primary())
01192 destination.append("PRIMARY ");
01193 else if (index.is_unique())
01194 destination.append("UNIQUE ");
01195
01196 destination.append("KEY ", 4);
01197 if (! (index.is_primary() && index.name().compare("PRIMARY")==0))
01198 {
01199 destination.push_back(quoted_identifier);
01200 destination.append(index.name());
01201 destination.push_back(quoted_identifier);
01202 destination.append(" (", 2);
01203 }
01204 else
01205 destination.append("(", 1);
01206
01207 size_t num_parts= index.index_part_size();
01208 for (size_t x= 0; x < num_parts; ++x)
01209 {
01210 const Table::Index::IndexPart &part= index.index_part(x);
01211 const Table::Field &field= table.field(part.fieldnr());
01212
01213 if (x != 0)
01214 destination.push_back(',');
01215
01216 destination.push_back(quoted_identifier);
01217 destination.append(field.name());
01218 destination.push_back(quoted_identifier);
01219
01220
01221
01222
01223
01224
01225 if (field.type() == Table::Field::VARCHAR ||
01226 field.type() == Table::Field::BLOB)
01227 {
01228 if (part.has_compare_length())
01229 {
01230 if (part.compare_length() != field.string_options().length())
01231 {
01232 destination.push_back('(');
01233 destination.append(boost::lexical_cast<string>(part.compare_length()));
01234 destination.push_back(')');
01235 }
01236 }
01237 }
01238 }
01239 destination.push_back(')');
01240
01241 switch (index.type())
01242 {
01243 case Table::Index::UNKNOWN_INDEX:
01244 break;
01245 case Table::Index::BTREE:
01246 destination.append(" USING BTREE");
01247 break;
01248 case Table::Index::RTREE:
01249 destination.append(" USING RTREE");
01250 break;
01251 case Table::Index::HASH:
01252 destination.append(" USING HASH");
01253 break;
01254 case Table::Index::FULLTEXT:
01255 destination.append(" USING FULLTEXT");
01256 break;
01257 }
01258
01259 if (index.has_comment())
01260 {
01261 destination.append(" COMMENT ");
01262 append_escaped_string(&destination, index.comment());
01263 }
01264
01265 return NONE;
01266 }
01267
01268 static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
01269 {
01270 switch (opt)
01271 {
01272 case Table::ForeignKeyConstraint::OPTION_RESTRICT:
01273 destination.append("RESTRICT");
01274 break;
01275 case Table::ForeignKeyConstraint::OPTION_CASCADE:
01276 destination.append("CASCADE");
01277 break;
01278 case Table::ForeignKeyConstraint::OPTION_SET_NULL:
01279 destination.append("SET NULL");
01280 break;
01281 case Table::ForeignKeyConstraint::OPTION_UNDEF:
01282 case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
01283 destination.append("NO ACTION");
01284 break;
01285 case Table::ForeignKeyConstraint::OPTION_SET_DEFAULT:
01286 destination.append("SET DEFAULT");
01287 break;
01288 }
01289 }
01290
01291 enum TransformSqlError
01292 transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
01293 const Table &,
01294 string &destination,
01295 enum TransformSqlVariant sql_variant)
01296 {
01297 char quoted_identifier= '`';
01298 if (sql_variant == ANSI)
01299 quoted_identifier= '"';
01300
01301 destination.append(" ");
01302
01303 if (fkey.has_name())
01304 {
01305 destination.append("CONSTRAINT ");
01306 append_escaped_string(&destination, fkey.name(), quoted_identifier);
01307 destination.append(" ", 1);
01308 }
01309
01310 destination.append("FOREIGN KEY (");
01311
01312 for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
01313 {
01314 if (x != 0)
01315 destination.append(", ");
01316
01317 append_escaped_string(&destination, fkey.column_names(x),
01318 quoted_identifier);
01319 }
01320
01321 destination.append(") REFERENCES ");
01322
01323 append_escaped_string(&destination, fkey.references_table_name(),
01324 quoted_identifier);
01325 destination.append(" (");
01326
01327 for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
01328 {
01329 if (x != 0)
01330 destination.append(", ");
01331
01332 append_escaped_string(&destination, fkey.references_columns(x),
01333 quoted_identifier);
01334 }
01335
01336 destination.push_back(')');
01337
01338 if (fkey.has_update_option() and fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
01339 {
01340 destination.append(" ON UPDATE ");
01341 transformForeignKeyOptionToSql(fkey.update_option(), destination);
01342 }
01343
01344 if (fkey.has_delete_option() and fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
01345 {
01346 destination.append(" ON DELETE ");
01347 transformForeignKeyOptionToSql(fkey.delete_option(), destination);
01348 }
01349
01350 return NONE;
01351 }
01352
01353 enum TransformSqlError
01354 transformFieldDefinitionToSql(const Table::Field &field,
01355 string &destination,
01356 enum TransformSqlVariant sql_variant)
01357 {
01358 char quoted_identifier= '`';
01359 char quoted_default;
01360
01361 if (sql_variant == ANSI)
01362 quoted_identifier= '"';
01363
01364 if (sql_variant == DRIZZLE)
01365 quoted_default= '\'';
01366 else
01367 quoted_default= quoted_identifier;
01368
01369 append_escaped_string(&destination, field.name(), quoted_identifier);
01370
01371 Table::Field::FieldType field_type= field.type();
01372
01373 switch (field_type)
01374 {
01375 case Table::Field::DOUBLE:
01376 destination.append(" DOUBLE");
01377 if (field.has_numeric_options()
01378 && field.numeric_options().has_precision())
01379 {
01380 stringstream ss;
01381 ss << "(" << field.numeric_options().precision() << ",";
01382 ss << field.numeric_options().scale() << ")";
01383 destination.append(ss.str());
01384 }
01385 break;
01386 case Table::Field::VARCHAR:
01387 {
01388 if (field.string_options().has_collation()
01389 && field.string_options().collation().compare("binary") == 0)
01390 destination.append(" VARBINARY(");
01391 else
01392 destination.append(" VARCHAR(");
01393
01394 destination.append(boost::lexical_cast<string>(field.string_options().length()));
01395 destination.append(")");
01396 }
01397 break;
01398 case Table::Field::BLOB:
01399 {
01400 if (field.string_options().has_collation()
01401 && field.string_options().collation().compare("binary") == 0)
01402 destination.append(" BLOB");
01403 else
01404 destination.append(" TEXT");
01405 }
01406 break;
01407 case Table::Field::ENUM:
01408 {
01409 size_t num_field_values= field.enumeration_values().field_value_size();
01410 destination.append(" ENUM(");
01411 for (size_t x= 0; x < num_field_values; ++x)
01412 {
01413 const string &type= field.enumeration_values().field_value(x);
01414
01415 if (x != 0)
01416 destination.push_back(',');
01417
01418 destination.push_back('\'');
01419 destination.append(type);
01420 destination.push_back('\'');
01421 }
01422 destination.push_back(')');
01423 break;
01424 }
01425 case Table::Field::UUID:
01426 destination.append(" UUID");
01427 break;
01428 case Table::Field::IPV6:
01429 destination.append(" IPV6");
01430 break;
01431 case Table::Field::BOOLEAN:
01432 destination.append(" BOOLEAN");
01433 break;
01434 case Table::Field::INTEGER:
01435 destination.append(" INT");
01436 break;
01437 case Table::Field::BIGINT:
01438 if (field.has_constraints() and
01439 field.constraints().is_unsigned())
01440 {
01441 destination.append(" BIGINT UNSIGNED");
01442 }
01443 else
01444 {
01445 destination.append(" BIGINT");
01446 }
01447 break;
01448 case Table::Field::DECIMAL:
01449 {
01450 destination.append(" DECIMAL(");
01451 stringstream ss;
01452 ss << field.numeric_options().precision() << ",";
01453 ss << field.numeric_options().scale() << ")";
01454 destination.append(ss.str());
01455 }
01456 break;
01457 case Table::Field::DATE:
01458 destination.append(" DATE");
01459 break;
01460
01461 case Table::Field::EPOCH:
01462 if (field.time_options().microseconds())
01463 {
01464 destination.append(" TIMESTAMP(6)");
01465 }
01466 else
01467 {
01468 destination.append(" TIMESTAMP");
01469 }
01470 break;
01471
01472 case Table::Field::DATETIME:
01473 destination.append(" DATETIME");
01474 break;
01475 case Table::Field::TIME:
01476 destination.append(" TIME");
01477 break;
01478 }
01479
01480 if (field.type() == Table::Field::BLOB ||
01481 field.type() == Table::Field::VARCHAR)
01482 {
01483 if (field.string_options().has_collation()
01484 && field.string_options().collation().compare("binary"))
01485 {
01486 destination.append(" COLLATE ");
01487 destination.append(field.string_options().collation());
01488 }
01489 }
01490
01491 if (field.has_constraints() and field.constraints().is_unique())
01492 {
01493 destination.append(" UNIQUE");
01494 }
01495
01496 if (field.has_constraints() && field.constraints().is_notnull())
01497 {
01498 destination.append(" NOT NULL");
01499 }
01500 else if (field.type() == Table::Field::EPOCH)
01501 {
01502 destination.append(" NULL");
01503 }
01504
01505 if (field.type() == Table::Field::INTEGER ||
01506 field.type() == Table::Field::BIGINT)
01507 {
01508
01509 if (field.has_numeric_options() &&
01510 field.numeric_options().is_autoincrement())
01511 {
01512 destination.append(" AUTO_INCREMENT");
01513 }
01514 }
01515
01516 if (field.options().has_default_value())
01517 {
01518 destination.append(" DEFAULT ");
01519 append_escaped_string(&destination, field.options().default_value());
01520 }
01521 else if (field.options().has_default_expression())
01522 {
01523 destination.append(" DEFAULT ");
01524 destination.append(field.options().default_expression());
01525 }
01526 else if (field.options().has_default_bin_value())
01527 {
01528 const string &v= field.options().default_bin_value();
01529 if (v.length() == 0)
01530 {
01531 destination.append(" DEFAULT ''");
01532 }
01533 else
01534 {
01535 destination.append(" DEFAULT 0x");
01536 for (size_t x= 0; x < v.length(); x++)
01537 {
01538 char hex[3];
01539 snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
01540 destination.append(hex, 2);
01541 }
01542 }
01543 }
01544 else if (field.options().has_default_null()
01545 && field.options().default_null()
01546 && field.type() != Table::Field::BLOB)
01547 {
01548 destination.append(" DEFAULT NULL");
01549 }
01550
01551 if (field.has_options() && field.options().has_update_expression())
01552 {
01553 destination.append(" ON UPDATE ");
01554 destination.append(field.options().update_expression());
01555 }
01556
01557 if (field.has_comment())
01558 {
01559 destination.append(" COMMENT ");
01560 append_escaped_string(&destination, field.comment(), quoted_default);
01561 }
01562 return NONE;
01563 }
01564
01565 bool shouldQuoteFieldValue(Table::Field::FieldType in_type)
01566 {
01567 switch (in_type)
01568 {
01569 case Table::Field::DOUBLE:
01570 case Table::Field::DECIMAL:
01571 case Table::Field::INTEGER:
01572 case Table::Field::BIGINT:
01573 return false;
01574 default:
01575 return true;
01576 }
01577 }
01578
01579 Table::Field::FieldType internalFieldTypeToFieldProtoType(enum enum_field_types type)
01580 {
01581 switch (type) {
01582 case DRIZZLE_TYPE_LONG:
01583 return Table::Field::INTEGER;
01584 case DRIZZLE_TYPE_DOUBLE:
01585 return Table::Field::DOUBLE;
01586 case DRIZZLE_TYPE_NULL:
01587 assert(false);
01588 return Table::Field::INTEGER;
01589 case DRIZZLE_TYPE_MICROTIME:
01590 case DRIZZLE_TYPE_TIMESTAMP:
01591 return Table::Field::EPOCH;
01592 case DRIZZLE_TYPE_LONGLONG:
01593 return Table::Field::BIGINT;
01594 case DRIZZLE_TYPE_DATETIME:
01595 return Table::Field::DATETIME;
01596 case DRIZZLE_TYPE_TIME:
01597 return Table::Field::TIME;
01598 case DRIZZLE_TYPE_DATE:
01599 return Table::Field::DATE;
01600 case DRIZZLE_TYPE_VARCHAR:
01601 return Table::Field::VARCHAR;
01602 case DRIZZLE_TYPE_DECIMAL:
01603 return Table::Field::DECIMAL;
01604 case DRIZZLE_TYPE_ENUM:
01605 return Table::Field::ENUM;
01606 case DRIZZLE_TYPE_BLOB:
01607 return Table::Field::BLOB;
01608 case DRIZZLE_TYPE_UUID:
01609 return Table::Field::UUID;
01610 case DRIZZLE_TYPE_BOOLEAN:
01611 return Table::Field::BOOLEAN;
01612 case DRIZZLE_TYPE_IPV6:
01613 return Table::Field::IPV6;
01614 }
01615
01616 assert(false);
01617 return Table::Field::INTEGER;
01618 }
01619
01620 bool transactionContainsBulkSegment(const Transaction &transaction)
01621 {
01622 size_t num_statements= transaction.statement_size();
01623 if (num_statements == 0)
01624 return false;
01625
01626
01627
01628
01629
01630
01631 size_t x;
01632 for (x= 0; x < num_statements; ++x)
01633 {
01634 const Statement &statement= transaction.statement(x);
01635 Statement::Type type= statement.type();
01636
01637 switch (type)
01638 {
01639 case Statement::INSERT:
01640 if (statement.insert_data().segment_id() > 1)
01641 return true;
01642 break;
01643 case Statement::UPDATE:
01644 if (statement.update_data().segment_id() > 1)
01645 return true;
01646 break;
01647 case Statement::DELETE:
01648 if (statement.delete_data().segment_id() > 1)
01649 return true;
01650 break;
01651 default:
01652 break;
01653 }
01654 }
01655 return false;
01656 }
01657
01658 }
01659 }