~drizzle-trunk/drizzle/development

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