~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

Merge Jay

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2009 Sun Microsystems
 
5
 *
 
6
 *  Authors:
 
7
 *
 
8
 *    Jay Pipes <joinfu@sun.com>
 
9
 *
 
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.
 
13
 *
 
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.
 
18
 *
 
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
 
22
 */
 
23
 
 
24
/**
 
25
 * @file
 
26
 *
 
27
 * Implementation of various routines that can be used to convert
 
28
 * Statement messages to other formats, including SQL strings.
 
29
 */
 
30
 
 
31
#include "drizzled/global.h"
 
32
 
 
33
#include "drizzled/message/statement_transform.h"
 
34
#include "drizzled/message/transaction.pb.h"
 
35
#include "drizzled/message/table.pb.h"
 
36
 
 
37
#include <string>
 
38
#include <vector>
 
39
 
 
40
using namespace std;
 
41
using namespace drizzled;
 
42
 
 
43
enum message::TransformSqlError
 
44
message::transformStatementToSql(const message::Statement &source,
 
45
                                 vector<string> &sql_strings,
 
46
                                 enum message::TransformSqlVariant sql_variant)
 
47
{
 
48
  message::TransformSqlError error= NONE;
 
49
 
 
50
  switch (source.type())
 
51
  {
 
52
  case message::Statement::INSERT:
 
53
    {
 
54
      if (! source.has_insert_header())
 
55
      {
 
56
        error= MISSING_HEADER;
 
57
        return error;
 
58
      }
 
59
      if (! source.has_insert_data())
 
60
      {
 
61
        error= MISSING_DATA;
 
62
        return error;
 
63
      }
 
64
 
 
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();
 
68
      size_t x;
 
69
 
 
70
      if (num_keys > 1)
 
71
        sql_strings.push_back("START TRANSACTION");
 
72
 
 
73
      for (x= 0; x < num_keys; ++x)
 
74
      {
 
75
        string destination;
 
76
 
 
77
        error= transformInsertRecordToSql(insert_header,
 
78
                                          insert_data.record(x),
 
79
                                          &destination,
 
80
                                          sql_variant);
 
81
        if (error != NONE)
 
82
          break;
 
83
 
 
84
        sql_strings.push_back(destination);
 
85
      }
 
86
 
 
87
      if (num_keys > 1)
 
88
      {
 
89
        if (error == NONE)
 
90
          sql_strings.push_back("COMMIT");
 
91
        else
 
92
          sql_strings.push_back("ROLLBACK");
 
93
      }
 
94
    }
 
95
    break;
 
96
  case message::Statement::UPDATE:
 
97
    {
 
98
      if (! source.has_update_header())
 
99
      {
 
100
        error= MISSING_HEADER;
 
101
        return error;
 
102
      }
 
103
      if (! source.has_update_data())
 
104
      {
 
105
        error= MISSING_DATA;
 
106
        return error;
 
107
      }
 
108
 
 
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();
 
112
      size_t x;
 
113
 
 
114
      if (num_keys > 1)
 
115
        sql_strings.push_back("START TRANSACTION");
 
116
 
 
117
      for (x= 0; x < num_keys; ++x)
 
118
      {
 
119
        string destination;
 
120
 
 
121
        error= transformUpdateRecordToSql(update_header,
 
122
                                          update_data.record(x),
 
123
                                          &destination,
 
124
                                          sql_variant);
 
125
        if (error != NONE)
 
126
          break;
 
127
 
 
128
        sql_strings.push_back(destination);
 
129
      }
 
130
 
 
131
      if (num_keys > 1)
 
132
      {
 
133
        if (error == NONE)
 
134
          sql_strings.push_back("COMMIT");
 
135
        else
 
136
          sql_strings.push_back("ROLLBACK");
 
137
      }
 
138
    }
 
139
    break;
 
140
  case message::Statement::DELETE:
 
141
    {
 
142
      if (! source.has_delete_header())
 
143
      {
 
144
        error= MISSING_HEADER;
 
145
        return error;
 
146
      }
 
147
      if (! source.has_delete_data())
 
148
      {
 
149
        error= MISSING_DATA;
 
150
        return error;
 
151
      }
 
152
 
 
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();
 
156
      size_t x;
 
157
 
 
158
      if (num_keys > 1)
 
159
        sql_strings.push_back("START TRANSACTION");
 
160
 
 
161
      for (x= 0; x < num_keys; ++x)
 
162
      {
 
163
        string destination;
 
164
 
 
165
        error= transformDeleteRecordToSql(delete_header,
 
166
                                          delete_data.record(x),
 
167
                                          &destination,
 
168
                                          sql_variant);
 
169
        if (error != NONE)
 
170
          break;
 
171
 
 
172
        sql_strings.push_back(destination);
 
173
      }
 
174
 
 
175
      if (num_keys > 1)
 
176
      {
 
177
        if (error == NONE)
 
178
          sql_strings.push_back("COMMIT");
 
179
        else
 
180
          sql_strings.push_back("ROLLBACK");
 
181
      }
 
182
    }
 
183
    break;
 
184
  case message::Statement::SET_VARIABLE:
 
185
    {
 
186
      assert(source.has_set_variable_statement());
 
187
      string destination;
 
188
      error= message::transformSetVariableStatementToSql(source.set_variable_statement(),
 
189
                                                       &destination,
 
190
                                                       sql_variant);
 
191
      sql_strings.push_back(destination);
 
192
    }
 
193
    break;
 
194
  case message::Statement::RAW_SQL:
 
195
  default:
 
196
    sql_strings.push_back(source.sql());
 
197
    break;
 
198
  }
 
199
  return error;
 
200
}
 
201
 
 
202
enum message::TransformSqlError
 
203
message::transformInsertHeaderToSql(const message::InsertHeader &header,
 
204
                                    std::string *destination,
 
205
                                    enum message::TransformSqlVariant sql_variant)
 
206
{
 
207
  char quoted_identifier= '`';
 
208
  if (sql_variant == ANSI)
 
209
    quoted_identifier= '"';
 
210
 
 
211
  destination->assign("INSERT INTO ");
 
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(" (");
 
220
 
 
221
  /* Add field list to SQL string... */
 
222
  size_t num_fields= header.field_metadata_size();
 
223
  size_t x;
 
224
 
 
225
  for (x= 0; x < num_fields; ++x)
 
226
  {
 
227
    const message::FieldMetadata &field_metadata= header.field_metadata(x);
 
228
    if (x != 0)
 
229
      destination->push_back(',');
 
230
    
 
231
    destination->push_back(quoted_identifier);
 
232
    destination->append(field_metadata.name());
 
233
    destination->push_back(quoted_identifier);
 
234
  }
 
235
 
 
236
  return NONE;
 
237
}
 
238
 
 
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)
 
244
{
 
245
  enum message::TransformSqlError error= transformInsertHeaderToSql(header,
 
246
                                                                    destination,
 
247
                                                                    sql_variant);
 
248
 
 
249
  char quoted_identifier= '`';
 
250
  if (sql_variant == ANSI)
 
251
    quoted_identifier= '"';
 
252
 
 
253
  destination->append(") VALUES (");
 
254
 
 
255
  /* Add insert values */
 
256
  size_t num_fields= header.field_metadata_size();
 
257
  size_t x;
 
258
  bool should_quote_field_value= false;
 
259
  
 
260
  for (x= 0; x < num_fields; ++x)
 
261
  {
 
262
    if (x != 0)
 
263
      destination->push_back(',');
 
264
 
 
265
    should_quote_field_value= message::shouldQuoteFieldValue(header.field_metadata(x).type());
 
266
 
 
267
    if (should_quote_field_value)
 
268
      destination->push_back('\'');
 
269
 
 
270
    destination->append(record.insert_value(x));
 
271
 
 
272
    if (should_quote_field_value)
 
273
      destination->push_back('\'');
 
274
  }
 
275
  destination->push_back(')');
 
276
 
 
277
  return error;
 
278
}
 
279
 
 
280
enum message::TransformSqlError
 
281
message::transformInsertStatementToSql(const message::InsertHeader &header,
 
282
                                       const message::InsertData &data,
 
283
                                       std::string *destination,
 
284
                                       enum message::TransformSqlVariant sql_variant)
 
285
{
 
286
  enum message::TransformSqlError error= transformInsertHeaderToSql(header,
 
287
                                                                    destination,
 
288
                                                                    sql_variant);
 
289
 
 
290
  char quoted_identifier= '`';
 
291
  if (sql_variant == ANSI)
 
292
    quoted_identifier= '"';
 
293
 
 
294
  destination->append(") VALUES (");
 
295
 
 
296
  /* Add insert values */
 
297
  size_t num_records= data.record_size();
 
298
  size_t num_fields= header.field_metadata_size();
 
299
  size_t x, y;
 
300
  bool should_quote_field_value= false;
 
301
  
 
302
  for (x= 0; x < num_records; ++x)
 
303
  {
 
304
    if (x != 0)
 
305
      destination->append("),(");
 
306
 
 
307
    for (y= 0; y < num_fields; ++y)
 
308
    {
 
309
      if (y != 0)
 
310
        destination->push_back(',');
 
311
 
 
312
      should_quote_field_value= message::shouldQuoteFieldValue(header.field_metadata(y).type());
 
313
 
 
314
      if (should_quote_field_value)
 
315
        destination->push_back('\'');
 
316
 
 
317
      destination->append(data.record(x).insert_value(y));
 
318
 
 
319
      if (should_quote_field_value)
 
320
        destination->push_back('\'');
 
321
    }
 
322
  }
 
323
  destination->push_back(')');
 
324
 
 
325
  return error;
 
326
}
 
327
 
 
328
enum message::TransformSqlError
 
329
message::transformUpdateHeaderToSql(const message::UpdateHeader &header,
 
330
                                    std::string *destination,
 
331
                                    enum message::TransformSqlVariant sql_variant)
 
332
{
 
333
  char quoted_identifier= '`';
 
334
  if (sql_variant == ANSI)
 
335
    quoted_identifier= '"';
 
336
 
 
337
  destination->assign("UPDATE ");
 
338
  destination->push_back(quoted_identifier);
 
339
  destination->append(header.table_metadata().schema_name());
 
340
  destination->push_back(quoted_identifier);
 
341
  destination->push_back('.');
 
342
  destination->push_back(quoted_identifier);
 
343
  destination->append(header.table_metadata().table_name());
 
344
  destination->push_back(quoted_identifier);
 
345
  destination->append(" SET ");
 
346
 
 
347
  /* Add field SET list to SQL string... */
 
348
  size_t num_set_fields= header.set_field_metadata_size();
 
349
  size_t x;
 
350
  bool should_quote_field_value= false;
 
351
 
 
352
  for (x= 0; x < num_set_fields; ++x)
 
353
  {
 
354
    const message::FieldMetadata &field_metadata= header.set_field_metadata(x);
 
355
    if (x != 0)
 
356
      destination->push_back(',');
 
357
    
 
358
    destination->push_back(quoted_identifier);
 
359
    destination->append(field_metadata.name());
 
360
    destination->push_back(quoted_identifier);
 
361
    destination->push_back('=');
 
362
 
 
363
    should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
 
364
 
 
365
    if (should_quote_field_value)
 
366
      destination->push_back('\'');
 
367
 
 
368
    destination->append(header.set_value(x));
 
369
 
 
370
    if (should_quote_field_value)
 
371
      destination->push_back('\'');
 
372
  }
 
373
 
 
374
  return NONE;
 
375
}
 
376
 
 
377
enum message::TransformSqlError
 
378
message::transformUpdateRecordToSql(const message::UpdateHeader &header,
 
379
                                    const message::UpdateRecord &record,
 
380
                                    std::string *destination,
 
381
                                    enum message::TransformSqlVariant sql_variant)
 
382
{
 
383
  enum message::TransformSqlError error= transformUpdateHeaderToSql(header,
 
384
                                                                    destination,
 
385
                                                                    sql_variant);
 
386
 
 
387
  char quoted_identifier= '`';
 
388
  if (sql_variant == ANSI)
 
389
    quoted_identifier= '"';
 
390
 
 
391
  size_t num_key_fields= header.key_field_metadata_size();
 
392
  size_t x;
 
393
  bool should_quote_field_value= false;
 
394
 
 
395
  destination->append(" WHERE ");
 
396
  for (x= 0; x < num_key_fields; ++x) 
 
397
  {
 
398
    const message::FieldMetadata &field_metadata= header.key_field_metadata(x);
 
399
    
 
400
    if (x != 0)
 
401
      destination->append(" AND "); /* Always AND condition with a multi-column PK */
 
402
 
 
403
    destination->push_back(quoted_identifier);
 
404
    destination->append(field_metadata.name());
 
405
    destination->push_back(quoted_identifier);
 
406
 
 
407
    destination->push_back('=');
 
408
 
 
409
    should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
 
410
 
 
411
    if (should_quote_field_value)
 
412
      destination->push_back('\'');
 
413
 
 
414
    destination->append(record.key_value(x));
 
415
 
 
416
    if (should_quote_field_value)
 
417
      destination->push_back('\'');
 
418
  }
 
419
  if (num_key_fields > 1)
 
420
    destination->push_back(')');
 
421
 
 
422
  return error;
 
423
}
 
424
 
 
425
enum message::TransformSqlError
 
426
message::transformUpdateStatementToSql(const message::UpdateHeader &header,
 
427
                                       const message::UpdateData &data,
 
428
                                       std::string *destination,
 
429
                                       enum message::TransformSqlVariant sql_variant)
 
430
{
 
431
  enum message::TransformSqlError error= transformUpdateHeaderToSql(header,
 
432
                                                                    destination,
 
433
                                                                    sql_variant);
 
434
 
 
435
  char quoted_identifier= '`';
 
436
  if (sql_variant == ANSI)
 
437
    quoted_identifier= '"';
 
438
 
 
439
  /* Add WHERE clause to SQL string... */
 
440
  size_t num_key_fields= header.key_field_metadata_size();
 
441
  size_t num_key_records= data.record_size();
 
442
  size_t x, y;
 
443
  bool should_quote_field_value= false;
 
444
 
 
445
  destination->append(" WHERE ");
 
446
  for (x= 0; x < num_key_records; ++x)
 
447
  {
 
448
    if (x != 0)
 
449
      destination->append(" OR "); /* Always OR condition for multiple key records */
 
450
 
 
451
    if (num_key_fields > 1)
 
452
      destination->push_back('(');
 
453
 
 
454
    for (y= 0; y < num_key_fields; ++y) 
 
455
    {
 
456
      const message::FieldMetadata &field_metadata= header.key_field_metadata(y);
 
457
      
 
458
      if (y != 0)
 
459
        destination->append(" AND "); /* Always AND condition with a multi-column PK */
 
460
 
 
461
      destination->push_back(quoted_identifier);
 
462
      destination->append(field_metadata.name());
 
463
      destination->push_back(quoted_identifier);
 
464
 
 
465
      destination->push_back('=');
 
466
 
 
467
      should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
 
468
 
 
469
      if (should_quote_field_value)
 
470
        destination->push_back('\'');
 
471
 
 
472
      destination->append(data.record(x).key_value(y));
 
473
 
 
474
      if (should_quote_field_value)
 
475
        destination->push_back('\'');
 
476
    }
 
477
    if (num_key_fields > 1)
 
478
      destination->push_back(')');
 
479
  }
 
480
  return error;
 
481
}
 
482
 
 
483
enum message::TransformSqlError
 
484
message::transformDeleteHeaderToSql(const message::DeleteHeader &header,
 
485
                                    std::string *destination,
 
486
                                    enum message::TransformSqlVariant sql_variant)
 
487
{
 
488
  char quoted_identifier= '`';
 
489
  if (sql_variant == ANSI)
 
490
    quoted_identifier= '"';
 
491
 
 
492
  destination->assign("DELETE FROM ");
 
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);
 
500
 
 
501
  return NONE;
 
502
}
 
503
 
 
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)
 
509
{
 
510
  enum message::TransformSqlError error= transformDeleteHeaderToSql(header,
 
511
                                                                    destination,
 
512
                                                                    sql_variant);
 
513
  char quoted_identifier= '`';
 
514
  if (sql_variant == ANSI)
 
515
    quoted_identifier= '"';
 
516
 
 
517
  /* Add WHERE clause to SQL string... */
 
518
  uint32_t num_key_fields= header.key_field_metadata_size();
 
519
  uint32_t x;
 
520
  bool should_quote_field_value= false;
 
521
 
 
522
  destination->append(" WHERE ");
 
523
  for (x= 0; x < num_key_fields; ++x) 
 
524
  {
 
525
    const message::FieldMetadata &field_metadata= header.key_field_metadata(x);
 
526
    
 
527
    if (x != 0)
 
528
      destination->append(" AND "); /* Always AND condition with a multi-column PK */
 
529
 
 
530
    destination->push_back(quoted_identifier);
 
531
    destination->append(field_metadata.name());
 
532
    destination->push_back(quoted_identifier);
 
533
 
 
534
    destination->push_back('=');
 
535
 
 
536
    should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
 
537
 
 
538
    if (should_quote_field_value)
 
539
      destination->push_back('\'');
 
540
 
 
541
    destination->append(record.key_value(x));
 
542
 
 
543
    if (should_quote_field_value)
 
544
      destination->push_back('\'');
 
545
  }
 
546
  if (num_key_fields > 1)
 
547
    destination->push_back(')');
 
548
 
 
549
  return error;
 
550
}
 
551
 
 
552
enum message::TransformSqlError
 
553
message::transformDeleteStatementToSql(const message::DeleteHeader &header,
 
554
                                       const message::DeleteData &data,
 
555
                                       std::string *destination,
 
556
                                       enum message::TransformSqlVariant sql_variant)
 
557
{
 
558
  enum message::TransformSqlError error= transformDeleteHeaderToSql(header,
 
559
                                                                    destination,
 
560
                                                                    sql_variant);
 
561
  char quoted_identifier= '`';
 
562
  if (sql_variant == ANSI)
 
563
    quoted_identifier= '"';
 
564
 
 
565
  /* Add WHERE clause to SQL string... */
 
566
  uint32_t num_key_fields= header.key_field_metadata_size();
 
567
  uint32_t num_key_records= data.record_size();
 
568
  uint32_t x, y;
 
569
  bool should_quote_field_value= false;
 
570
 
 
571
  destination->append(" WHERE ");
 
572
  for (x= 0; x < num_key_records; ++x)
 
573
  {
 
574
    if (x != 0)
 
575
      destination->append(" OR "); /* Always OR condition for multiple key records */
 
576
 
 
577
    if (num_key_fields > 1)
 
578
      destination->push_back('(');
 
579
 
 
580
    for (y= 0; y < num_key_fields; ++y) 
 
581
    {
 
582
      const message::FieldMetadata &field_metadata= header.key_field_metadata(y);
 
583
      
 
584
      if (y != 0)
 
585
        destination->append(" AND "); /* Always AND condition with a multi-column PK */
 
586
 
 
587
      destination->push_back(quoted_identifier);
 
588
      destination->append(field_metadata.name());
 
589
      destination->push_back(quoted_identifier);
 
590
 
 
591
      destination->push_back('=');
 
592
 
 
593
      should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
 
594
 
 
595
      if (should_quote_field_value)
 
596
        destination->push_back('\'');
 
597
 
 
598
      destination->append(data.record(x).key_value(y));
 
599
 
 
600
      if (should_quote_field_value)
 
601
        destination->push_back('\'');
 
602
    }
 
603
    if (num_key_fields > 1)
 
604
      destination->push_back(')');
 
605
  }
 
606
  return error;
 
607
}
 
608
 
 
609
enum message::TransformSqlError
 
610
message::transformSetVariableStatementToSql(const message::SetVariableStatement &statement,
 
611
                                            std::string *destination,
 
612
                                            enum message::TransformSqlVariant sql_variant)
 
613
{
 
614
  (void) sql_variant;
 
615
  const message::FieldMetadata &variable_metadata= statement.variable_metadata();
 
616
  bool should_quote_field_value= message::shouldQuoteFieldValue(variable_metadata.type());
 
617
 
 
618
  destination->append("SET GLOBAL "); /* Only global variables are replicated */
 
619
  destination->append(variable_metadata.name());
 
620
  destination->push_back('=');
 
621
 
 
622
  if (should_quote_field_value)
 
623
    destination->push_back('\'');
 
624
  
 
625
  destination->append(statement.variable_value());
 
626
 
 
627
  if (should_quote_field_value)
 
628
    destination->push_back('\'');
 
629
 
 
630
  return NONE;
 
631
}
 
632
 
 
633
bool message::shouldQuoteFieldValue(message::Table::Field::FieldType in_type)
 
634
{
 
635
  switch (in_type)
 
636
  {
 
637
  case message::Table::Field::DOUBLE:
 
638
  case message::Table::Field::DECIMAL:
 
639
  case message::Table::Field::INTEGER:
 
640
  case message::Table::Field::BIGINT:
 
641
  case message::Table::Field::ENUM:
 
642
    return false;
 
643
  default:
 
644
    return true;
 
645
  } 
 
646
}