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.
31
#include "drizzled/global.h"
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)
48
message::TransformSqlError error= NONE;
50
switch (source.type())
52
case message::Statement::INSERT:
54
if (! source.has_insert_header())
56
error= MISSING_HEADER;
59
if (! source.has_insert_data())
65
const message::InsertHeader &insert_header= source.insert_header();
66
const message::InsertData &insert_data= source.insert_data();
67
size_t num_keys= insert_data.record_size();
71
sql_strings.push_back("START TRANSACTION");
73
for (x= 0; x < num_keys; ++x)
77
error= transformInsertRecordToSql(insert_header,
78
insert_data.record(x),
84
sql_strings.push_back(destination);
90
sql_strings.push_back("COMMIT");
92
sql_strings.push_back("ROLLBACK");
96
case message::Statement::UPDATE:
98
if (! source.has_update_header())
100
error= MISSING_HEADER;
103
if (! source.has_update_data())
109
const message::UpdateHeader &update_header= source.update_header();
110
const message::UpdateData &update_data= source.update_data();
111
size_t num_keys= update_data.record_size();
115
sql_strings.push_back("START TRANSACTION");
117
for (x= 0; x < num_keys; ++x)
121
error= transformUpdateRecordToSql(update_header,
122
update_data.record(x),
128
sql_strings.push_back(destination);
134
sql_strings.push_back("COMMIT");
136
sql_strings.push_back("ROLLBACK");
140
case message::Statement::DELETE:
142
if (! source.has_delete_header())
144
error= MISSING_HEADER;
147
if (! source.has_delete_data())
153
const message::DeleteHeader &delete_header= source.delete_header();
154
const message::DeleteData &delete_data= source.delete_data();
155
size_t num_keys= delete_data.record_size();
159
sql_strings.push_back("START TRANSACTION");
161
for (x= 0; x < num_keys; ++x)
165
error= transformDeleteRecordToSql(delete_header,
166
delete_data.record(x),
172
sql_strings.push_back(destination);
178
sql_strings.push_back("COMMIT");
180
sql_strings.push_back("ROLLBACK");
184
case message::Statement::SET_VARIABLE:
186
assert(source.has_set_variable_statement());
188
error= message::transformSetVariableStatementToSql(source.set_variable_statement(),
191
sql_strings.push_back(destination);
194
case message::Statement::RAW_SQL:
196
sql_strings.push_back(source.sql());
202
enum message::TransformSqlError
203
message::transformInsertHeaderToSql(const message::InsertHeader &header,
204
std::string *destination,
205
enum message::TransformSqlVariant sql_variant)
207
char quoted_identifier= '`';
208
if (sql_variant == ANSI)
209
quoted_identifier= '"';
211
destination->assign("INSERT INTO ", 12);
212
destination->push_back(quoted_identifier);
213
destination->append(header.table_metadata().schema_name());
214
destination->push_back(quoted_identifier);
215
destination->push_back('.');
216
destination->push_back(quoted_identifier);
217
destination->append(header.table_metadata().table_name());
218
destination->push_back(quoted_identifier);
219
destination->append(" (", 2);
221
/* Add field list to SQL string... */
222
size_t num_fields= header.field_metadata_size();
225
for (x= 0; x < num_fields; ++x)
227
const message::FieldMetadata &field_metadata= header.field_metadata(x);
229
destination->push_back(',');
231
destination->push_back(quoted_identifier);
232
destination->append(field_metadata.name());
233
destination->push_back(quoted_identifier);
239
enum message::TransformSqlError
240
message::transformInsertRecordToSql(const message::InsertHeader &header,
241
const message::InsertRecord &record,
242
std::string *destination,
243
enum message::TransformSqlVariant sql_variant)
245
enum message::TransformSqlError error= transformInsertHeaderToSql(header,
249
char quoted_identifier= '`';
250
if (sql_variant == ANSI)
251
quoted_identifier= '"';
253
destination->append(") VALUES (");
255
/* Add insert values */
256
size_t num_fields= header.field_metadata_size();
258
bool should_quote_field_value= false;
260
for (x= 0; x < num_fields; ++x)
263
destination->push_back(',');
265
const message::FieldMetadata &field_metadata= header.field_metadata(x);
267
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
269
if (should_quote_field_value)
270
destination->push_back('\'');
272
if (field_metadata.type() == message::Table::Field::BLOB)
275
* We do this here because BLOB data is returned
276
* in a string correctly, but calling append()
277
* without a length will result in only the string
278
* up to a \0 being output here.
280
string raw_data(record.insert_value(x));
281
destination->append(raw_data.c_str(), raw_data.size());
285
destination->append(record.insert_value(x));
288
if (should_quote_field_value)
289
destination->push_back('\'');
291
destination->push_back(')');
296
enum message::TransformSqlError
297
message::transformInsertStatementToSql(const message::InsertHeader &header,
298
const message::InsertData &data,
299
std::string *destination,
300
enum message::TransformSqlVariant sql_variant)
302
enum message::TransformSqlError error= transformInsertHeaderToSql(header,
306
char quoted_identifier= '`';
307
if (sql_variant == ANSI)
308
quoted_identifier= '"';
310
destination->append(") VALUES (", 10);
312
/* Add insert values */
313
size_t num_records= data.record_size();
314
size_t num_fields= header.field_metadata_size();
316
bool should_quote_field_value= false;
318
for (x= 0; x < num_records; ++x)
321
destination->append("),(", 3);
323
for (y= 0; y < num_fields; ++y)
326
destination->push_back(',');
328
const message::FieldMetadata &field_metadata= header.field_metadata(y);
330
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
332
if (should_quote_field_value)
333
destination->push_back('\'');
335
if (field_metadata.type() == message::Table::Field::BLOB)
338
* We do this here because BLOB data is returned
339
* in a string correctly, but calling append()
340
* without a length will result in only the string
341
* up to a \0 being output here.
343
string raw_data(data.record(x).insert_value(y));
344
destination->append(raw_data.c_str(), raw_data.size());
348
destination->append(data.record(x).insert_value(y));
351
if (should_quote_field_value)
352
destination->push_back('\'');
355
destination->push_back(')');
360
enum message::TransformSqlError
361
message::transformUpdateHeaderToSql(const message::UpdateHeader &header,
362
std::string *destination,
363
enum message::TransformSqlVariant sql_variant)
365
char quoted_identifier= '`';
366
if (sql_variant == ANSI)
367
quoted_identifier= '"';
369
destination->assign("UPDATE ", 7);
370
destination->push_back(quoted_identifier);
371
destination->append(header.table_metadata().schema_name());
372
destination->push_back(quoted_identifier);
373
destination->push_back('.');
374
destination->push_back(quoted_identifier);
375
destination->append(header.table_metadata().table_name());
376
destination->push_back(quoted_identifier);
377
destination->append(" SET ", 5);
382
enum message::TransformSqlError
383
message::transformUpdateRecordToSql(const message::UpdateHeader &header,
384
const message::UpdateRecord &record,
385
std::string *destination,
386
enum message::TransformSqlVariant sql_variant)
388
enum message::TransformSqlError error= transformUpdateHeaderToSql(header,
392
char quoted_identifier= '`';
393
if (sql_variant == ANSI)
394
quoted_identifier= '"';
396
/* Add field SET list to SQL string... */
397
size_t num_set_fields= header.set_field_metadata_size();
399
bool should_quote_field_value= false;
401
for (x= 0; x < num_set_fields; ++x)
403
const message::FieldMetadata &field_metadata= header.set_field_metadata(x);
405
destination->push_back(',');
407
destination->push_back(quoted_identifier);
408
destination->append(field_metadata.name());
409
destination->push_back(quoted_identifier);
410
destination->push_back('=');
412
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
414
if (should_quote_field_value)
415
destination->push_back('\'');
417
if (field_metadata.type() == message::Table::Field::BLOB)
420
* We do this here because BLOB data is returned
421
* in a string correctly, but calling append()
422
* without a length will result in only the string
423
* up to a \0 being output here.
425
string raw_data(record.after_value(x));
426
destination->append(raw_data.c_str(), raw_data.size());
430
destination->append(record.after_value(x));
433
if (should_quote_field_value)
434
destination->push_back('\'');
437
size_t num_key_fields= header.key_field_metadata_size();
439
destination->append(" WHERE ", 7);
440
for (x= 0; x < num_key_fields; ++x)
442
const message::FieldMetadata &field_metadata= header.key_field_metadata(x);
445
destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
447
destination->push_back(quoted_identifier);
448
destination->append(field_metadata.name());
449
destination->push_back(quoted_identifier);
451
destination->push_back('=');
453
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
455
if (should_quote_field_value)
456
destination->push_back('\'');
458
if (field_metadata.type() == message::Table::Field::BLOB)
461
* We do this here because BLOB data is returned
462
* in a string correctly, but calling append()
463
* without a length will result in only the string
464
* up to a \0 being output here.
466
string raw_data(record.key_value(x));
467
destination->append(raw_data.c_str(), raw_data.size());
471
destination->append(record.key_value(x));
474
if (should_quote_field_value)
475
destination->push_back('\'');
477
if (num_key_fields > 1)
478
destination->push_back(')');
483
enum message::TransformSqlError
484
message::transformDeleteHeaderToSql(const message::DeleteHeader &header,
485
std::string *destination,
486
enum message::TransformSqlVariant sql_variant)
488
char quoted_identifier= '`';
489
if (sql_variant == ANSI)
490
quoted_identifier= '"';
492
destination->assign("DELETE FROM ", 12);
493
destination->push_back(quoted_identifier);
494
destination->append(header.table_metadata().schema_name());
495
destination->push_back(quoted_identifier);
496
destination->push_back('.');
497
destination->push_back(quoted_identifier);
498
destination->append(header.table_metadata().table_name());
499
destination->push_back(quoted_identifier);
504
enum message::TransformSqlError
505
message::transformDeleteRecordToSql(const message::DeleteHeader &header,
506
const message::DeleteRecord &record,
507
std::string *destination,
508
enum message::TransformSqlVariant sql_variant)
510
enum message::TransformSqlError error= transformDeleteHeaderToSql(header,
513
char quoted_identifier= '`';
514
if (sql_variant == ANSI)
515
quoted_identifier= '"';
517
/* Add WHERE clause to SQL string... */
518
uint32_t num_key_fields= header.key_field_metadata_size();
520
bool should_quote_field_value= false;
522
destination->append(" WHERE ", 7);
523
for (x= 0; x < num_key_fields; ++x)
525
const message::FieldMetadata &field_metadata= header.key_field_metadata(x);
528
destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
530
destination->push_back(quoted_identifier);
531
destination->append(field_metadata.name());
532
destination->push_back(quoted_identifier);
534
destination->push_back('=');
536
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
538
if (should_quote_field_value)
539
destination->push_back('\'');
541
if (field_metadata.type() == message::Table::Field::BLOB)
544
* We do this here because BLOB data is returned
545
* in a string correctly, but calling append()
546
* without a length will result in only the string
547
* up to a \0 being output here.
549
string raw_data(record.key_value(x));
550
destination->append(raw_data.c_str(), raw_data.size());
554
destination->append(record.key_value(x));
557
if (should_quote_field_value)
558
destination->push_back('\'');
564
enum message::TransformSqlError
565
message::transformDeleteStatementToSql(const message::DeleteHeader &header,
566
const message::DeleteData &data,
567
std::string *destination,
568
enum message::TransformSqlVariant sql_variant)
570
enum message::TransformSqlError error= transformDeleteHeaderToSql(header,
573
char quoted_identifier= '`';
574
if (sql_variant == ANSI)
575
quoted_identifier= '"';
577
/* Add WHERE clause to SQL string... */
578
uint32_t num_key_fields= header.key_field_metadata_size();
579
uint32_t num_key_records= data.record_size();
581
bool should_quote_field_value= false;
583
destination->append(" WHERE ", 7);
584
for (x= 0; x < num_key_records; ++x)
587
destination->append(" OR ", 4); /* Always OR condition for multiple key records */
589
if (num_key_fields > 1)
590
destination->push_back('(');
592
for (y= 0; y < num_key_fields; ++y)
594
const message::FieldMetadata &field_metadata= header.key_field_metadata(y);
597
destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
599
destination->push_back(quoted_identifier);
600
destination->append(field_metadata.name());
601
destination->push_back(quoted_identifier);
603
destination->push_back('=');
605
should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
607
if (should_quote_field_value)
608
destination->push_back('\'');
610
if (field_metadata.type() == message::Table::Field::BLOB)
613
* We do this here because BLOB data is returned
614
* in a string correctly, but calling append()
615
* without a length will result in only the string
616
* up to a \0 being output here.
618
string raw_data(data.record(x).key_value(y));
619
destination->append(raw_data.c_str(), raw_data.size());
623
destination->append(data.record(x).key_value(y));
626
if (should_quote_field_value)
627
destination->push_back('\'');
629
if (num_key_fields > 1)
630
destination->push_back(')');
635
enum message::TransformSqlError
636
message::transformSetVariableStatementToSql(const message::SetVariableStatement &statement,
637
std::string *destination,
638
enum message::TransformSqlVariant sql_variant)
641
const message::FieldMetadata &variable_metadata= statement.variable_metadata();
642
bool should_quote_field_value= message::shouldQuoteFieldValue(variable_metadata.type());
644
destination->append("SET GLOBAL ", 11); /* Only global variables are replicated */
645
destination->append(variable_metadata.name());
646
destination->push_back('=');
648
if (should_quote_field_value)
649
destination->push_back('\'');
651
destination->append(statement.variable_value());
653
if (should_quote_field_value)
654
destination->push_back('\'');
659
bool message::shouldQuoteFieldValue(message::Table::Field::FieldType in_type)
663
case message::Table::Field::DOUBLE:
664
case message::Table::Field::DECIMAL:
665
case message::Table::Field::INTEGER:
666
case message::Table::Field::BIGINT:
667
case message::Table::Field::ENUM: