~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

  • Committer: Brian Aker
  • Date: 2009-12-06 01:55:53 UTC
  • mfrom: (1238.1.5 push)
  • Revision ID: brian@gaz-20091206015553-cva833q4gvwj11ob
Bundle for staging.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2009 Sun Microsystems, Inc.
5
 
 *  Copyright (C) 2010 Jay Pipes
 
4
 *  Copyright (C) 2009 Sun Microsystems
6
5
 *
7
6
 *  Authors:
8
7
 *
9
 
 *    Jay Pipes <jaypipes@gmail.com>
 
8
 *    Jay Pipes <joinfu@sun.com>
10
9
 *
11
10
 *  This program is free software; you can redistribute it and/or modify
12
11
 *  it under the terms of the GNU General Public License as published by
29
28
 * Statement messages to other formats, including SQL strings.
30
29
 */
31
30
 
32
 
#include <config.h>
 
31
#include "drizzled/global.h"
33
32
 
34
 
#include <boost/lexical_cast.hpp>
35
 
#include <drizzled/message/statement_transform.h>
36
 
#include <drizzled/message/transaction.pb.h>
37
 
#include <drizzled/message/table.pb.h>
38
 
#include <drizzled/charset.h>
39
 
#include <drizzled/charset_info.h>
40
 
#include <drizzled/global_charset_info.h>
 
33
#include "drizzled/message/statement_transform.h"
 
34
#include "drizzled/message/transaction.pb.h"
 
35
#include "drizzled/message/table.pb.h"
41
36
 
42
37
#include <string>
43
38
#include <vector>
44
 
#include <sstream>
45
 
#include <cstdio>
46
39
 
47
40
using namespace std;
48
 
 
49
 
namespace drizzled
50
 
{
51
 
 
52
 
namespace message
53
 
{
54
 
 
55
 
static void escapeEmbeddedQuotes(string &s, const char quote='\'')
56
 
{
57
 
  string::iterator it;
58
 
 
59
 
  for (it= s.begin(); it != s.end(); ++it)
60
 
  {
61
 
    if (*it == quote)
62
 
    {
63
 
      it= s.insert(it, quote);
64
 
      ++it;  // advance back to the quote
65
 
    }
66
 
  }
67
 
}
68
 
 
69
 
/* Incredibly similar to append_unescaped() in table.cc, but for std::string */
70
 
static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
71
 
{
72
 
  const char *pos= input.c_str();
73
 
  const char *end= input.c_str()+input.length();
74
 
  res->push_back(quote);
75
 
 
76
 
  for (; pos != end ; pos++)
77
 
  {
78
 
    uint32_t mblen;
79
 
    if (use_mb(default_charset_info) &&
80
 
        (mblen= my_ismbchar(default_charset_info, pos, end)))
81
 
    {
82
 
      res->append(pos, mblen);
83
 
      pos+= mblen - 1;
84
 
      if (pos >= end)
85
 
        break;
86
 
      continue;
87
 
    }
88
 
 
89
 
    switch (*pos) {
90
 
    case 0:                             /* Must be escaped for 'mysql' */
91
 
      res->push_back('\\');
92
 
      res->push_back('0');
93
 
      break;
94
 
    case '\n':                          /* Must be escaped for logs */
95
 
      res->push_back('\\');
96
 
      res->push_back('n');
97
 
      break;
98
 
    case '\r':
99
 
      res->push_back('\\');             /* This gives better readability */
100
 
      res->push_back('r');
101
 
      break;
102
 
    case '\\':
103
 
      res->push_back('\\');             /* Because of the sql syntax */
104
 
      res->push_back('\\');
105
 
      break;
106
 
    default:
107
 
      if (*pos == quote) /* SQL syntax for quoting a quote */
108
 
      {
109
 
        res->push_back(quote);
110
 
        res->push_back(quote);
111
 
      }
112
 
      else
113
 
        res->push_back(*pos);
114
 
      break;
115
 
    }
116
 
  }
117
 
  res->push_back(quote);
118
 
}
119
 
 
120
 
enum TransformSqlError
121
 
transformStatementToSql(const Statement &source,
122
 
                        vector<string> &sql_strings,
123
 
                        enum TransformSqlVariant sql_variant,
124
 
                        bool already_in_transaction)
125
 
{
126
 
  TransformSqlError error= NONE;
 
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;
127
49
 
128
50
  switch (source.type())
129
51
  {
130
 
  case Statement::ROLLBACK_STATEMENT:
131
 
    {
132
 
      break;
133
 
    }
134
 
  case Statement::ROLLBACK:
135
 
    {
136
 
      sql_strings.push_back("ROLLBACK");
137
 
      break;
138
 
    }
139
 
  case Statement::INSERT:
 
52
  case message::Statement::INSERT:
140
53
    {
141
54
      if (! source.has_insert_header())
142
55
      {
149
62
        return error;
150
63
      }
151
64
 
152
 
      const InsertHeader &insert_header= source.insert_header();
153
 
      const InsertData &insert_data= source.insert_data();
 
65
      const message::InsertHeader &insert_header= source.insert_header();
 
66
      const message::InsertData &insert_data= source.insert_data();
154
67
      size_t num_keys= insert_data.record_size();
 
68
      size_t x;
155
69
 
156
 
      if (num_keys > 1 && ! already_in_transaction)
 
70
      if (num_keys > 1)
157
71
        sql_strings.push_back("START TRANSACTION");
158
72
 
159
 
      for (size_t x= 0; x < num_keys; ++x)
 
73
      for (x= 0; x < num_keys; ++x)
160
74
      {
161
75
        string destination;
162
76
 
163
77
        error= transformInsertRecordToSql(insert_header,
164
78
                                          insert_data.record(x),
165
 
                                          destination,
 
79
                                          &destination,
166
80
                                          sql_variant);
167
81
        if (error != NONE)
168
82
          break;
170
84
        sql_strings.push_back(destination);
171
85
      }
172
86
 
173
 
      if (num_keys > 1 && ! already_in_transaction)
 
87
      if (num_keys > 1)
174
88
      {
175
89
        if (error == NONE)
176
90
          sql_strings.push_back("COMMIT");
179
93
      }
180
94
    }
181
95
    break;
182
 
  case Statement::UPDATE:
 
96
  case message::Statement::UPDATE:
183
97
    {
184
98
      if (! source.has_update_header())
185
99
      {
192
106
        return error;
193
107
      }
194
108
 
195
 
      const UpdateHeader &update_header= source.update_header();
196
 
      const UpdateData &update_data= source.update_data();
 
109
      const message::UpdateHeader &update_header= source.update_header();
 
110
      const message::UpdateData &update_data= source.update_data();
197
111
      size_t num_keys= update_data.record_size();
198
112
      size_t x;
199
113
 
200
 
      if (num_keys > 1 && ! already_in_transaction)
 
114
      if (num_keys > 1)
201
115
        sql_strings.push_back("START TRANSACTION");
202
116
 
203
117
      for (x= 0; x < num_keys; ++x)
206
120
 
207
121
        error= transformUpdateRecordToSql(update_header,
208
122
                                          update_data.record(x),
209
 
                                          destination,
 
123
                                          &destination,
210
124
                                          sql_variant);
211
125
        if (error != NONE)
212
126
          break;
214
128
        sql_strings.push_back(destination);
215
129
      }
216
130
 
217
 
      if (num_keys > 1 && ! already_in_transaction)
 
131
      if (num_keys > 1)
218
132
      {
219
133
        if (error == NONE)
220
134
          sql_strings.push_back("COMMIT");
223
137
      }
224
138
    }
225
139
    break;
226
 
  case Statement::DELETE:
 
140
  case message::Statement::DELETE:
227
141
    {
228
142
      if (! source.has_delete_header())
229
143
      {
236
150
        return error;
237
151
      }
238
152
 
239
 
      const DeleteHeader &delete_header= source.delete_header();
240
 
      const DeleteData &delete_data= source.delete_data();
 
153
      const message::DeleteHeader &delete_header= source.delete_header();
 
154
      const message::DeleteData &delete_data= source.delete_data();
241
155
      size_t num_keys= delete_data.record_size();
242
156
      size_t x;
243
157
 
244
 
      if (num_keys > 1 && ! already_in_transaction)
 
158
      if (num_keys > 1)
245
159
        sql_strings.push_back("START TRANSACTION");
246
160
 
247
161
      for (x= 0; x < num_keys; ++x)
250
164
 
251
165
        error= transformDeleteRecordToSql(delete_header,
252
166
                                          delete_data.record(x),
253
 
                                          destination,
 
167
                                          &destination,
254
168
                                          sql_variant);
255
169
        if (error != NONE)
256
170
          break;
258
172
        sql_strings.push_back(destination);
259
173
      }
260
174
 
261
 
      if (num_keys > 1 && ! already_in_transaction)
 
175
      if (num_keys > 1)
262
176
      {
263
177
        if (error == NONE)
264
178
          sql_strings.push_back("COMMIT");
267
181
      }
268
182
    }
269
183
    break;
270
 
  case Statement::CREATE_TABLE:
271
 
    {
272
 
      assert(source.has_create_table_statement());
273
 
      string destination;
274
 
      error= transformCreateTableStatementToSql(source.create_table_statement(),
275
 
                                                destination,
276
 
                                                sql_variant);
277
 
      sql_strings.push_back(destination);
278
 
    }
279
 
    break;
280
 
  case Statement::TRUNCATE_TABLE:
 
184
  case message::Statement::TRUNCATE_TABLE:
281
185
    {
282
186
      assert(source.has_truncate_table_statement());
283
187
      string destination;
284
 
      error= transformTruncateTableStatementToSql(source.truncate_table_statement(),
285
 
                                                  destination,
286
 
                                                  sql_variant);
287
 
      sql_strings.push_back(destination);
288
 
    }
289
 
    break;
290
 
  case Statement::DROP_TABLE:
291
 
    {
292
 
      assert(source.has_drop_table_statement());
293
 
      string destination;
294
 
      error= transformDropTableStatementToSql(source.drop_table_statement(),
295
 
                                              destination,
296
 
                                              sql_variant);
297
 
      sql_strings.push_back(destination);
298
 
    }
299
 
    break;
300
 
  case Statement::CREATE_SCHEMA:
301
 
    {
302
 
      assert(source.has_create_schema_statement());
303
 
      string destination;
304
 
      error= transformCreateSchemaStatementToSql(source.create_schema_statement(),
305
 
                                                 destination,
306
 
                                                 sql_variant);
307
 
      sql_strings.push_back(destination);
308
 
    }
309
 
    break;
310
 
  case Statement::DROP_SCHEMA:
311
 
    {
312
 
      assert(source.has_drop_schema_statement());
313
 
      string destination;
314
 
      error= transformDropSchemaStatementToSql(source.drop_schema_statement(),
315
 
                                               destination,
316
 
                                               sql_variant);
317
 
      sql_strings.push_back(destination);
318
 
    }
319
 
    break;
320
 
  case Statement::ALTER_SCHEMA:
321
 
    {
322
 
      assert(source.has_alter_schema_statement());
323
 
      string destination;
324
 
      error= transformAlterSchemaStatementToSql(source.alter_schema_statement(),
325
 
                                                destination,
326
 
                                                sql_variant);
327
 
      sql_strings.push_back(destination);
328
 
    }
329
 
    break;
330
 
  case Statement::SET_VARIABLE:
 
188
      error= message::transformTruncateTableStatementToSql(source.truncate_table_statement(),
 
189
                                                           &destination,
 
190
                                                           sql_variant);
 
191
      sql_strings.push_back(destination);
 
192
    }
 
193
    break;
 
194
  case message::Statement::SET_VARIABLE:
331
195
    {
332
196
      assert(source.has_set_variable_statement());
333
197
      string destination;
334
 
      error= transformSetVariableStatementToSql(source.set_variable_statement(),
335
 
                                                destination,
336
 
                                                sql_variant);
 
198
      error= message::transformSetVariableStatementToSql(source.set_variable_statement(),
 
199
                                                       &destination,
 
200
                                                       sql_variant);
337
201
      sql_strings.push_back(destination);
338
202
    }
339
203
    break;
340
 
  case Statement::RAW_SQL:
 
204
  case message::Statement::RAW_SQL:
341
205
  default:
342
206
    sql_strings.push_back(source.sql());
343
207
    break;
345
209
  return error;
346
210
}
347
211
 
348
 
enum TransformSqlError
349
 
transformInsertHeaderToSql(const InsertHeader &header,
350
 
                           string &destination,
351
 
                           enum TransformSqlVariant sql_variant)
 
212
enum message::TransformSqlError
 
213
message::transformInsertHeaderToSql(const message::InsertHeader &header,
 
214
                                    std::string *destination,
 
215
                                    enum message::TransformSqlVariant sql_variant)
352
216
{
353
217
  char quoted_identifier= '`';
354
218
  if (sql_variant == ANSI)
355
219
    quoted_identifier= '"';
356
220
 
357
 
  destination.assign("INSERT INTO ", 12);
358
 
  destination.push_back(quoted_identifier);
359
 
  destination.append(header.table_metadata().schema_name());
360
 
  destination.push_back(quoted_identifier);
361
 
  destination.push_back('.');
362
 
  destination.push_back(quoted_identifier);
363
 
  destination.append(header.table_metadata().table_name());
364
 
  destination.push_back(quoted_identifier);
365
 
  destination.append(" (", 2);
 
221
  destination->assign("INSERT INTO ", 12);
 
222
  destination->push_back(quoted_identifier);
 
223
  destination->append(header.table_metadata().schema_name());
 
224
  destination->push_back(quoted_identifier);
 
225
  destination->push_back('.');
 
226
  destination->push_back(quoted_identifier);
 
227
  destination->append(header.table_metadata().table_name());
 
228
  destination->push_back(quoted_identifier);
 
229
  destination->append(" (", 2);
366
230
 
367
231
  /* Add field list to SQL string... */
368
232
  size_t num_fields= header.field_metadata_size();
370
234
 
371
235
  for (x= 0; x < num_fields; ++x)
372
236
  {
373
 
    const FieldMetadata &field_metadata= header.field_metadata(x);
 
237
    const message::FieldMetadata &field_metadata= header.field_metadata(x);
374
238
    if (x != 0)
375
 
      destination.push_back(',');
 
239
      destination->push_back(',');
376
240
    
377
 
    destination.push_back(quoted_identifier);
378
 
    destination.append(field_metadata.name());
379
 
    destination.push_back(quoted_identifier);
 
241
    destination->push_back(quoted_identifier);
 
242
    destination->append(field_metadata.name());
 
243
    destination->push_back(quoted_identifier);
380
244
  }
381
245
 
382
246
  return NONE;
383
247
}
384
248
 
385
 
enum TransformSqlError
386
 
transformInsertRecordToSql(const InsertHeader &header,
387
 
                           const InsertRecord &record,
388
 
                           string &destination,
389
 
                           enum TransformSqlVariant sql_variant)
 
249
enum message::TransformSqlError
 
250
message::transformInsertRecordToSql(const message::InsertHeader &header,
 
251
                                    const message::InsertRecord &record,
 
252
                                    std::string *destination,
 
253
                                    enum message::TransformSqlVariant sql_variant)
390
254
{
391
 
  enum TransformSqlError error= transformInsertHeaderToSql(header,
392
 
                                                           destination,
393
 
                                                           sql_variant);
 
255
  enum message::TransformSqlError error= transformInsertHeaderToSql(header,
 
256
                                                                    destination,
 
257
                                                                    sql_variant);
394
258
 
395
259
  char quoted_identifier= '`';
396
260
  if (sql_variant == ANSI)
397
261
    quoted_identifier= '"';
398
262
 
399
 
  destination.append(") VALUES (");
 
263
  destination->append(") VALUES (");
400
264
 
401
265
  /* Add insert values */
402
266
  size_t num_fields= header.field_metadata_size();
406
270
  for (x= 0; x < num_fields; ++x)
407
271
  {
408
272
    if (x != 0)
409
 
      destination.push_back(',');
410
 
 
411
 
    const FieldMetadata &field_metadata= header.field_metadata(x);
412
 
 
413
 
    if (record.is_null(x))
414
 
    {
415
 
      should_quote_field_value= false;
416
 
    }
417
 
    else 
418
 
    {
419
 
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
420
 
    }
 
273
      destination->push_back(',');
 
274
 
 
275
    const message::FieldMetadata &field_metadata= header.field_metadata(x);
 
276
 
 
277
    should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
421
278
 
422
279
    if (should_quote_field_value)
423
 
      destination.push_back('\'');
 
280
      destination->push_back('\'');
424
281
 
425
 
    if (record.is_null(x))
 
282
    if (field_metadata.type() == message::Table::Field::BLOB)
426
283
    {
427
 
      destination.append("NULL");
 
284
      /* 
 
285
        * We do this here because BLOB data is returned
 
286
        * in a string correctly, but calling append()
 
287
        * without a length will result in only the string
 
288
        * up to a \0 being output here.
 
289
        */
 
290
      string raw_data(record.insert_value(x));
 
291
      destination->append(raw_data.c_str(), raw_data.size());
428
292
    }
429
293
    else
430
294
    {
431
 
      if (field_metadata.type() == Table::Field::BLOB)
432
 
      {
433
 
        /*
434
 
         * We do this here because BLOB data is returned
435
 
         * in a string correctly, but calling append()
436
 
         * without a length will result in only the string
437
 
         * up to a \0 being output here.
438
 
         */
439
 
        string raw_data(record.insert_value(x));
440
 
        destination.append(raw_data.c_str(), raw_data.size());
441
 
      }
442
 
      else
443
 
      {
444
 
        string tmp(record.insert_value(x));
445
 
        escapeEmbeddedQuotes(tmp);
446
 
        destination.append(tmp);
447
 
      }
 
295
      destination->append(record.insert_value(x));
448
296
    }
449
297
 
450
298
    if (should_quote_field_value)
451
 
      destination.push_back('\'');
 
299
      destination->push_back('\'');
452
300
  }
453
 
  destination.push_back(')');
 
301
  destination->push_back(')');
454
302
 
455
303
  return error;
456
304
}
457
305
 
458
 
enum TransformSqlError
459
 
transformInsertStatementToSql(const InsertHeader &header,
460
 
                              const InsertData &data,
461
 
                              string &destination,
462
 
                              enum TransformSqlVariant sql_variant)
 
306
enum message::TransformSqlError
 
307
message::transformInsertStatementToSql(const message::InsertHeader &header,
 
308
                                       const message::InsertData &data,
 
309
                                       std::string *destination,
 
310
                                       enum message::TransformSqlVariant sql_variant)
463
311
{
464
 
  enum TransformSqlError error= transformInsertHeaderToSql(header,
465
 
                                                           destination,
466
 
                                                           sql_variant);
 
312
  enum message::TransformSqlError error= transformInsertHeaderToSql(header,
 
313
                                                                    destination,
 
314
                                                                    sql_variant);
467
315
 
468
316
  char quoted_identifier= '`';
469
317
  if (sql_variant == ANSI)
470
318
    quoted_identifier= '"';
471
319
 
472
 
  destination.append(") VALUES (", 10);
 
320
  destination->append(") VALUES (", 10);
473
321
 
474
322
  /* Add insert values */
475
323
  size_t num_records= data.record_size();
480
328
  for (x= 0; x < num_records; ++x)
481
329
  {
482
330
    if (x != 0)
483
 
      destination.append("),(", 3);
 
331
      destination->append("),(", 3);
484
332
 
485
333
    for (y= 0; y < num_fields; ++y)
486
334
    {
487
335
      if (y != 0)
488
 
        destination.push_back(',');
 
336
        destination->push_back(',');
489
337
 
490
 
      const FieldMetadata &field_metadata= header.field_metadata(y);
 
338
      const message::FieldMetadata &field_metadata= header.field_metadata(y);
491
339
      
492
 
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
340
      should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
493
341
 
494
342
      if (should_quote_field_value)
495
 
        destination.push_back('\'');
 
343
        destination->push_back('\'');
496
344
 
497
 
      if (field_metadata.type() == Table::Field::BLOB)
 
345
      if (field_metadata.type() == message::Table::Field::BLOB)
498
346
      {
499
347
        /* 
500
348
         * We do this here because BLOB data is returned
503
351
         * up to a \0 being output here.
504
352
         */
505
353
        string raw_data(data.record(x).insert_value(y));
506
 
        destination.append(raw_data.c_str(), raw_data.size());
 
354
        destination->append(raw_data.c_str(), raw_data.size());
507
355
      }
508
356
      else
509
357
      {
510
 
        string tmp(data.record(x).insert_value(y));
511
 
        escapeEmbeddedQuotes(tmp);
512
 
        destination.append(tmp);
 
358
        destination->append(data.record(x).insert_value(y));
513
359
      }
514
360
 
515
361
      if (should_quote_field_value)
516
 
        destination.push_back('\'');
 
362
        destination->push_back('\'');
517
363
    }
518
364
  }
519
 
  destination.push_back(')');
 
365
  destination->push_back(')');
520
366
 
521
367
  return error;
522
368
}
523
369
 
524
 
enum TransformSqlError
525
 
transformUpdateHeaderToSql(const UpdateHeader &header,
526
 
                           string &destination,
527
 
                           enum TransformSqlVariant sql_variant)
 
370
enum message::TransformSqlError
 
371
message::transformUpdateHeaderToSql(const message::UpdateHeader &header,
 
372
                                    std::string *destination,
 
373
                                    enum message::TransformSqlVariant sql_variant)
528
374
{
529
375
  char quoted_identifier= '`';
530
376
  if (sql_variant == ANSI)
531
377
    quoted_identifier= '"';
532
378
 
533
 
  destination.assign("UPDATE ", 7);
534
 
  destination.push_back(quoted_identifier);
535
 
  destination.append(header.table_metadata().schema_name());
536
 
  destination.push_back(quoted_identifier);
537
 
  destination.push_back('.');
538
 
  destination.push_back(quoted_identifier);
539
 
  destination.append(header.table_metadata().table_name());
540
 
  destination.push_back(quoted_identifier);
541
 
  destination.append(" SET ", 5);
 
379
  destination->assign("UPDATE ", 7);
 
380
  destination->push_back(quoted_identifier);
 
381
  destination->append(header.table_metadata().schema_name());
 
382
  destination->push_back(quoted_identifier);
 
383
  destination->push_back('.');
 
384
  destination->push_back(quoted_identifier);
 
385
  destination->append(header.table_metadata().table_name());
 
386
  destination->push_back(quoted_identifier);
 
387
  destination->append(" SET ", 5);
542
388
 
543
389
  return NONE;
544
390
}
545
391
 
546
 
enum TransformSqlError
547
 
transformUpdateRecordToSql(const UpdateHeader &header,
548
 
                           const UpdateRecord &record,
549
 
                           string &destination,
550
 
                           enum TransformSqlVariant sql_variant)
 
392
enum message::TransformSqlError
 
393
message::transformUpdateRecordToSql(const message::UpdateHeader &header,
 
394
                                    const message::UpdateRecord &record,
 
395
                                    std::string *destination,
 
396
                                    enum message::TransformSqlVariant sql_variant)
551
397
{
552
 
  enum TransformSqlError error= transformUpdateHeaderToSql(header,
553
 
                                                           destination,
554
 
                                                           sql_variant);
 
398
  enum message::TransformSqlError error= transformUpdateHeaderToSql(header,
 
399
                                                                    destination,
 
400
                                                                    sql_variant);
555
401
 
556
402
  char quoted_identifier= '`';
557
403
  if (sql_variant == ANSI)
564
410
 
565
411
  for (x= 0; x < num_set_fields; ++x)
566
412
  {
567
 
    const FieldMetadata &field_metadata= header.set_field_metadata(x);
 
413
    const message::FieldMetadata &field_metadata= header.set_field_metadata(x);
568
414
    if (x != 0)
569
 
      destination.push_back(',');
 
415
      destination->push_back(',');
570
416
    
571
 
    destination.push_back(quoted_identifier);
572
 
    destination.append(field_metadata.name());
573
 
    destination.push_back(quoted_identifier);
574
 
    destination.push_back('=');
575
 
 
576
 
    if (record.is_null(x))
577
 
    {
578
 
      should_quote_field_value= false;
579
 
    }
580
 
    else 
581
 
    {
582
 
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
583
 
    }    
584
 
 
585
 
    if (should_quote_field_value)
586
 
      destination.push_back('\'');
587
 
 
588
 
    if (record.is_null(x))
589
 
    {
590
 
      destination.append("NULL");
591
 
    }
592
 
    else 
593
 
    {
594
 
      if (field_metadata.type() == Table::Field::BLOB)
595
 
      {
596
 
        /*
597
 
         * We do this here because BLOB data is returned
598
 
         * in a string correctly, but calling append()
599
 
         * without a length will result in only the string
600
 
         * up to a \0 being output here.
601
 
         */
602
 
        string raw_data(record.after_value(x));
603
 
        destination.append(raw_data.c_str(), raw_data.size());
604
 
      }
605
 
      else 
606
 
      {
607
 
        string tmp(record.after_value(x));
608
 
        escapeEmbeddedQuotes(tmp);
609
 
        destination.append(tmp);
610
 
      }
611
 
    }
612
 
 
613
 
    if (should_quote_field_value)
614
 
      destination.push_back('\'');
 
417
    destination->push_back(quoted_identifier);
 
418
    destination->append(field_metadata.name());
 
419
    destination->push_back(quoted_identifier);
 
420
    destination->push_back('=');
 
421
 
 
422
    should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
 
423
 
 
424
    if (should_quote_field_value)
 
425
      destination->push_back('\'');
 
426
 
 
427
    if (field_metadata.type() == message::Table::Field::BLOB)
 
428
    {
 
429
      /* 
 
430
       * We do this here because BLOB data is returned
 
431
       * in a string correctly, but calling append()
 
432
       * without a length will result in only the string
 
433
       * up to a \0 being output here.
 
434
       */
 
435
      string raw_data(record.after_value(x));
 
436
      destination->append(raw_data.c_str(), raw_data.size());
 
437
    }
 
438
    else
 
439
    {
 
440
      destination->append(record.after_value(x));
 
441
    }
 
442
 
 
443
    if (should_quote_field_value)
 
444
      destination->push_back('\'');
615
445
  }
616
446
 
617
447
  size_t num_key_fields= header.key_field_metadata_size();
618
448
 
619
 
  destination.append(" WHERE ", 7);
 
449
  destination->append(" WHERE ", 7);
620
450
  for (x= 0; x < num_key_fields; ++x) 
621
451
  {
622
 
    const FieldMetadata &field_metadata= header.key_field_metadata(x);
 
452
    const message::FieldMetadata &field_metadata= header.key_field_metadata(x);
623
453
    
624
454
    if (x != 0)
625
 
      destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
626
 
 
627
 
    destination.push_back(quoted_identifier);
628
 
    destination.append(field_metadata.name());
629
 
    destination.push_back(quoted_identifier);
630
 
 
631
 
    destination.push_back('=');
632
 
 
633
 
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
455
      destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
 
456
 
 
457
    destination->push_back(quoted_identifier);
 
458
    destination->append(field_metadata.name());
 
459
    destination->push_back(quoted_identifier);
 
460
 
 
461
    destination->push_back('=');
 
462
 
 
463
    should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
634
464
 
635
465
    if (should_quote_field_value)
636
 
      destination.push_back('\'');
 
466
      destination->push_back('\'');
637
467
 
638
 
    if (field_metadata.type() == Table::Field::BLOB)
 
468
    if (field_metadata.type() == message::Table::Field::BLOB)
639
469
    {
640
470
      /* 
641
471
       * We do this here because BLOB data is returned
644
474
       * up to a \0 being output here.
645
475
       */
646
476
      string raw_data(record.key_value(x));
647
 
      destination.append(raw_data.c_str(), raw_data.size());
 
477
      destination->append(raw_data.c_str(), raw_data.size());
648
478
    }
649
479
    else
650
480
    {
651
 
      destination.append(record.key_value(x));
 
481
      destination->append(record.key_value(x));
652
482
    }
653
483
 
654
484
    if (should_quote_field_value)
655
 
      destination.push_back('\'');
 
485
      destination->push_back('\'');
656
486
  }
 
487
  if (num_key_fields > 1)
 
488
    destination->push_back(')');
657
489
 
658
490
  return error;
659
491
}
660
492
 
661
 
enum TransformSqlError
662
 
transformDeleteHeaderToSql(const DeleteHeader &header,
663
 
                           string &destination,
664
 
                           enum TransformSqlVariant sql_variant)
 
493
enum message::TransformSqlError
 
494
message::transformDeleteHeaderToSql(const message::DeleteHeader &header,
 
495
                                    std::string *destination,
 
496
                                    enum message::TransformSqlVariant sql_variant)
665
497
{
666
498
  char quoted_identifier= '`';
667
499
  if (sql_variant == ANSI)
668
500
    quoted_identifier= '"';
669
501
 
670
 
  destination.assign("DELETE FROM ", 12);
671
 
  destination.push_back(quoted_identifier);
672
 
  destination.append(header.table_metadata().schema_name());
673
 
  destination.push_back(quoted_identifier);
674
 
  destination.push_back('.');
675
 
  destination.push_back(quoted_identifier);
676
 
  destination.append(header.table_metadata().table_name());
677
 
  destination.push_back(quoted_identifier);
 
502
  destination->assign("DELETE FROM ", 12);
 
503
  destination->push_back(quoted_identifier);
 
504
  destination->append(header.table_metadata().schema_name());
 
505
  destination->push_back(quoted_identifier);
 
506
  destination->push_back('.');
 
507
  destination->push_back(quoted_identifier);
 
508
  destination->append(header.table_metadata().table_name());
 
509
  destination->push_back(quoted_identifier);
678
510
 
679
511
  return NONE;
680
512
}
681
513
 
682
 
enum TransformSqlError
683
 
transformDeleteRecordToSql(const DeleteHeader &header,
684
 
                           const DeleteRecord &record,
685
 
                           string &destination,
686
 
                           enum TransformSqlVariant sql_variant)
 
514
enum message::TransformSqlError
 
515
message::transformDeleteRecordToSql(const message::DeleteHeader &header,
 
516
                                    const message::DeleteRecord &record,
 
517
                                    std::string *destination,
 
518
                                    enum message::TransformSqlVariant sql_variant)
687
519
{
688
 
  enum TransformSqlError error= transformDeleteHeaderToSql(header,
689
 
                                                           destination,
690
 
                                                           sql_variant);
 
520
  enum message::TransformSqlError error= transformDeleteHeaderToSql(header,
 
521
                                                                    destination,
 
522
                                                                    sql_variant);
691
523
  char quoted_identifier= '`';
692
524
  if (sql_variant == ANSI)
693
525
    quoted_identifier= '"';
697
529
  uint32_t x;
698
530
  bool should_quote_field_value= false;
699
531
 
700
 
  destination.append(" WHERE ", 7);
 
532
  destination->append(" WHERE ", 7);
701
533
  for (x= 0; x < num_key_fields; ++x) 
702
534
  {
703
 
    const FieldMetadata &field_metadata= header.key_field_metadata(x);
 
535
    const message::FieldMetadata &field_metadata= header.key_field_metadata(x);
704
536
    
705
537
    if (x != 0)
706
 
      destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
707
 
 
708
 
    destination.push_back(quoted_identifier);
709
 
    destination.append(field_metadata.name());
710
 
    destination.push_back(quoted_identifier);
711
 
 
712
 
    destination.push_back('=');
713
 
 
714
 
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
538
      destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
 
539
 
 
540
    destination->push_back(quoted_identifier);
 
541
    destination->append(field_metadata.name());
 
542
    destination->push_back(quoted_identifier);
 
543
 
 
544
    destination->push_back('=');
 
545
 
 
546
    should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
715
547
 
716
548
    if (should_quote_field_value)
717
 
      destination.push_back('\'');
 
549
      destination->push_back('\'');
718
550
 
719
 
    if (field_metadata.type() == Table::Field::BLOB)
 
551
    if (field_metadata.type() == message::Table::Field::BLOB)
720
552
    {
721
553
      /* 
722
554
       * We do this here because BLOB data is returned
725
557
       * up to a \0 being output here.
726
558
       */
727
559
      string raw_data(record.key_value(x));
728
 
      destination.append(raw_data.c_str(), raw_data.size());
 
560
      destination->append(raw_data.c_str(), raw_data.size());
729
561
    }
730
562
    else
731
563
    {
732
 
      string tmp(record.key_value(x));
733
 
      escapeEmbeddedQuotes(tmp);
734
 
      destination.append(tmp);
 
564
      destination->append(record.key_value(x));
735
565
    }
736
566
 
737
567
    if (should_quote_field_value)
738
 
      destination.push_back('\'');
 
568
      destination->push_back('\'');
739
569
  }
740
570
 
741
571
  return error;
742
572
}
743
573
 
744
 
enum TransformSqlError
745
 
transformDeleteStatementToSql(const DeleteHeader &header,
746
 
                              const DeleteData &data,
747
 
                              string &destination,
748
 
                              enum TransformSqlVariant sql_variant)
 
574
enum message::TransformSqlError
 
575
message::transformDeleteStatementToSql(const message::DeleteHeader &header,
 
576
                                       const message::DeleteData &data,
 
577
                                       std::string *destination,
 
578
                                       enum message::TransformSqlVariant sql_variant)
749
579
{
750
 
  enum TransformSqlError error= transformDeleteHeaderToSql(header,
751
 
                                                           destination,
752
 
                                                           sql_variant);
 
580
  enum message::TransformSqlError error= transformDeleteHeaderToSql(header,
 
581
                                                                    destination,
 
582
                                                                    sql_variant);
753
583
  char quoted_identifier= '`';
754
584
  if (sql_variant == ANSI)
755
585
    quoted_identifier= '"';
760
590
  uint32_t x, y;
761
591
  bool should_quote_field_value= false;
762
592
 
763
 
  destination.append(" WHERE ", 7);
 
593
  destination->append(" WHERE ", 7);
764
594
  for (x= 0; x < num_key_records; ++x)
765
595
  {
766
596
    if (x != 0)
767
 
      destination.append(" OR ", 4); /* Always OR condition for multiple key records */
 
597
      destination->append(" OR ", 4); /* Always OR condition for multiple key records */
768
598
 
769
599
    if (num_key_fields > 1)
770
 
      destination.push_back('(');
 
600
      destination->push_back('(');
771
601
 
772
602
    for (y= 0; y < num_key_fields; ++y) 
773
603
    {
774
 
      const FieldMetadata &field_metadata= header.key_field_metadata(y);
 
604
      const message::FieldMetadata &field_metadata= header.key_field_metadata(y);
775
605
      
776
606
      if (y != 0)
777
 
        destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
778
 
 
779
 
      destination.push_back(quoted_identifier);
780
 
      destination.append(field_metadata.name());
781
 
      destination.push_back(quoted_identifier);
782
 
 
783
 
      destination.push_back('=');
784
 
 
785
 
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
607
        destination->append(" AND ", 5); /* Always AND condition with a multi-column PK */
 
608
 
 
609
      destination->push_back(quoted_identifier);
 
610
      destination->append(field_metadata.name());
 
611
      destination->push_back(quoted_identifier);
 
612
 
 
613
      destination->push_back('=');
 
614
 
 
615
      should_quote_field_value= message::shouldQuoteFieldValue(field_metadata.type());
786
616
 
787
617
      if (should_quote_field_value)
788
 
        destination.push_back('\'');
 
618
        destination->push_back('\'');
789
619
 
790
 
      if (field_metadata.type() == Table::Field::BLOB)
 
620
      if (field_metadata.type() == message::Table::Field::BLOB)
791
621
      {
792
622
        /* 
793
623
         * We do this here because BLOB data is returned
796
626
         * up to a \0 being output here.
797
627
         */
798
628
        string raw_data(data.record(x).key_value(y));
799
 
        destination.append(raw_data.c_str(), raw_data.size());
 
629
        destination->append(raw_data.c_str(), raw_data.size());
800
630
      }
801
631
      else
802
632
      {
803
 
        string tmp(data.record(x).key_value(y));
804
 
        escapeEmbeddedQuotes(tmp);
805
 
        destination.append(tmp);
 
633
        destination->append(data.record(x).key_value(y));
806
634
      }
807
635
 
808
636
      if (should_quote_field_value)
809
 
        destination.push_back('\'');
 
637
        destination->push_back('\'');
810
638
    }
811
639
    if (num_key_fields > 1)
812
 
      destination.push_back(')');
 
640
      destination->push_back(')');
813
641
  }
814
642
  return error;
815
643
}
816
644
 
817
 
enum TransformSqlError
818
 
transformAlterSchemaStatementToSql(const AlterSchemaStatement &statement,
819
 
                                   string &destination,
820
 
                                   enum TransformSqlVariant sql_variant)
821
 
{
822
 
  const Schema &before= statement.before();
823
 
  const Schema &after= statement.after();
824
 
 
825
 
  /* Make sure we are given the before and after for the same object */
826
 
  if (before.uuid() != after.uuid())
827
 
    return UUID_MISMATCH;
828
 
 
829
 
  char quoted_identifier= '`';
830
 
  if (sql_variant == ANSI)
831
 
    quoted_identifier= '"';
832
 
 
833
 
  destination.append("ALTER SCHEMA ");
834
 
  destination.push_back(quoted_identifier);
835
 
  destination.append(before.name());
836
 
  destination.push_back(quoted_identifier);
837
 
 
838
 
  /*
839
 
   * Diff our schemas. Currently, only collation can change so a
840
 
   * diff of the two structures is not really necessary.
841
 
   */
842
 
  destination.append(" COLLATE = ");
843
 
  destination.append(after.collation());
844
 
 
845
 
  return NONE;
846
 
}
847
 
 
848
 
enum TransformSqlError
849
 
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
850
 
                                  string &destination,
851
 
                                  enum TransformSqlVariant sql_variant)
852
 
{
853
 
  char quoted_identifier= '`';
854
 
  if (sql_variant == ANSI)
855
 
    quoted_identifier= '"';
856
 
 
857
 
  destination.append("DROP SCHEMA ", 12);
858
 
  destination.push_back(quoted_identifier);
859
 
  destination.append(statement.schema_name());
860
 
  destination.push_back(quoted_identifier);
861
 
 
862
 
  return NONE;
863
 
}
864
 
 
865
 
enum TransformSqlError
866
 
transformCreateSchemaStatementToSql(const CreateSchemaStatement &statement,
867
 
                                    string &destination,
868
 
                                    enum TransformSqlVariant sql_variant)
869
 
{
870
 
  char quoted_identifier= '`';
871
 
  if (sql_variant == ANSI)
872
 
    quoted_identifier= '"';
873
 
 
874
 
  const Schema &schema= statement.schema();
875
 
 
876
 
  destination.append("CREATE SCHEMA ");
877
 
  destination.push_back(quoted_identifier);
878
 
  destination.append(schema.name());
879
 
  destination.push_back(quoted_identifier);
880
 
 
881
 
  if (schema.has_collation())
882
 
  {
883
 
    destination.append(" COLLATE ");
884
 
    destination.append(schema.collation());
885
 
  }
886
 
 
887
 
  if (schema.has_replication_options() and schema.replication_options().has_dont_replicate() and schema.replication_options().dont_replicate())
888
 
  {
889
 
    destination.append(" REPLICATION = FALSE");
890
 
  }
891
 
 
892
 
  return NONE;
893
 
}
894
 
 
895
 
enum TransformSqlError
896
 
transformDropTableStatementToSql(const DropTableStatement &statement,
897
 
                                 string &destination,
898
 
                                 enum TransformSqlVariant sql_variant)
899
 
{
900
 
  char quoted_identifier= '`';
901
 
  if (sql_variant == ANSI)
902
 
    quoted_identifier= '"';
903
 
 
904
 
  const TableMetadata &table_metadata= statement.table_metadata();
905
 
 
906
 
  destination.append("DROP TABLE ");
907
 
 
908
 
  /* Add the IF EXISTS clause if necessary */
909
 
  if (statement.has_if_exists_clause() &&
910
 
      statement.if_exists_clause() == true)
911
 
  {
912
 
    destination.append("IF EXISTS ");
913
 
  }
914
 
 
915
 
  destination.push_back(quoted_identifier);
916
 
  destination.append(table_metadata.schema_name());
917
 
  destination.push_back(quoted_identifier);
918
 
  destination.push_back('.');
919
 
  destination.push_back(quoted_identifier);
920
 
  destination.append(table_metadata.table_name());
921
 
  destination.push_back(quoted_identifier);
922
 
 
923
 
  return NONE;
924
 
}
925
 
 
926
 
enum TransformSqlError
927
 
transformTruncateTableStatementToSql(const TruncateTableStatement &statement,
928
 
                                     string &destination,
929
 
                                     enum TransformSqlVariant sql_variant)
930
 
{
931
 
  char quoted_identifier= '`';
932
 
  if (sql_variant == ANSI)
933
 
    quoted_identifier= '"';
934
 
 
935
 
  const TableMetadata &table_metadata= statement.table_metadata();
936
 
 
937
 
  destination.append("TRUNCATE TABLE ");
938
 
  destination.push_back(quoted_identifier);
939
 
  destination.append(table_metadata.schema_name());
940
 
  destination.push_back(quoted_identifier);
941
 
  destination.push_back('.');
942
 
  destination.push_back(quoted_identifier);
943
 
  destination.append(table_metadata.table_name());
944
 
  destination.push_back(quoted_identifier);
945
 
 
946
 
  return NONE;
947
 
}
948
 
 
949
 
enum TransformSqlError
950
 
transformSetVariableStatementToSql(const SetVariableStatement &statement,
951
 
                                   string &destination,
952
 
                                   enum TransformSqlVariant sql_variant)
 
645
enum message::TransformSqlError
 
646
message::transformTruncateTableStatementToSql(const message::TruncateTableStatement &statement,
 
647
                                              std::string *destination,
 
648
                                              enum message::TransformSqlVariant sql_variant)
 
649
{
 
650
  char quoted_identifier= '`';
 
651
  if (sql_variant == ANSI)
 
652
    quoted_identifier= '"';
 
653
 
 
654
  const message::TableMetadata &table_metadata= statement.table_metadata();
 
655
 
 
656
  destination->append("TRUNCATE TABLE ", 15);
 
657
  destination->push_back(quoted_identifier);
 
658
  destination->append(table_metadata.schema_name());
 
659
  destination->push_back(quoted_identifier);
 
660
  destination->push_back('.');
 
661
  destination->push_back(quoted_identifier);
 
662
  destination->append(table_metadata.table_name());
 
663
  destination->push_back(quoted_identifier);
 
664
 
 
665
  return NONE;
 
666
}
 
667
 
 
668
enum message::TransformSqlError
 
669
message::transformSetVariableStatementToSql(const message::SetVariableStatement &statement,
 
670
                                            std::string *destination,
 
671
                                            enum message::TransformSqlVariant sql_variant)
953
672
{
954
673
  (void) sql_variant;
955
 
  const FieldMetadata &variable_metadata= statement.variable_metadata();
956
 
  bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
957
 
 
958
 
  destination.append("SET GLOBAL "); /* Only global variables are replicated */
959
 
  destination.append(variable_metadata.name());
960
 
  destination.push_back('=');
961
 
 
962
 
  if (should_quote_field_value)
963
 
    destination.push_back('\'');
964
 
  
965
 
  destination.append(statement.variable_value());
966
 
 
967
 
  if (should_quote_field_value)
968
 
    destination.push_back('\'');
969
 
 
970
 
  return NONE;
971
 
}
972
 
 
973
 
enum TransformSqlError
974
 
transformCreateTableStatementToSql(const CreateTableStatement &statement,
975
 
                                   string &destination,
976
 
                                   enum TransformSqlVariant sql_variant)
977
 
{
978
 
  return transformTableDefinitionToSql(statement.table(), destination, sql_variant);
979
 
}
980
 
 
981
 
enum TransformSqlError
982
 
transformTableDefinitionToSql(const Table &table,
983
 
                              string &destination,
984
 
                              enum TransformSqlVariant sql_variant, bool with_schema)
985
 
{
986
 
  char quoted_identifier= '`';
987
 
  if (sql_variant == ANSI)
988
 
    quoted_identifier= '"';
989
 
 
990
 
  destination.append("CREATE ");
991
 
 
992
 
  if (table.type() == Table::TEMPORARY)
993
 
    destination.append("TEMPORARY ");
994
 
  
995
 
  destination.append("TABLE ");
996
 
  if (with_schema)
997
 
  {
998
 
    append_escaped_string(&destination, table.schema(), quoted_identifier);
999
 
    destination.push_back('.');
1000
 
  }
1001
 
  append_escaped_string(&destination, table.name(), quoted_identifier);
1002
 
  destination.append(" (\n");
1003
 
 
1004
 
  enum TransformSqlError result= NONE;
1005
 
  size_t num_fields= table.field_size();
1006
 
  for (size_t x= 0; x < num_fields; ++x)
1007
 
  {
1008
 
    const Table::Field &field= table.field(x);
1009
 
 
1010
 
    if (x != 0)
1011
 
      destination.append(",\n");
1012
 
 
1013
 
    destination.append("  ");
1014
 
 
1015
 
    result= transformFieldDefinitionToSql(field, destination, sql_variant);
1016
 
 
1017
 
    if (result != NONE)
1018
 
      return result;
1019
 
  }
1020
 
 
1021
 
  size_t num_indexes= table.indexes_size();
1022
 
  
1023
 
  if (num_indexes > 0)
1024
 
    destination.append(",\n");
1025
 
 
1026
 
  for (size_t x= 0; x < num_indexes; ++x)
1027
 
  {
1028
 
    const message::Table::Index &index= table.indexes(x);
1029
 
 
1030
 
    if (x != 0)
1031
 
      destination.append(",\n");
1032
 
 
1033
 
    result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
1034
 
    
1035
 
    if (result != NONE)
1036
 
      return result;
1037
 
  }
1038
 
 
1039
 
  size_t num_foreign_keys= table.fk_constraint_size();
1040
 
 
1041
 
  if (num_foreign_keys > 0)
1042
 
    destination.append(",\n");
1043
 
 
1044
 
  for (size_t x= 0; x < num_foreign_keys; ++x)
1045
 
  {
1046
 
    const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
1047
 
 
1048
 
    if (x != 0)
1049
 
      destination.append(",\n");
1050
 
 
1051
 
    result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1052
 
 
1053
 
    if (result != NONE)
1054
 
      return result;
1055
 
  }
1056
 
 
1057
 
  destination.append("\n)");
1058
 
 
1059
 
  /* Add ENGINE = " clause */
1060
 
  if (table.has_engine())
1061
 
  {
1062
 
    destination.append(" ENGINE=");
1063
 
    destination.append(table.engine().name());
1064
 
 
1065
 
    size_t num_engine_options= table.engine().options_size();
1066
 
    if (num_engine_options > 0)
1067
 
      destination.append(" ", 1);
1068
 
    for (size_t x= 0; x < num_engine_options; ++x)
1069
 
    {
1070
 
      const Engine::Option &option= table.engine().options(x);
1071
 
      destination.append(option.name());
1072
 
      destination.append("='");
1073
 
      destination.append(option.state());
1074
 
      destination.append("'");
1075
 
      if (x != num_engine_options-1)
1076
 
      {
1077
 
        destination.append(", ");
1078
 
      }
1079
 
    }
1080
 
  }
1081
 
 
1082
 
  if (table.has_options())
1083
 
    (void) transformTableOptionsToSql(table.options(), destination, sql_variant);
1084
 
 
1085
 
  return NONE;
1086
 
}
1087
 
 
1088
 
enum TransformSqlError
1089
 
transformTableOptionsToSql(const Table::TableOptions &options,
1090
 
                           string &destination,
1091
 
                           enum TransformSqlVariant sql_variant)
1092
 
{
1093
 
  if (sql_variant == ANSI)
1094
 
    return NONE; /* ANSI does not support table options... */
1095
 
 
1096
 
  if (options.has_comment())
1097
 
  {
1098
 
    destination.append(" COMMENT=");
1099
 
    append_escaped_string(&destination, options.comment());
1100
 
  }
1101
 
 
1102
 
  if (options.has_collation())
1103
 
  {
1104
 
    destination.append(" COLLATE = ");
1105
 
    destination.append(options.collation());
1106
 
  }
1107
 
 
1108
 
  if (options.has_data_file_name())
1109
 
  {
1110
 
    destination.append("\nDATA_FILE_NAME = '");
1111
 
    destination.append(options.data_file_name());
1112
 
    destination.push_back('\'');
1113
 
  }
1114
 
 
1115
 
  if (options.has_index_file_name())
1116
 
  {
1117
 
    destination.append("\nINDEX_FILE_NAME = '");
1118
 
    destination.append(options.index_file_name());
1119
 
    destination.push_back('\'');
1120
 
  }
1121
 
 
1122
 
  if (options.has_max_rows())
1123
 
  {
1124
 
    destination.append("\nMAX_ROWS = ");
1125
 
    destination.append(boost::lexical_cast<string>(options.max_rows()));
1126
 
  }
1127
 
 
1128
 
  if (options.has_min_rows())
1129
 
  {
1130
 
    destination.append("\nMIN_ROWS = ");
1131
 
    destination.append(boost::lexical_cast<string>(options.min_rows()));
1132
 
  }
1133
 
 
1134
 
  if (options.has_user_set_auto_increment_value()
1135
 
      && options.has_auto_increment_value())
1136
 
  {
1137
 
    destination.append(" AUTO_INCREMENT=");
1138
 
    destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
1139
 
  }
1140
 
 
1141
 
  if (options.has_avg_row_length())
1142
 
  {
1143
 
    destination.append("\nAVG_ROW_LENGTH = ");
1144
 
    destination.append(boost::lexical_cast<string>(options.avg_row_length()));
1145
 
  }
1146
 
 
1147
 
  if (options.has_checksum() && options.checksum())
1148
 
    destination.append("\nCHECKSUM = TRUE");
1149
 
 
1150
 
  if (options.has_page_checksum() && options.page_checksum())
1151
 
    destination.append("\nPAGE_CHECKSUM = TRUE");
1152
 
 
1153
 
  if (options.has_dont_replicate() and options.dont_replicate())
1154
 
  {
1155
 
    destination.append(" REPLICATION = FALSE");
1156
 
  }
1157
 
 
1158
 
  return NONE;
1159
 
}
1160
 
 
1161
 
enum TransformSqlError
1162
 
transformIndexDefinitionToSql(const Table::Index &index,
1163
 
                              const Table &table,
1164
 
                              string &destination,
1165
 
                              enum TransformSqlVariant sql_variant)
1166
 
{
1167
 
  char quoted_identifier= '`';
1168
 
  if (sql_variant == ANSI)
1169
 
    quoted_identifier= '"';
1170
 
 
1171
 
  destination.append("  ", 2);
1172
 
 
1173
 
  if (index.is_primary())
1174
 
    destination.append("PRIMARY ");
1175
 
  else if (index.is_unique())
1176
 
    destination.append("UNIQUE ");
1177
 
 
1178
 
  destination.append("KEY ", 4);
1179
 
  if (! (index.is_primary() && index.name().compare("PRIMARY")==0))
1180
 
  {
1181
 
    destination.push_back(quoted_identifier);
1182
 
    destination.append(index.name());
1183
 
    destination.push_back(quoted_identifier);
1184
 
    destination.append(" (", 2);
1185
 
  }
1186
 
  else
1187
 
    destination.append("(", 1);
1188
 
 
1189
 
  size_t num_parts= index.index_part_size();
1190
 
  for (size_t x= 0; x < num_parts; ++x)
1191
 
  {
1192
 
    const Table::Index::IndexPart &part= index.index_part(x);
1193
 
    const Table::Field &field= table.field(part.fieldnr());
1194
 
 
1195
 
    if (x != 0)
1196
 
      destination.push_back(',');
1197
 
    
1198
 
    destination.push_back(quoted_identifier);
1199
 
    destination.append(field.name());
1200
 
    destination.push_back(quoted_identifier);
1201
 
 
1202
 
    /* 
1203
 
     * If the index part's field type is VARCHAR or TEXT
1204
 
     * then check for a prefix length then is different
1205
 
     * from the field's full length...
1206
 
     */
1207
 
    if (field.type() == Table::Field::VARCHAR ||
1208
 
        field.type() == Table::Field::BLOB)
1209
 
    {
1210
 
      if (part.has_compare_length())
1211
 
      {
1212
 
        if (part.compare_length() != field.string_options().length())
1213
 
        {
1214
 
          destination.push_back('(');
1215
 
          destination.append(boost::lexical_cast<string>(part.compare_length()));
1216
 
          destination.push_back(')');
1217
 
        }
1218
 
      }
1219
 
    }
1220
 
  }
1221
 
  destination.push_back(')');
1222
 
 
1223
 
  switch (index.type())
1224
 
  {
1225
 
  case Table::Index::UNKNOWN_INDEX:
1226
 
    break;
1227
 
  case Table::Index::BTREE:
1228
 
    destination.append(" USING BTREE");
1229
 
    break;
1230
 
  case Table::Index::RTREE:
1231
 
    destination.append(" USING RTREE");
1232
 
    break;
1233
 
  case Table::Index::HASH:
1234
 
    destination.append(" USING HASH");
1235
 
    break;
1236
 
  case Table::Index::FULLTEXT:
1237
 
    destination.append(" USING FULLTEXT");
1238
 
    break;
1239
 
  }
1240
 
 
1241
 
  if (index.has_comment())
1242
 
  {
1243
 
    destination.append(" COMMENT ");
1244
 
    append_escaped_string(&destination, index.comment());
1245
 
  }
1246
 
 
1247
 
  return NONE;
1248
 
}
1249
 
 
1250
 
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
1251
 
{
1252
 
  switch (opt)
1253
 
  {
1254
 
  case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1255
 
    destination.append("RESTRICT");
1256
 
    break;
1257
 
  case Table::ForeignKeyConstraint::OPTION_CASCADE:
1258
 
    destination.append("CASCADE");
1259
 
    break;
1260
 
  case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1261
 
    destination.append("SET NULL");
1262
 
    break;
1263
 
  case Table::ForeignKeyConstraint::OPTION_UNDEF:
1264
 
  case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1265
 
    destination.append("NO ACTION");
1266
 
    break;
1267
 
  case Table::ForeignKeyConstraint::OPTION_SET_DEFAULT:
1268
 
    destination.append("SET DEFAULT");
1269
 
    break;
1270
 
  }
1271
 
}
1272
 
 
1273
 
enum TransformSqlError
1274
 
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
1275
 
                                             const Table &,
1276
 
                                             string &destination,
1277
 
                                             enum TransformSqlVariant sql_variant)
1278
 
{
1279
 
  char quoted_identifier= '`';
1280
 
  if (sql_variant == ANSI)
1281
 
    quoted_identifier= '"';
1282
 
 
1283
 
  destination.append("  ");
1284
 
 
1285
 
  if (fkey.has_name())
1286
 
  {
1287
 
    destination.append("CONSTRAINT ");
1288
 
    append_escaped_string(&destination, fkey.name(), quoted_identifier);
1289
 
    destination.append(" ", 1);
1290
 
  }
1291
 
 
1292
 
  destination.append("FOREIGN KEY (");
1293
 
 
1294
 
  for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1295
 
  {
1296
 
    if (x != 0)
1297
 
      destination.append(", ");
1298
 
 
1299
 
    append_escaped_string(&destination, fkey.column_names(x),
1300
 
                          quoted_identifier);
1301
 
  }
1302
 
 
1303
 
  destination.append(") REFERENCES ");
1304
 
 
1305
 
  append_escaped_string(&destination, fkey.references_table_name(),
1306
 
                        quoted_identifier);
1307
 
  destination.append(" (");
1308
 
 
1309
 
  for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1310
 
  {
1311
 
    if (x != 0)
1312
 
      destination.append(", ");
1313
 
 
1314
 
    append_escaped_string(&destination, fkey.references_columns(x),
1315
 
                          quoted_identifier);
1316
 
  }
1317
 
 
1318
 
  destination.push_back(')');
1319
 
 
1320
 
  if (fkey.has_update_option() and fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1321
 
  {
1322
 
    destination.append(" ON UPDATE ");
1323
 
    transformForeignKeyOptionToSql(fkey.update_option(), destination);
1324
 
  }
1325
 
 
1326
 
  if (fkey.has_delete_option() and fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1327
 
  {
1328
 
    destination.append(" ON DELETE ");
1329
 
    transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1330
 
  }
1331
 
 
1332
 
  return NONE;
1333
 
}
1334
 
 
1335
 
enum TransformSqlError
1336
 
transformFieldDefinitionToSql(const Table::Field &field,
1337
 
                              string &destination,
1338
 
                              enum TransformSqlVariant sql_variant)
1339
 
{
1340
 
  char quoted_identifier= '`';
1341
 
  char quoted_default;
1342
 
 
1343
 
  if (sql_variant == ANSI)
1344
 
    quoted_identifier= '"';
1345
 
 
1346
 
  if (sql_variant == DRIZZLE)
1347
 
    quoted_default= '\'';
1348
 
  else
1349
 
    quoted_default= quoted_identifier;
1350
 
 
1351
 
  append_escaped_string(&destination, field.name(), quoted_identifier);
1352
 
 
1353
 
  Table::Field::FieldType field_type= field.type();
1354
 
 
1355
 
  switch (field_type)
1356
 
  {
1357
 
    case Table::Field::DOUBLE:
1358
 
    destination.append(" DOUBLE");
1359
 
    if (field.has_numeric_options()
1360
 
        && field.numeric_options().has_precision())
1361
 
    {
1362
 
      stringstream ss;
1363
 
      ss << "(" << field.numeric_options().precision() << ",";
1364
 
      ss << field.numeric_options().scale() << ")";
1365
 
      destination.append(ss.str());
1366
 
    }
1367
 
    break;
1368
 
  case Table::Field::VARCHAR:
1369
 
    {
1370
 
      if (field.string_options().has_collation()
1371
 
          && field.string_options().collation().compare("binary") == 0)
1372
 
        destination.append(" VARBINARY(");
1373
 
      else
1374
 
        destination.append(" VARCHAR(");
1375
 
 
1376
 
      destination.append(boost::lexical_cast<string>(field.string_options().length()));
1377
 
      destination.append(")");
1378
 
    }
1379
 
    break;
1380
 
  case Table::Field::BLOB:
1381
 
    {
1382
 
      if (field.string_options().has_collation()
1383
 
          && field.string_options().collation().compare("binary") == 0)
1384
 
        destination.append(" BLOB");
1385
 
      else
1386
 
        destination.append(" TEXT");
1387
 
    }
1388
 
    break;
1389
 
  case Table::Field::ENUM:
1390
 
    {
1391
 
      size_t num_field_values= field.enumeration_values().field_value_size();
1392
 
      destination.append(" ENUM(");
1393
 
      for (size_t x= 0; x < num_field_values; ++x)
1394
 
      {
1395
 
        const string &type= field.enumeration_values().field_value(x);
1396
 
 
1397
 
        if (x != 0)
1398
 
          destination.push_back(',');
1399
 
 
1400
 
        destination.push_back('\'');
1401
 
        destination.append(type);
1402
 
        destination.push_back('\'');
1403
 
      }
1404
 
      destination.push_back(')');
1405
 
      break;
1406
 
    }
1407
 
  case Table::Field::UUID:
1408
 
    destination.append(" UUID");
1409
 
    break;
1410
 
  case Table::Field::BOOLEAN:
1411
 
    destination.append(" BOOLEAN");
1412
 
    break;
1413
 
  case Table::Field::INTEGER:
1414
 
    destination.append(" INT");
1415
 
    break;
1416
 
  case Table::Field::BIGINT:
1417
 
    if (field.has_constraints() and
1418
 
        field.constraints().is_unsigned())
1419
 
    {
1420
 
      destination.append(" BIGINT UNSIGNED");
1421
 
    }
1422
 
    else
1423
 
    {
1424
 
      destination.append(" BIGINT");
1425
 
    }
1426
 
    break;
1427
 
  case Table::Field::DECIMAL:
1428
 
    {
1429
 
      destination.append(" DECIMAL(");
1430
 
      stringstream ss;
1431
 
      ss << field.numeric_options().precision() << ",";
1432
 
      ss << field.numeric_options().scale() << ")";
1433
 
      destination.append(ss.str());
1434
 
    }
1435
 
    break;
1436
 
  case Table::Field::DATE:
1437
 
    destination.append(" DATE");
1438
 
    break;
1439
 
 
1440
 
  case Table::Field::EPOCH:
1441
 
    if (field.time_options().microseconds())
1442
 
    {
1443
 
      destination.append(" TIMESTAMP(6)");
1444
 
    }
1445
 
    else
1446
 
    {
1447
 
      destination.append(" TIMESTAMP");
1448
 
    }
1449
 
    break;
1450
 
 
1451
 
  case Table::Field::DATETIME:
1452
 
    destination.append(" DATETIME");
1453
 
    break;
1454
 
  case Table::Field::TIME:
1455
 
    destination.append(" TIME");
1456
 
    break;
1457
 
  }
1458
 
 
1459
 
  if (field.type() == Table::Field::BLOB ||
1460
 
      field.type() == Table::Field::VARCHAR)
1461
 
  {
1462
 
    if (field.string_options().has_collation()
1463
 
        && field.string_options().collation().compare("binary"))
1464
 
    {
1465
 
      destination.append(" COLLATE ");
1466
 
      destination.append(field.string_options().collation());
1467
 
    }
1468
 
  }
1469
 
 
1470
 
  if (field.has_constraints() and field.constraints().is_unique())
1471
 
  {
1472
 
    destination.append(" UNIQUE");
1473
 
  }
1474
 
 
1475
 
  if (field.has_constraints() && field.constraints().is_notnull())
1476
 
  {
1477
 
    destination.append(" NOT NULL");
1478
 
  }
1479
 
  else if (field.type() == Table::Field::EPOCH)
1480
 
  {
1481
 
    destination.append(" NULL");
1482
 
  }
1483
 
 
1484
 
  if (field.type() == Table::Field::INTEGER || 
1485
 
      field.type() == Table::Field::BIGINT)
1486
 
  {
1487
 
    /* AUTO_INCREMENT must be after NOT NULL */
1488
 
    if (field.has_numeric_options() &&
1489
 
        field.numeric_options().is_autoincrement())
1490
 
    {
1491
 
      destination.append(" AUTO_INCREMENT");
1492
 
    }
1493
 
  }
1494
 
 
1495
 
  if (field.options().has_default_value())
1496
 
  {
1497
 
    destination.append(" DEFAULT ");
1498
 
    append_escaped_string(&destination, field.options().default_value());
1499
 
  }
1500
 
  else if (field.options().has_default_expression())
1501
 
  {
1502
 
    destination.append(" DEFAULT ");
1503
 
    destination.append(field.options().default_expression());
1504
 
  }
1505
 
  else if (field.options().has_default_bin_value())
1506
 
  {
1507
 
    const string &v= field.options().default_bin_value();
1508
 
    if (v.length() == 0)
1509
 
    {
1510
 
      destination.append(" DEFAULT ''");
1511
 
    }
1512
 
    else
1513
 
    {
1514
 
      destination.append(" DEFAULT 0x");
1515
 
      for (size_t x= 0; x < v.length(); x++)
1516
 
      {
1517
 
        char hex[3];
1518
 
        snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
1519
 
        destination.append(hex, 2);
1520
 
      }
1521
 
    }
1522
 
  }
1523
 
  else if (field.options().has_default_null()
1524
 
           && field.options().default_null()
1525
 
           && field.type() != Table::Field::BLOB)
1526
 
  {
1527
 
    destination.append(" DEFAULT NULL");
1528
 
  }
1529
 
 
1530
 
  if (field.has_options() && field.options().has_update_expression())
1531
 
  {
1532
 
    destination.append(" ON UPDATE ");
1533
 
    destination.append(field.options().update_expression());
1534
 
  }
1535
 
 
1536
 
  if (field.has_comment())
1537
 
  {
1538
 
    destination.append(" COMMENT ");
1539
 
    append_escaped_string(&destination, field.comment(), quoted_default);
1540
 
  }
1541
 
  return NONE;
1542
 
}
1543
 
 
1544
 
bool shouldQuoteFieldValue(Table::Field::FieldType in_type)
 
674
  const message::FieldMetadata &variable_metadata= statement.variable_metadata();
 
675
  bool should_quote_field_value= message::shouldQuoteFieldValue(variable_metadata.type());
 
676
 
 
677
  destination->append("SET GLOBAL ", 11); /* Only global variables are replicated */
 
678
  destination->append(variable_metadata.name());
 
679
  destination->push_back('=');
 
680
 
 
681
  if (should_quote_field_value)
 
682
    destination->push_back('\'');
 
683
  
 
684
  destination->append(statement.variable_value());
 
685
 
 
686
  if (should_quote_field_value)
 
687
    destination->push_back('\'');
 
688
 
 
689
  return NONE;
 
690
}
 
691
 
 
692
bool message::shouldQuoteFieldValue(message::Table::Field::FieldType in_type)
1545
693
{
1546
694
  switch (in_type)
1547
695
  {
1548
 
  case Table::Field::DOUBLE:
1549
 
  case Table::Field::DECIMAL:
1550
 
  case Table::Field::INTEGER:
1551
 
  case Table::Field::BIGINT:
 
696
  case message::Table::Field::DOUBLE:
 
697
  case message::Table::Field::DECIMAL:
 
698
  case message::Table::Field::INTEGER:
 
699
  case message::Table::Field::BIGINT:
 
700
  case message::Table::Field::ENUM:
1552
701
    return false;
1553
702
  default:
1554
703
    return true;
1555
704
  } 
1556
705
}
1557
 
 
1558
 
Table::Field::FieldType internalFieldTypeToFieldProtoType(enum enum_field_types type)
1559
 
{
1560
 
  switch (type) {
1561
 
  case DRIZZLE_TYPE_LONG:
1562
 
    return Table::Field::INTEGER;
1563
 
  case DRIZZLE_TYPE_DOUBLE:
1564
 
    return Table::Field::DOUBLE;
1565
 
  case DRIZZLE_TYPE_NULL:
1566
 
    assert(false); /* Not a user definable type */
1567
 
    return Table::Field::INTEGER; /* unreachable */
1568
 
  case DRIZZLE_TYPE_MICROTIME:
1569
 
  case DRIZZLE_TYPE_TIMESTAMP:
1570
 
    return Table::Field::EPOCH;
1571
 
  case DRIZZLE_TYPE_LONGLONG:
1572
 
    return Table::Field::BIGINT;
1573
 
  case DRIZZLE_TYPE_DATETIME:
1574
 
    return Table::Field::DATETIME;
1575
 
  case DRIZZLE_TYPE_TIME:
1576
 
    return Table::Field::TIME;
1577
 
  case DRIZZLE_TYPE_DATE:
1578
 
    return Table::Field::DATE;
1579
 
  case DRIZZLE_TYPE_VARCHAR:
1580
 
    return Table::Field::VARCHAR;
1581
 
  case DRIZZLE_TYPE_DECIMAL:
1582
 
    return Table::Field::DECIMAL;
1583
 
  case DRIZZLE_TYPE_ENUM:
1584
 
    return Table::Field::ENUM;
1585
 
  case DRIZZLE_TYPE_BLOB:
1586
 
    return Table::Field::BLOB;
1587
 
  case DRIZZLE_TYPE_UUID:
1588
 
    return Table::Field::UUID;
1589
 
  case DRIZZLE_TYPE_BOOLEAN:
1590
 
    return Table::Field::BOOLEAN;
1591
 
  }
1592
 
 
1593
 
  assert(false);
1594
 
  return Table::Field::INTEGER; /* unreachable */
1595
 
}
1596
 
 
1597
 
bool transactionContainsBulkSegment(const Transaction &transaction)
1598
 
{
1599
 
  size_t num_statements= transaction.statement_size();
1600
 
  if (num_statements == 0)
1601
 
    return false;
1602
 
 
1603
 
  /*
1604
 
   * Only INSERT, UPDATE, and DELETE statements can possibly
1605
 
   * have bulk segments.  So, we loop through the statements
1606
 
   * checking for segment_id > 1 in those specific submessages.
1607
 
   */
1608
 
  size_t x;
1609
 
  for (x= 0; x < num_statements; ++x)
1610
 
  {
1611
 
    const Statement &statement= transaction.statement(x);
1612
 
    Statement::Type type= statement.type();
1613
 
 
1614
 
    switch (type)
1615
 
    {
1616
 
      case Statement::INSERT:
1617
 
        if (statement.insert_data().segment_id() > 1)
1618
 
          return true;
1619
 
        break;
1620
 
      case Statement::UPDATE:
1621
 
        if (statement.update_data().segment_id() > 1)
1622
 
          return true;
1623
 
        break;
1624
 
      case Statement::DELETE:
1625
 
        if (statement.delete_data().segment_id() > 1)
1626
 
          return true;
1627
 
        break;
1628
 
      default:
1629
 
        break;
1630
 
    }
1631
 
  }
1632
 
  return false;
1633
 
}
1634
 
 
1635
 
} /* namespace message */
1636
 
} /* namespace drizzled */