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
8
* Jay Pipes <joinfu@sun.com>
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; version 2 of the License.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
* Implementation of various routines that can be used to convert
28
* Statement messages to other formats, including SQL strings.
33
#include "drizzled/message/statement_transform.h"
34
#include "drizzled/message/transaction.pb.h"
35
#include "drizzled/message/table.pb.h"
41
using namespace drizzled;
43
enum message::TransformSqlError
44
message::transformStatementToSql(const message::Statement &source,
45
vector<string> &sql_strings,
46
enum message::TransformSqlVariant sql_variant,
47
bool already_in_transaction)
49
message::TransformSqlError error= NONE;
51
switch (source.type())
53
case message::Statement::INSERT:
55
if (! source.has_insert_header())
57
error= MISSING_HEADER;
60
if (! source.has_insert_data())
66
const message::InsertHeader &insert_header= source.insert_header();
67
const message::InsertData &insert_data= source.insert_data();
68
size_t num_keys= insert_data.record_size();
71
if (num_keys > 1 && ! already_in_transaction)
72
sql_strings.push_back("START TRANSACTION");
74
for (x= 0; x < num_keys; ++x)
78
error= transformInsertRecordToSql(insert_header,
79
insert_data.record(x),
85
sql_strings.push_back(destination);
88
if (num_keys > 1 && ! already_in_transaction)
91
sql_strings.push_back("COMMIT");
93
sql_strings.push_back("ROLLBACK");
97
case message::Statement::UPDATE:
99
if (! source.has_update_header())
101
error= MISSING_HEADER;
104
if (! source.has_update_data())
110
const message::UpdateHeader &update_header= source.update_header();
111
const message::UpdateData &update_data= source.update_data();
112
size_t num_keys= update_data.record_size();
115
if (num_keys > 1 && ! already_in_transaction)
116
sql_strings.push_back("START TRANSACTION");
118
for (x= 0; x < num_keys; ++x)
122
error= transformUpdateRecordToSql(update_header,
123
update_data.record(x),
129
sql_strings.push_back(destination);
132
if (num_keys > 1 && ! already_in_transaction)
135
sql_strings.push_back("COMMIT");
137
sql_strings.push_back("ROLLBACK");
141
case message::Statement::DELETE:
143
if (! source.has_delete_header())
145
error= MISSING_HEADER;
148
if (! source.has_delete_data())
154
const message::DeleteHeader &delete_header= source.delete_header();
155
const message::DeleteData &delete_data= source.delete_data();
156
size_t num_keys= delete_data.record_size();
159
if (num_keys > 1 && ! already_in_transaction)
160
sql_strings.push_back("START TRANSACTION");
162
for (x= 0; x < num_keys; ++x)
166
error= transformDeleteRecordToSql(delete_header,
167
delete_data.record(x),
173
sql_strings.push_back(destination);
176
if (num_keys > 1 && ! already_in_transaction)
179
sql_strings.push_back("COMMIT");
181
sql_strings.push_back("ROLLBACK");
185
case message::Statement::TRUNCATE_TABLE:
187
assert(source.has_truncate_table_statement());
189
error= message::transformTruncateTableStatementToSql(source.truncate_table_statement(),
192
sql_strings.push_back(destination);
195
case message::Statement::SET_VARIABLE:
197
assert(source.has_set_variable_statement());
199
error= message::transformSetVariableStatementToSql(source.set_variable_statement(),
202
sql_strings.push_back(destination);
205
case message::Statement::RAW_SQL:
207
sql_strings.push_back(source.sql());
213
enum message::TransformSqlError
214
message::transformInsertHeaderToSql(const message::InsertHeader &header,
215
std::string *destination,
216
enum message::TransformSqlVariant sql_variant)
218
char quoted_identifier= '`';
219
if (sql_variant == ANSI)
220
quoted_identifier= '"';
222
destination->assign("INSERT INTO ", 12);
223
destination->push_back(quoted_identifier);
224
destination->append(header.table_metadata().schema_name());
225
destination->push_back(quoted_identifier);
226
destination->push_back('.');
227
destination->push_back(quoted_identifier);
228
destination->append(header.table_metadata().table_name());
229
destination->push_back(quoted_identifier);
230
destination->append(" (", 2);
232
/* Add field list to SQL string... */
233
size_t num_fields= header.field_metadata_size();
236
for (x= 0; x < num_fields; ++x)
238
const message::FieldMetadata &field_metadata= header.field_metadata(x);
240
destination->push_back(',');
242
destination->push_back(quoted_identifier);
243
destination->append(field_metadata.name());
244
destination->push_back(quoted_identifier);
250
enum message::TransformSqlError
251
message::transformInsertRecordToSql(const message::InsertHeader &header,
252
const message::InsertRecord &record,
253
std::string *destination,
254
enum message::TransformSqlVariant sql_variant)
256
enum message::TransformSqlError error= transformInsertHeaderToSql(header,
260
char quoted_identifier= '`';
261
if (sql_variant == ANSI)
262
quoted_identifier= '"';
264
destination->append(") VALUES (");
266
/* Add insert values */
267
size_t num_fields= header.field_metadata_size();
269
bool should_quote_field_value= false;
271
for (x= 0; x < num_fields; ++x)
274
destination->push_back(',');
276
const message::FieldMetadata &field_metadata= header.field_metadata(x);
278
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
280
if (should_quote_field_value)
281
destination->push_back('\'');
283
if (field_metadata.type() == message::Table::Field::BLOB)
286
* We do this here because BLOB data is returned
287
* in a string correctly, but calling append()
288
* without a length will result in only the string
289
* up to a \0 being output here.
291
string raw_data(record.insert_value(x));
292
destination->append(raw_data.c_str(), raw_data.size());
296
destination->append(record.insert_value(x));
299
if (should_quote_field_value)
300
destination->push_back('\'');
302
destination->push_back(')');
307
enum message::TransformSqlError
308
message::transformInsertStatementToSql(const message::InsertHeader &header,
309
const message::InsertData &data,
310
std::string *destination,
311
enum message::TransformSqlVariant sql_variant)
313
enum message::TransformSqlError error= transformInsertHeaderToSql(header,
317
char quoted_identifier= '`';
318
if (sql_variant == ANSI)
319
quoted_identifier= '"';
321
destination->append(") VALUES (", 10);
323
/* Add insert values */
324
size_t num_records= data.record_size();
325
size_t num_fields= header.field_metadata_size();
327
bool should_quote_field_value= false;
329
for (x= 0; x < num_records; ++x)
332
destination->append("),(", 3);
334
for (y= 0; y < num_fields; ++y)
337
destination->push_back(',');
339
const message::FieldMetadata &field_metadata= header.field_metadata(y);
341
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
343
if (should_quote_field_value)
344
destination->push_back('\'');
346
if (field_metadata.type() == message::Table::Field::BLOB)
349
* We do this here because BLOB data is returned
350
* in a string correctly, but calling append()
351
* without a length will result in only the string
352
* up to a \0 being output here.
354
string raw_data(data.record(x).insert_value(y));
355
destination->append(raw_data.c_str(), raw_data.size());
359
destination->append(data.record(x).insert_value(y));
362
if (should_quote_field_value)
363
destination->push_back('\'');
366
destination->push_back(')');
371
enum message::TransformSqlError
372
message::transformUpdateHeaderToSql(const message::UpdateHeader &header,
373
std::string *destination,
374
enum message::TransformSqlVariant sql_variant)
376
char quoted_identifier= '`';
377
if (sql_variant == ANSI)
378
quoted_identifier= '"';
380
destination->assign("UPDATE ", 7);
381
destination->push_back(quoted_identifier);
382
destination->append(header.table_metadata().schema_name());
383
destination->push_back(quoted_identifier);
384
destination->push_back('.');
385
destination->push_back(quoted_identifier);
386
destination->append(header.table_metadata().table_name());
387
destination->push_back(quoted_identifier);
388
destination->append(" SET ", 5);
393
enum message::TransformSqlError
394
message::transformUpdateRecordToSql(const message::UpdateHeader &header,
395
const message::UpdateRecord &record,
396
std::string *destination,
397
enum message::TransformSqlVariant sql_variant)
399
enum message::TransformSqlError error= transformUpdateHeaderToSql(header,
403
char quoted_identifier= '`';
404
if (sql_variant == ANSI)
405
quoted_identifier= '"';
407
/* Add field SET list to SQL string... */
408
size_t num_set_fields= header.set_field_metadata_size();
410
bool should_quote_field_value= false;
412
for (x= 0; x < num_set_fields; ++x)
414
const message::FieldMetadata &field_metadata= header.set_field_metadata(x);
416
destination->push_back(',');
418
destination->push_back(quoted_identifier);
419
destination->append(field_metadata.name());
420
destination->push_back(quoted_identifier);
421
destination->push_back('=');
423
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
425
if (should_quote_field_value)
426
destination->push_back('\'');
428
if (field_metadata.type() == message::Table::Field::BLOB)
431
* We do this here because BLOB data is returned
432
* in a string correctly, but calling append()
433
* without a length will result in only the string
434
* up to a \0 being output here.
436
string raw_data(record.after_value(x));
437
destination->append(raw_data.c_str(), raw_data.size());
441
destination->append(record.after_value(x));
444
if (should_quote_field_value)
445
destination->push_back('\'');
448
size_t num_key_fields= header.key_field_metadata_size();
450
destination->append(" WHERE ", 7);
451
for (x= 0; x < num_key_fields; ++x)
453
const message::FieldMetadata &field_metadata= header.key_field_metadata(x);
456
destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
458
destination->push_back(quoted_identifier);
459
destination->append(field_metadata.name());
460
destination->push_back(quoted_identifier);
462
destination->push_back('=');
464
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
466
if (should_quote_field_value)
467
destination->push_back('\'');
469
if (field_metadata.type() == message::Table::Field::BLOB)
472
* We do this here because BLOB data is returned
473
* in a string correctly, but calling append()
474
* without a length will result in only the string
475
* up to a \0 being output here.
477
string raw_data(record.key_value(x));
478
destination->append(raw_data.c_str(), raw_data.size());
482
destination->append(record.key_value(x));
485
if (should_quote_field_value)
486
destination->push_back('\'');
488
if (num_key_fields > 1)
489
destination->push_back(')');
494
enum message::TransformSqlError
495
message::transformDeleteHeaderToSql(const message::DeleteHeader &header,
496
std::string *destination,
497
enum message::TransformSqlVariant sql_variant)
499
char quoted_identifier= '`';
500
if (sql_variant == ANSI)
501
quoted_identifier= '"';
503
destination->assign("DELETE FROM ", 12);
504
destination->push_back(quoted_identifier);
505
destination->append(header.table_metadata().schema_name());
506
destination->push_back(quoted_identifier);
507
destination->push_back('.');
508
destination->push_back(quoted_identifier);
509
destination->append(header.table_metadata().table_name());
510
destination->push_back(quoted_identifier);
515
enum message::TransformSqlError
516
message::transformDeleteRecordToSql(const message::DeleteHeader &header,
517
const message::DeleteRecord &record,
518
std::string *destination,
519
enum message::TransformSqlVariant sql_variant)
521
enum message::TransformSqlError error= transformDeleteHeaderToSql(header,
524
char quoted_identifier= '`';
525
if (sql_variant == ANSI)
526
quoted_identifier= '"';
528
/* Add WHERE clause to SQL string... */
529
uint32_t num_key_fields= header.key_field_metadata_size();
531
bool should_quote_field_value= false;
533
destination->append(" WHERE ", 7);
534
for (x= 0; x < num_key_fields; ++x)
536
const message::FieldMetadata &field_metadata= header.key_field_metadata(x);
539
destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
541
destination->push_back(quoted_identifier);
542
destination->append(field_metadata.name());
543
destination->push_back(quoted_identifier);
545
destination->push_back('=');
547
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
549
if (should_quote_field_value)
550
destination->push_back('\'');
552
if (field_metadata.type() == message::Table::Field::BLOB)
555
* We do this here because BLOB data is returned
556
* in a string correctly, but calling append()
557
* without a length will result in only the string
558
* up to a \0 being output here.
560
string raw_data(record.key_value(x));
561
destination->append(raw_data.c_str(), raw_data.size());
565
destination->append(record.key_value(x));
568
if (should_quote_field_value)
569
destination->push_back('\'');
575
enum message::TransformSqlError
576
message::transformDeleteStatementToSql(const message::DeleteHeader &header,
577
const message::DeleteData &data,
578
std::string *destination,
579
enum message::TransformSqlVariant sql_variant)
581
enum message::TransformSqlError error= transformDeleteHeaderToSql(header,
584
char quoted_identifier= '`';
585
if (sql_variant == ANSI)
586
quoted_identifier= '"';
588
/* Add WHERE clause to SQL string... */
589
uint32_t num_key_fields= header.key_field_metadata_size();
590
uint32_t num_key_records= data.record_size();
592
bool should_quote_field_value= false;
594
destination->append(" WHERE ", 7);
595
for (x= 0; x < num_key_records; ++x)
598
destination->append(" OR ", 4); /* Always OR condition for multiple key records */
600
if (num_key_fields > 1)
601
destination->push_back('(');
603
for (y= 0; y < num_key_fields; ++y)
605
const message::FieldMetadata &field_metadata= header.key_field_metadata(y);
608
destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
610
destination->push_back(quoted_identifier);
611
destination->append(field_metadata.name());
612
destination->push_back(quoted_identifier);
614
destination->push_back('=');
616
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
618
if (should_quote_field_value)
619
destination->push_back('\'');
621
if (field_metadata.type() == message::Table::Field::BLOB)
624
* We do this here because BLOB data is returned
625
* in a string correctly, but calling append()
626
* without a length will result in only the string
627
* up to a \0 being output here.
629
string raw_data(data.record(x).key_value(y));
630
destination->append(raw_data.c_str(), raw_data.size());
634
destination->append(data.record(x).key_value(y));
637
if (should_quote_field_value)
638
destination->push_back('\'');
640
if (num_key_fields > 1)
641
destination->push_back(')');
646
enum message::TransformSqlError
647
message::transformTruncateTableStatementToSql(const message::TruncateTableStatement &statement,
648
std::string *destination,
649
enum message::TransformSqlVariant sql_variant)
651
char quoted_identifier= '`';
652
if (sql_variant == ANSI)
653
quoted_identifier= '"';
655
const message::TableMetadata &table_metadata= statement.table_metadata();
657
destination->append("TRUNCATE TABLE ", 15);
658
destination->push_back(quoted_identifier);
659
destination->append(table_metadata.schema_name());
660
destination->push_back(quoted_identifier);
661
destination->push_back('.');
662
destination->push_back(quoted_identifier);
663
destination->append(table_metadata.table_name());
664
destination->push_back(quoted_identifier);
669
enum message::TransformSqlError
670
message::transformSetVariableStatementToSql(const message::SetVariableStatement &statement,
671
std::string *destination,
672
enum message::TransformSqlVariant sql_variant)
675
const message::FieldMetadata &variable_metadata= statement.variable_metadata();
676
bool should_quote_field_value= message::shouldQuoteFieldValue(variable_metadata.type());
678
destination->append("SET GLOBAL ", 11); /* Only global variables are replicated */
679
destination->append(variable_metadata.name());
680
destination->push_back('=');
682
if (should_quote_field_value)
683
destination->push_back('\'');
685
destination->append(statement.variable_value());
687
if (should_quote_field_value)
688
destination->push_back('\'');
693
bool message::shouldQuoteFieldValue(message::Table::Field::FieldType in_type)
697
case message::Table::Field::DOUBLE:
698
case message::Table::Field::DECIMAL:
699
case message::Table::Field::INTEGER:
700
case message::Table::Field::BIGINT:
701
case message::Table::Field::ENUM: