~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

Added pandora check for berkeley db.

Show diffs side-by-side

added added

removed removed

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