~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
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
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>
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
35
#include "drizzled/message/statement_transform.h"
36
#include "drizzled/message/transaction.pb.h"
37
#include "drizzled/message/table.pb.h"
1638.10.28 by Stewart Smith
fix a lot of quoting and escaping of things in SHOW CREATE TABLE in statement_transform
38
#include "drizzled/charset.h"
39
#include "drizzled/charset_info.h"
40
#include "drizzled/global_charset_info.h"
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
41
42
#include <string>
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
43
#include <vector>
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
44
#include <sstream>
1502.3.1 by iwamatsu at nigauri
Add cstdio include to files needing it. Fixes the build on some debian
45
#include <cstdio>
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
46
47
using namespace std;
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
48
49
namespace drizzled
50
{
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
51
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
52
namespace message
53
{
54
1785.2.1 by David Shrewsbury
When converting transaction log contents to SQL, make sure we escape embedded quotes.
55
static void escapeEmbeddedQuotes(string &s, const char quote='\'')
56
{
57
  string::iterator it;
58
59
  for (it= s.begin(); it != s.end(); ++it)
60
  {
61
    if (*it == quote)
62
    {
63
      it= s.insert(it, quote);
64
      ++it;  // advance back to the quote
65
    }
66
  }
67
}
68
1638.10.28 by Stewart Smith
fix a lot of quoting and escaping of things in SHOW CREATE TABLE in statement_transform
69
/* Incredibly similar to append_unescaped() in table.cc, but for std::string */
70
static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
71
{
72
  const char *pos= input.c_str();
73
  const char *end= input.c_str()+input.length();
74
  res->push_back(quote);
75
76
  for (; pos != end ; pos++)
77
  {
78
    uint32_t mblen;
79
    if (use_mb(default_charset_info) &&
80
        (mblen= my_ismbchar(default_charset_info, pos, end)))
81
    {
82
      res->append(pos, mblen);
83
      pos+= mblen - 1;
84
      if (pos >= end)
85
        break;
86
      continue;
87
    }
88
89
    switch (*pos) {
90
    case 0:				/* Must be escaped for 'mysql' */
91
      res->push_back('\\');
92
      res->push_back('0');
93
      break;
94
    case '\n':				/* Must be escaped for logs */
95
      res->push_back('\\');
96
      res->push_back('n');
97
      break;
98
    case '\r':
99
      res->push_back('\\');		/* This gives better readability */
100
      res->push_back('r');
101
      break;
102
    case '\\':
103
      res->push_back('\\');		/* Because of the sql syntax */
104
      res->push_back('\\');
105
      break;
106
    default:
107
      if (*pos == quote) /* SQL syntax for quoting a quote */
108
      {
109
        res->push_back(quote);
110
        res->push_back(quote);
111
      }
112
      else
113
        res->push_back(*pos);
114
      break;
115
    }
116
  }
117
  res->push_back(quote);
118
}
119
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
120
enum TransformSqlError
121
transformStatementToSql(const Statement &source,
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
122
                        vector<string> &sql_strings,
123
                        enum TransformSqlVariant sql_variant,
124
                        bool already_in_transaction)
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
125
{
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
126
  TransformSqlError error= NONE;
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
127
128
  switch (source.type())
129
  {
1976.8.2 by David Shrewsbury
Support rollback of segmented statements ; removed unnecessary code for --replicate-query (didn't work correctly anyway).
130
  case Statement::ROLLBACK_STATEMENT:
131
    {
132
      break;
133
    }
1820.2.1 by David Shrewsbury
Fix for transaction_reader to output ROLLBACK statements
134
  case Statement::ROLLBACK:
135
    {
136
      sql_strings.push_back("ROLLBACK");
137
      break;
138
    }
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
139
  case Statement::INSERT:
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
140
    {
141
      if (! source.has_insert_header())
142
      {
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
143
        error= MISSING_HEADER;
144
        return error;
145
      }
146
      if (! source.has_insert_data())
147
      {
148
        error= MISSING_DATA;
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
149
        return error;
150
      }
151
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
152
      const InsertHeader &insert_header= source.insert_header();
153
      const InsertData &insert_data= source.insert_data();
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
154
      size_t num_keys= insert_data.record_size();
155
      size_t x;
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
160
      for (x= 0; x < num_keys; ++x)
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;
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
321
  case Statement::SET_VARIABLE:
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
322
    {
323
      assert(source.has_set_variable_statement());
324
      string destination;
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
325
      error= transformSetVariableStatementToSql(source.set_variable_statement(),
326
                                                destination,
327
                                                sql_variant);
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
328
      sql_strings.push_back(destination);
329
    }
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
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::RAW_SQL:
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
332
  default:
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
333
    sql_strings.push_back(source.sql());
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
334
    break;
335
  }
336
  return error;
337
}
338
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
339
enum TransformSqlError
340
transformInsertHeaderToSql(const InsertHeader &header,
341
                           string &destination,
342
                           enum TransformSqlVariant sql_variant)
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
343
{
344
  char quoted_identifier= '`';
345
  if (sql_variant == ANSI)
346
    quoted_identifier= '"';
347
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
348
  destination.assign("INSERT INTO ", 12);
349
  destination.push_back(quoted_identifier);
350
  destination.append(header.table_metadata().schema_name());
351
  destination.push_back(quoted_identifier);
352
  destination.push_back('.');
353
  destination.push_back(quoted_identifier);
354
  destination.append(header.table_metadata().table_name());
355
  destination.push_back(quoted_identifier);
356
  destination.append(" (", 2);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
357
358
  /* Add field list to SQL string... */
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
359
  size_t num_fields= header.field_metadata_size();
360
  size_t x;
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
361
362
  for (x= 0; x < num_fields; ++x)
363
  {
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
364
    const FieldMetadata &field_metadata= header.field_metadata(x);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
365
    if (x != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
366
      destination.push_back(',');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
367
    
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
368
    destination.push_back(quoted_identifier);
369
    destination.append(field_metadata.name());
370
    destination.push_back(quoted_identifier);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
371
  }
372
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
373
  return NONE;
374
}
375
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
376
enum TransformSqlError
377
transformInsertRecordToSql(const InsertHeader &header,
378
                           const InsertRecord &record,
379
                           string &destination,
380
                           enum TransformSqlVariant sql_variant)
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
381
{
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
382
  enum TransformSqlError error= transformInsertHeaderToSql(header,
383
                                                           destination,
384
                                                           sql_variant);
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
385
386
  char quoted_identifier= '`';
387
  if (sql_variant == ANSI)
388
    quoted_identifier= '"';
389
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
390
  destination.append(") VALUES (");
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
391
392
  /* Add insert values */
393
  size_t num_fields= header.field_metadata_size();
394
  size_t x;
395
  bool should_quote_field_value= false;
396
  
397
  for (x= 0; x < num_fields; ++x)
398
  {
399
    if (x != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
400
      destination.push_back(',');
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
    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
403
1667.3.2 by Joe Daly
add a working test case, and more fixes so the test case works
404
    if (record.is_null(x))
405
    {
406
      should_quote_field_value= false;
407
    }
408
    else 
409
    {
410
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
411
    }
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
412
413
    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
414
      destination.push_back('\'');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
415
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
416
    if (record.is_null(x))
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
417
    {
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
418
      destination.append("NULL");
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
419
    }
420
    else
421
    {
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
422
      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
423
      {
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
424
        /*
425
         * We do this here because BLOB data is returned
426
         * in a string correctly, but calling append()
427
         * without a length will result in only the string
428
         * up to a \0 being output here.
429
         */
430
        string raw_data(record.insert_value(x));
431
        destination.append(raw_data.c_str(), raw_data.size());
1667.3.2 by Joe Daly
add a working test case, and more fixes so the test case works
432
      }
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
433
      else
1667.3.2 by Joe Daly
add a working test case, and more fixes so the test case works
434
      {
1785.2.1 by David Shrewsbury
When converting transaction log contents to SQL, make sure we escape embedded quotes.
435
        string tmp(record.insert_value(x));
436
        escapeEmbeddedQuotes(tmp);
437
        destination.append(tmp);
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
438
      }
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
439
    }
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
440
441
    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
442
      destination.push_back('\'');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
443
  }
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
444
  destination.push_back(')');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
445
446
  return error;
447
}
448
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
449
enum TransformSqlError
450
transformInsertStatementToSql(const InsertHeader &header,
451
                              const InsertData &data,
452
                              string &destination,
453
                              enum TransformSqlVariant sql_variant)
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
454
{
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
455
  enum TransformSqlError error= transformInsertHeaderToSql(header,
456
                                                           destination,
457
                                                           sql_variant);
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
458
459
  char quoted_identifier= '`';
460
  if (sql_variant == ANSI)
461
    quoted_identifier= '"';
462
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
463
  destination.append(") VALUES (", 10);
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
464
465
  /* Add insert values */
466
  size_t num_records= data.record_size();
467
  size_t num_fields= header.field_metadata_size();
468
  size_t x, y;
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
469
  bool should_quote_field_value= false;
470
  
471
  for (x= 0; x < num_records; ++x)
472
  {
473
    if (x != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
474
      destination.append("),(", 3);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
475
476
    for (y= 0; y < num_fields; ++y)
477
    {
478
      if (y != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
479
        destination.push_back(',');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
480
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
481
      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
482
      
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
483
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
484
485
      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
486
        destination.push_back('\'');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
487
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
488
      if (field_metadata.type() == Table::Field::BLOB)
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
489
      {
490
        /* 
491
         * We do this here because BLOB data is returned
492
         * in a string correctly, but calling append()
493
         * without a length will result in only the string
494
         * up to a \0 being output here.
495
         */
496
        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
497
        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
498
      }
499
      else
500
      {
1785.2.1 by David Shrewsbury
When converting transaction log contents to SQL, make sure we escape embedded quotes.
501
        string tmp(data.record(x).insert_value(y));
502
        escapeEmbeddedQuotes(tmp);
503
        destination.append(tmp);
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
504
      }
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
505
506
      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
507
        destination.push_back('\'');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
508
    }
509
  }
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
510
  destination.push_back(')');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
511
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
512
  return error;
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
513
}
514
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
515
enum TransformSqlError
516
transformUpdateHeaderToSql(const UpdateHeader &header,
517
                           string &destination,
518
                           enum TransformSqlVariant sql_variant)
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
519
{
520
  char quoted_identifier= '`';
521
  if (sql_variant == ANSI)
522
    quoted_identifier= '"';
523
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
524
  destination.assign("UPDATE ", 7);
525
  destination.push_back(quoted_identifier);
526
  destination.append(header.table_metadata().schema_name());
527
  destination.push_back(quoted_identifier);
528
  destination.push_back('.');
529
  destination.push_back(quoted_identifier);
530
  destination.append(header.table_metadata().table_name());
531
  destination.push_back(quoted_identifier);
532
  destination.append(" SET ", 5);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
533
1143.2.33 by Jay Pipes
This patch fixes a bug in the replication service and transaction
534
  return NONE;
535
}
536
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
537
enum TransformSqlError
538
transformUpdateRecordToSql(const UpdateHeader &header,
539
                           const UpdateRecord &record,
540
                           string &destination,
541
                           enum TransformSqlVariant sql_variant)
1143.2.33 by Jay Pipes
This patch fixes a bug in the replication service and transaction
542
{
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
543
  enum TransformSqlError error= transformUpdateHeaderToSql(header,
544
                                                           destination,
545
                                                           sql_variant);
1143.2.33 by Jay Pipes
This patch fixes a bug in the replication service and transaction
546
547
  char quoted_identifier= '`';
548
  if (sql_variant == ANSI)
549
    quoted_identifier= '"';
550
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
551
  /* Add field SET list to SQL string... */
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
552
  size_t num_set_fields= header.set_field_metadata_size();
553
  size_t x;
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
554
  bool should_quote_field_value= false;
555
556
  for (x= 0; x < num_set_fields; ++x)
557
  {
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
558
    const FieldMetadata &field_metadata= header.set_field_metadata(x);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
559
    if (x != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
560
      destination.push_back(',');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
561
    
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
562
    destination.push_back(quoted_identifier);
563
    destination.append(field_metadata.name());
564
    destination.push_back(quoted_identifier);
565
    destination.push_back('=');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
566
1667.3.2 by Joe Daly
add a working test case, and more fixes so the test case works
567
    if (record.is_null(x))
568
    {
569
      should_quote_field_value= false;
570
    }
571
    else 
572
    {
573
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
574
    }    
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
575
576
    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
577
      destination.push_back('\'');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
578
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
579
    if (record.is_null(x))
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
580
    {
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
581
      destination.append("NULL");
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
582
    }
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
583
    else 
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
584
    {
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
585
      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
586
      {
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
587
        /*
588
         * We do this here because BLOB data is returned
589
         * in a string correctly, but calling append()
590
         * without a length will result in only the string
591
         * up to a \0 being output here.
592
         */
593
        string raw_data(record.after_value(x));
594
        destination.append(raw_data.c_str(), raw_data.size());
1667.3.2 by Joe Daly
add a working test case, and more fixes so the test case works
595
      }
1771.2.1 by Joseph Daly
fix 641685, properly handle update and inserts for BLOB fields with NULL values
596
      else 
1667.3.2 by Joe Daly
add a working test case, and more fixes so the test case works
597
      {
1785.2.1 by David Shrewsbury
When converting transaction log contents to SQL, make sure we escape embedded quotes.
598
        string tmp(record.after_value(x));
599
        escapeEmbeddedQuotes(tmp);
600
        destination.append(tmp);
1667.3.2 by Joe Daly
add a working test case, and more fixes so the test case works
601
      }
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
602
    }
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
603
604
    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
605
      destination.push_back('\'');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
606
  }
607
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
608
  size_t num_key_fields= header.key_field_metadata_size();
609
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
610
  destination.append(" WHERE ", 7);
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
611
  for (x= 0; x < num_key_fields; ++x) 
612
  {
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
613
    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
614
    
615
    if (x != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
616
      destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
617
618
    destination.push_back(quoted_identifier);
619
    destination.append(field_metadata.name());
620
    destination.push_back(quoted_identifier);
621
622
    destination.push_back('=');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
623
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
624
    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
625
626
    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
627
      destination.push_back('\'');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
628
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
629
    if (field_metadata.type() == Table::Field::BLOB)
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
630
    {
631
      /* 
632
       * We do this here because BLOB data is returned
633
       * in a string correctly, but calling append()
634
       * without a length will result in only the string
635
       * up to a \0 being output here.
636
       */
637
      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
638
      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
639
    }
640
    else
641
    {
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
642
      destination.append(record.key_value(x));
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
643
    }
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
644
645
    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
646
      destination.push_back('\'');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
647
  }
648
649
  return error;
650
}
651
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
652
enum TransformSqlError
653
transformDeleteHeaderToSql(const DeleteHeader &header,
654
                           string &destination,
655
                           enum TransformSqlVariant sql_variant)
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
656
{
657
  char quoted_identifier= '`';
658
  if (sql_variant == ANSI)
659
    quoted_identifier= '"';
660
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
661
  destination.assign("DELETE FROM ", 12);
662
  destination.push_back(quoted_identifier);
663
  destination.append(header.table_metadata().schema_name());
664
  destination.push_back(quoted_identifier);
665
  destination.push_back('.');
666
  destination.push_back(quoted_identifier);
667
  destination.append(header.table_metadata().table_name());
668
  destination.push_back(quoted_identifier);
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
669
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
670
  return NONE;
671
}
672
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
673
enum TransformSqlError
674
transformDeleteRecordToSql(const DeleteHeader &header,
675
                           const DeleteRecord &record,
676
                           string &destination,
677
                           enum TransformSqlVariant sql_variant)
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
678
{
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
679
  enum TransformSqlError error= transformDeleteHeaderToSql(header,
680
                                                           destination,
681
                                                           sql_variant);
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
682
  char quoted_identifier= '`';
683
  if (sql_variant == ANSI)
684
    quoted_identifier= '"';
685
686
  /* Add WHERE clause to SQL string... */
687
  uint32_t num_key_fields= header.key_field_metadata_size();
688
  uint32_t x;
689
  bool should_quote_field_value= false;
690
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
691
  destination.append(" WHERE ", 7);
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
692
  for (x= 0; x < num_key_fields; ++x) 
693
  {
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
694
    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
695
    
696
    if (x != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
697
      destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
698
699
    destination.push_back(quoted_identifier);
700
    destination.append(field_metadata.name());
701
    destination.push_back(quoted_identifier);
702
703
    destination.push_back('=');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
704
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
705
    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
706
707
    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
708
      destination.push_back('\'');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
709
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
710
    if (field_metadata.type() == Table::Field::BLOB)
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
711
    {
712
      /* 
713
       * We do this here because BLOB data is returned
714
       * in a string correctly, but calling append()
715
       * without a length will result in only the string
716
       * up to a \0 being output here.
717
       */
718
      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
719
      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
720
    }
721
    else
722
    {
1785.2.1 by David Shrewsbury
When converting transaction log contents to SQL, make sure we escape embedded quotes.
723
      string tmp(record.key_value(x));
724
      escapeEmbeddedQuotes(tmp);
725
      destination.append(tmp);
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
726
    }
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
727
728
    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
729
      destination.push_back('\'');
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
730
  }
731
732
  return error;
733
}
734
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
735
enum TransformSqlError
736
transformDeleteStatementToSql(const DeleteHeader &header,
737
                              const DeleteData &data,
738
                              string &destination,
739
                              enum TransformSqlVariant sql_variant)
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
740
{
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
741
  enum TransformSqlError error= transformDeleteHeaderToSql(header,
742
                                                           destination,
743
                                                           sql_variant);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
744
  char quoted_identifier= '`';
745
  if (sql_variant == ANSI)
746
    quoted_identifier= '"';
747
748
  /* Add WHERE clause to SQL string... */
749
  uint32_t num_key_fields= header.key_field_metadata_size();
750
  uint32_t num_key_records= data.record_size();
751
  uint32_t x, y;
752
  bool should_quote_field_value= false;
753
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
754
  destination.append(" WHERE ", 7);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
755
  for (x= 0; x < num_key_records; ++x)
756
  {
757
    if (x != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
758
      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
759
760
    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
761
      destination.push_back('(');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
762
763
    for (y= 0; y < num_key_fields; ++y) 
764
    {
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
765
      const FieldMetadata &field_metadata= header.key_field_metadata(y);
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
766
      
767
      if (y != 0)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
768
        destination.append(" AND ", 5); /* Always AND condition with a multi-column PK */
769
770
      destination.push_back(quoted_identifier);
771
      destination.append(field_metadata.name());
772
      destination.push_back(quoted_identifier);
773
774
      destination.push_back('=');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
775
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
776
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
777
778
      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
779
        destination.push_back('\'');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
780
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
781
      if (field_metadata.type() == Table::Field::BLOB)
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
782
      {
783
        /* 
784
         * We do this here because BLOB data is returned
785
         * in a string correctly, but calling append()
786
         * without a length will result in only the string
787
         * up to a \0 being output here.
788
         */
789
        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
790
        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
791
      }
792
      else
793
      {
1785.2.1 by David Shrewsbury
When converting transaction log contents to SQL, make sure we escape embedded quotes.
794
        string tmp(data.record(x).key_value(y));
795
        escapeEmbeddedQuotes(tmp);
796
        destination.append(tmp);
1143.2.35 by Jay Pipes
Adds support for BLOB fields in the replication stream. Note that
797
      }
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
798
799
      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
800
        destination.push_back('\'');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
801
    }
802
    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
803
      destination.push_back(')');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
804
  }
1143.2.7 by Jay Pipes
Based on IRC discussions with Brian, this patch reworks the Statement
805
  return error;
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
806
}
807
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
808
enum TransformSqlError
809
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
810
                                  string &destination,
811
                                  enum TransformSqlVariant sql_variant)
1308.2.3 by Jay Pipes
Adds DROP SCHEMA to the list of non RAW_SQL statements in replication stream.
812
{
813
  char quoted_identifier= '`';
814
  if (sql_variant == ANSI)
815
    quoted_identifier= '"';
816
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
817
  destination.append("DROP SCHEMA ", 12);
818
  destination.push_back(quoted_identifier);
819
  destination.append(statement.schema_name());
820
  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.
821
822
  return NONE;
823
}
824
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
825
enum TransformSqlError
826
transformCreateSchemaStatementToSql(const CreateSchemaStatement &statement,
827
                                    string &destination,
828
                                    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.
829
{
830
  char quoted_identifier= '`';
831
  if (sql_variant == ANSI)
832
    quoted_identifier= '"';
833
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
834
  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.
835
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
836
  destination.append("CREATE SCHEMA ", 14);
837
  destination.push_back(quoted_identifier);
838
  destination.append(schema.name());
839
  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.
840
841
  if (schema.has_collation())
842
  {
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
843
    destination.append(" COLLATE ", 9);
844
    destination.append(schema.collation());
845
  }
846
847
  return NONE;
848
}
849
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
850
enum TransformSqlError
851
transformDropTableStatementToSql(const DropTableStatement &statement,
852
                                 string &destination,
853
                                 enum TransformSqlVariant sql_variant)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
854
{
855
  char quoted_identifier= '`';
856
  if (sql_variant == ANSI)
857
    quoted_identifier= '"';
858
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
859
  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
860
861
  destination.append("DROP TABLE ", 11);
862
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.
863
  /* Add the IF EXISTS clause if necessary */
864
  if (statement.has_if_exists_clause() &&
865
      statement.if_exists_clause() == true)
866
  {
867
    destination.append("IF EXISTS ", 10);
868
  }
869
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
870
  destination.push_back(quoted_identifier);
871
  destination.append(table_metadata.schema_name());
872
  destination.push_back(quoted_identifier);
873
  destination.push_back('.');
874
  destination.push_back(quoted_identifier);
875
  destination.append(table_metadata.table_name());
876
  destination.push_back(quoted_identifier);
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.
877
878
  return NONE;
879
}
880
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
881
enum TransformSqlError
882
transformTruncateTableStatementToSql(const TruncateTableStatement &statement,
883
                                     string &destination,
884
                                     enum TransformSqlVariant sql_variant)
1143.4.6 by Jay Pipes
Adds test case to transaction log for TRUNCATE TABLE.
885
{
886
  char quoted_identifier= '`';
887
  if (sql_variant == ANSI)
888
    quoted_identifier= '"';
889
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
890
  const TableMetadata &table_metadata= statement.table_metadata();
1143.4.6 by Jay Pipes
Adds test case to transaction log for TRUNCATE TABLE.
891
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
892
  destination.append("TRUNCATE TABLE ", 15);
893
  destination.push_back(quoted_identifier);
894
  destination.append(table_metadata.schema_name());
895
  destination.push_back(quoted_identifier);
896
  destination.push_back('.');
897
  destination.push_back(quoted_identifier);
898
  destination.append(table_metadata.table_name());
899
  destination.push_back(quoted_identifier);
1143.4.6 by Jay Pipes
Adds test case to transaction log for TRUNCATE TABLE.
900
901
  return NONE;
902
}
903
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
904
enum TransformSqlError
905
transformSetVariableStatementToSql(const SetVariableStatement &statement,
906
                                   string &destination,
907
                                   enum TransformSqlVariant sql_variant)
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
908
{
909
  (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.
910
  const FieldMetadata &variable_metadata= statement.variable_metadata();
911
  bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
912
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
913
  destination.append("SET GLOBAL ", 11); /* Only global variables are replicated */
914
  destination.append(variable_metadata.name());
915
  destination.push_back('=');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
916
917
  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
918
    destination.push_back('\'');
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
919
  
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
920
  destination.append(statement.variable_value());
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
921
922
  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
923
    destination.push_back('\'');
924
925
  return NONE;
926
}
927
928
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
929
transformCreateTableStatementToSql(const CreateTableStatement &statement,
930
                                   string &destination,
931
                                   enum TransformSqlVariant sql_variant)
932
{
933
  return transformTableDefinitionToSql(statement.table(), destination, sql_variant);
934
}
935
936
enum TransformSqlError
937
transformTableDefinitionToSql(const Table &table,
938
                              string &destination,
1389 by Brian Aker
Large reord in ALTER TABLE for RENAME.
939
                              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
940
{
941
  char quoted_identifier= '`';
942
  if (sql_variant == ANSI)
943
    quoted_identifier= '"';
944
945
  destination.append("CREATE ", 7);
946
947
  if (table.type() == Table::TEMPORARY)
948
    destination.append("TEMPORARY ", 10);
949
  
950
  destination.append("TABLE ", 6);
1389 by Brian Aker
Large reord in ALTER TABLE for RENAME.
951
  if (with_schema)
952
  {
1638.10.28 by Stewart Smith
fix a lot of quoting and escaping of things in SHOW CREATE TABLE in statement_transform
953
    append_escaped_string(&destination, table.schema(), quoted_identifier);
1389 by Brian Aker
Large reord in ALTER TABLE for RENAME.
954
    destination.push_back('.');
955
  }
1638.10.28 by Stewart Smith
fix a lot of quoting and escaping of things in SHOW CREATE TABLE in statement_transform
956
  append_escaped_string(&destination, table.name(), quoted_identifier);
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
957
  destination.append(" (\n", 3);
1308.2.9 by Jay Pipes
Adds CREATE TABLE work to the statement tranform library. Removes it from /drizzle/message/table_reader.cc
958
959
  enum TransformSqlError result= NONE;
960
  size_t num_fields= table.field_size();
961
  for (size_t x= 0; x < num_fields; ++x)
962
  {
963
    const Table::Field &field= table.field(x);
964
965
    if (x != 0)
966
      destination.append(",\n", 2);
967
1638.10.3 by Stewart Smith
statement_transform for CREATE TABLE: fields are indented by 2 spaces
968
    destination.append("  ");
969
1308.2.9 by Jay Pipes
Adds CREATE TABLE work to the statement tranform library. Removes it from /drizzle/message/table_reader.cc
970
    result= transformFieldDefinitionToSql(field, destination, sql_variant);
1638.10.3 by Stewart Smith
statement_transform for CREATE TABLE: fields are indented by 2 spaces
971
1308.2.9 by Jay Pipes
Adds CREATE TABLE work to the statement tranform library. Removes it from /drizzle/message/table_reader.cc
972
    if (result != NONE)
973
      return result;
974
  }
975
976
  size_t num_indexes= table.indexes_size();
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
977
  
978
  if (num_indexes > 0)
979
    destination.append(",\n", 2);
980
1308.2.9 by Jay Pipes
Adds CREATE TABLE work to the statement tranform library. Removes it from /drizzle/message/table_reader.cc
981
  for (size_t x= 0; x < num_indexes; ++x)
982
  {
983
    const message::Table::Index &index= table.indexes(x);
984
985
    if (x != 0)
986
      destination.append(",\n", 2);
987
988
    result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
989
    
990
    if (result != NONE)
991
      return result;
992
  }
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).
993
994
  size_t num_foreign_keys= table.fk_constraint_size();
995
996
  if (num_foreign_keys > 0)
997
    destination.append(",\n", 2);
998
999
  for (size_t x= 0; x < num_foreign_keys; ++x)
1000
  {
1001
    const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
1002
1003
    if (x != 0)
1004
      destination.append(",\n", 2);
1005
1006
    result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1007
1008
    if (result != NONE)
1009
      return result;
1010
  }
1011
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1012
  destination.append("\n)", 2);
1308.2.9 by Jay Pipes
Adds CREATE TABLE work to the statement tranform library. Removes it from /drizzle/message/table_reader.cc
1013
1014
  /* Add ENGINE = " clause */
1015
  if (table.has_engine())
1016
  {
1638.10.6 by Stewart Smith
statement_transform: ENGINE clause of CREATE TABLE doesn't have spaces around equals sign
1017
    destination.append(" ENGINE=", 8);
1502.1.31 by Brian Aker
Merge engine options for schema/table.
1018
    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
1019
1502.1.31 by Brian Aker
Merge engine options for schema/table.
1020
    size_t num_engine_options= table.engine().options_size();
1638.10.10 by Stewart Smith
fix statement_transform for producing list of engine options
1021
    if (num_engine_options > 0)
1022
      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
1023
    for (size_t x= 0; x < num_engine_options; ++x)
1024
    {
1502.1.31 by Brian Aker
Merge engine options for schema/table.
1025
      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
1026
      destination.append(option.name());
1638.10.10 by Stewart Smith
fix statement_transform for producing list of engine options
1027
      destination.append("='", 2);
1502.1.30 by Brian Aker
First pass on cleanup of Stewart's patch, plus re-engineer to make it work a
1028
      destination.append(option.state());
1638.10.10 by Stewart Smith
fix statement_transform for producing list of engine options
1029
      destination.append("'", 1);
1030
      if(x != num_engine_options-1)
1031
        destination.append(", ", 2);
1308.2.9 by Jay Pipes
Adds CREATE TABLE work to the statement tranform library. Removes it from /drizzle/message/table_reader.cc
1032
    }
1033
  }
1034
1035
  if (table.has_options())
1036
    (void) transformTableOptionsToSql(table.options(), destination, sql_variant);
1037
1038
  return NONE;
1039
}
1040
1041
enum TransformSqlError
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1042
transformTableOptionsToSql(const Table::TableOptions &options,
1043
                           string &destination,
1044
                           enum TransformSqlVariant sql_variant)
1045
{
1046
  if (sql_variant == ANSI)
1047
    return NONE; /* ANSI does not support table options... */
1048
1049
  if (options.has_comment())
1050
  {
1638.10.28 by Stewart Smith
fix a lot of quoting and escaping of things in SHOW CREATE TABLE in statement_transform
1051
    destination.append(" COMMENT=", 9);
1052
    append_escaped_string(&destination, options.comment());
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1053
  }
1054
1055
  if (options.has_collation())
1056
  {
1638.10.54 by Stewart Smith
alter_table.result: COLLATE and ENGINE in same line for SHOW CREATE TABLE
1057
    destination.append(" COLLATE = ", 11);
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1058
    destination.append(options.collation());
1059
  }
1060
1061
  if (options.has_data_file_name())
1062
  {
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1063
    destination.append("\nDATA_FILE_NAME = '", 19);
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1064
    destination.append(options.data_file_name());
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1065
    destination.push_back('\'');
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1066
  }
1067
1068
  if (options.has_index_file_name())
1069
  {
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1070
    destination.append("\nINDEX_FILE_NAME = '", 20);
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1071
    destination.append(options.index_file_name());
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1072
    destination.push_back('\'');
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1073
  }
1074
1075
  if (options.has_max_rows())
1076
  {
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1077
    destination.append("\nMAX_ROWS = ", 12);
1775.5.1 by earney
modified files containing stringstream to use boost:lexical_cast instead as
1078
    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...
1079
  }
1080
1081
  if (options.has_min_rows())
1082
  {
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1083
    destination.append("\nMIN_ROWS = ", 12);
1775.5.1 by earney
modified files containing stringstream to use boost:lexical_cast instead as
1084
    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...
1085
  }
1086
1638.10.116 by Stewart Smith
only display AUTO_INCREMENT value if explicitly set by user (and preserve across ALTER TABLE).
1087
  if (options.has_user_set_auto_increment_value()
1088
      && options.has_auto_increment_value())
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1089
  {
1638.10.17 by Stewart Smith
fix SHOW CREATE TABLE (statement_transform) for auto_increment, including the (now correct) auto_increment test result.
1090
    destination.append(" AUTO_INCREMENT=", 16);
1775.5.1 by earney
modified files containing stringstream to use boost:lexical_cast instead as
1091
    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...
1092
  }
1093
1094
  if (options.has_avg_row_length())
1095
  {
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1096
    destination.append("\nAVG_ROW_LENGTH = ", 18);
1775.5.1 by earney
modified files containing stringstream to use boost:lexical_cast instead as
1097
    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...
1098
  }
1099
1100
  if (options.has_checksum() &&
1101
      options.checksum())
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1102
    destination.append("\nCHECKSUM = TRUE", 16);
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1103
  if (options.has_page_checksum() &&
1104
      options.page_checksum())
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1105
    destination.append("\nPAGE_CHECKSUM = TRUE", 21);
1308.2.8 by Jay Pipes
Adds method to statement_transform library to output CREATE TABLE options properly...
1106
1107
  return NONE;
1108
}
1109
1110
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
1111
transformIndexDefinitionToSql(const Table::Index &index,
1112
                              const Table &table,
1113
                              string &destination,
1114
                              enum TransformSqlVariant sql_variant)
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1115
{
1116
  char quoted_identifier= '`';
1117
  if (sql_variant == ANSI)
1118
    quoted_identifier= '"';
1119
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.
1120
  destination.append("  ", 2);
1121
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1122
  if (index.is_primary())
1123
    destination.append("PRIMARY ", 8);
1124
  else if (index.is_unique())
1125
    destination.append("UNIQUE ", 7);
1126
1127
  destination.append("KEY ", 4);
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.
1128
  if (! (index.is_primary() && index.name().compare("PRIMARY")==0))
1129
  {
1130
    destination.push_back(quoted_identifier);
1131
    destination.append(index.name());
1132
    destination.push_back(quoted_identifier);
1133
    destination.append(" (", 2);
1134
  }
1135
  else
1136
    destination.append("(", 1);
1137
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1138
  size_t num_parts= index.index_part_size();
1139
  for (size_t x= 0; x < num_parts; ++x)
1140
  {
1141
    const Table::Index::IndexPart &part= index.index_part(x);
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1142
    const Table::Field &field= table.field(part.fieldnr());
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1143
1144
    if (x != 0)
1145
      destination.push_back(',');
1146
    
1147
    destination.push_back(quoted_identifier);
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1148
    destination.append(field.name());
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1149
    destination.push_back(quoted_identifier);
1150
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1151
    /* 
1152
     * 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.
1153
     * then check for a prefix length then is different
1154
     * from the field's full length...
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1155
     */
1156
    if (field.type() == Table::Field::VARCHAR ||
1157
        field.type() == Table::Field::BLOB)
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1158
    {
1308.2.13 by Jay Pipes
Fixes CREATE TABLE output in statement_transform.cc for VARCHAR prefix indexes. What ass.
1159
      if (part.has_compare_length())
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1160
      {
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)
1161
        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.
1162
        {
1163
          destination.push_back('(');
1775.5.1 by earney
modified files containing stringstream to use boost:lexical_cast instead as
1164
          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.
1165
          destination.push_back(')');
1166
        }
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1167
      }
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1168
    }
1169
  }
1170
  destination.push_back(')');
1171
1638.10.30 by Stewart Smith
get USING (BTREE|HASH) index type syntax correct for statement_transform in CREATE TABLE.
1172
  switch (index.type())
1173
  {
1174
  case Table::Index::UNKNOWN_INDEX:
1175
    break;
1176
  case Table::Index::BTREE:
1177
    destination.append(" USING BTREE", 12);
1178
    break;
1179
  case Table::Index::RTREE:
1180
    destination.append(" USING RTREE", 12);
1181
    break;
1182
  case Table::Index::HASH:
1183
    destination.append(" USING HASH", 11);
1184
    break;
1185
  case Table::Index::FULLTEXT:
1186
    destination.append(" USING FULLTEXT", 15);
1187
    break;
1188
  }
1189
1638.10.33 by Stewart Smith
index comments in statement_transform
1190
  if (index.has_comment())
1191
  {
1192
    destination.append(" COMMENT ", 9);
1193
    append_escaped_string(&destination, index.comment());
1194
  }
1195
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1196
  return NONE;
1197
}
1198
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).
1199
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
1200
{
1201
  switch (opt)
1202
  {
1203
  case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1204
    destination.append("RESTRICT");
1205
    break;
1206
  case Table::ForeignKeyConstraint::OPTION_CASCADE:
1207
    destination.append("CASCADE");
1208
    break;
1209
  case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1210
    destination.append("SET NULL");
1211
    break;
1861.4.8 by Brian Aker
Adds in a portion of the ref constraints table.
1212
  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).
1213
  case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1214
    destination.append("NO ACTION");
1215
    break;
1861.4.8 by Brian Aker
Adds in a portion of the ref constraints table.
1216
  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).
1217
    destination.append("SET DEFAULT");
1218
    break;
1219
  }
1220
}
1221
1222
enum TransformSqlError
1223
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
1224
                                             const Table &,
1225
                                             string &destination,
1226
                                             enum TransformSqlVariant sql_variant)
1227
{
1228
  char quoted_identifier= '`';
1229
  if (sql_variant == ANSI)
1230
    quoted_identifier= '"';
1231
1232
  destination.append("  ", 2);
1233
1234
  if (fkey.has_name())
1235
  {
1236
    destination.append("CONSTRAINT ", 11);
1237
    append_escaped_string(&destination, fkey.name(), quoted_identifier);
1238
    destination.append(" ", 1);
1239
  }
1240
1241
  destination.append("FOREIGN KEY (", 13);
1242
1243
  for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1244
  {
1245
    if (x != 0)
1638.10.102 by Stewart Smith
merge trunk
1246
      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).
1247
1248
    append_escaped_string(&destination, fkey.column_names(x),
1249
                          quoted_identifier);
1250
  }
1251
1252
  destination.append(") REFERENCES ", 13);
1253
1254
  append_escaped_string(&destination, fkey.references_table_name(),
1255
                        quoted_identifier);
1256
  destination.append(" (", 2);
1257
1258
  for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1259
  {
1260
    if (x != 0)
1638.10.102 by Stewart Smith
merge trunk
1261
      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).
1262
1263
    append_escaped_string(&destination, fkey.references_columns(x),
1264
                          quoted_identifier);
1265
  }
1266
1267
  destination.push_back(')');
1268
1861.4.8 by Brian Aker
Adds in a portion of the ref constraints table.
1269
  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).
1270
  {
1271
    destination.append(" ON UPDATE ", 11);
1272
    transformForeignKeyOptionToSql(fkey.update_option(), destination);
1273
  }
1274
1861.4.8 by Brian Aker
Adds in a portion of the ref constraints table.
1275
  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).
1276
  {
1277
    destination.append(" ON DELETE ", 11);
1278
    transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1279
  }
1280
1281
  return NONE;
1282
}
1283
1308.2.7 by Jay Pipes
Add function to statement transform library which constructs INDEX clause
1284
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
1285
transformFieldDefinitionToSql(const Table::Field &field,
1286
                              string &destination,
1287
                              enum TransformSqlVariant sql_variant)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1288
{
1289
  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.
1290
  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
1291
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1292
  if (sql_variant == ANSI)
1293
    quoted_identifier= '"';
1294
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.
1295
  if (sql_variant == DRIZZLE)
1296
    quoted_default= '\'';
1297
  else
1298
    quoted_default= quoted_identifier;
1299
1638.10.28 by Stewart Smith
fix a lot of quoting and escaping of things in SHOW CREATE TABLE in statement_transform
1300
  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
1301
1302
  Table::Field::FieldType field_type= field.type();
1303
1304
  switch (field_type)
1305
  {
1306
    case Table::Field::DOUBLE:
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1307
    destination.append(" DOUBLE", 7);
1638.10.14 by Stewart Smith
if a DOUBLE column has scale and precision, display them
1308
    if (field.has_numeric_options()
1309
        && field.numeric_options().has_precision())
1310
    {
1311
      stringstream ss;
1312
      ss << "(" << field.numeric_options().precision() << ",";
1313
      ss << field.numeric_options().scale() << ")";
1314
      destination.append(ss.str());
1315
    }
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1316
    break;
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1317
  case Table::Field::VARCHAR:
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1318
    {
1638.10.11 by Stewart Smith
fix varchar/varbinary and blob/text for statement_transform of table definition
1319
      if (field.string_options().has_collation()
1320
          && field.string_options().collation().compare("binary") == 0)
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1321
        destination.append(" VARBINARY(", 11);
1638.10.11 by Stewart Smith
fix varchar/varbinary and blob/text for statement_transform of table definition
1322
      else
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1323
        destination.append(" VARCHAR(", 9);
1638.10.11 by Stewart Smith
fix varchar/varbinary and blob/text for statement_transform of table definition
1324
1775.5.1 by earney
modified files containing stringstream to use boost:lexical_cast instead as
1325
      destination.append(boost::lexical_cast<string>(field.string_options().length()));
1326
      destination.append(")");
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1327
    }
1328
    break;
1329
  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.
1330
    {
1331
      if (field.string_options().has_collation()
1332
          && field.string_options().collation().compare("binary") == 0)
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1333
        destination.append(" BLOB", 5);
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.
1334
      else
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1335
        destination.append(" TEXT", 5);
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.
1336
    }
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1337
    break;
1338
  case Table::Field::ENUM:
1339
    {
1396 by Brian Aker
Simple rename.
1340
      size_t num_field_values= field.enumeration_values().field_value_size();
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1341
      destination.append(" ENUM(", 6);
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1342
      for (size_t x= 0; x < num_field_values; ++x)
1343
      {
1396 by Brian Aker
Simple rename.
1344
        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
1345
1346
        if (x != 0)
1347
          destination.push_back(',');
1348
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1349
        destination.push_back('\'');
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1350
        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.
1351
        destination.push_back('\'');
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1352
      }
1353
      destination.push_back(')');
1354
      break;
1355
    }
1996.2.1 by Brian Aker
uuid type code.
1356
  case Table::Field::UUID:
1357
    destination.append(" UUID", 5);
1358
    break;
2023.2.2 by Brian Aker
Merge in BOOL change to BOOLEAN.
1359
  case Table::Field::BOOLEAN:
2023.2.3 by Brian Aker
Merge in fixes for DD to make use of BOOLEAN as a type.
1360
    destination.append(" BOOLEAN", 8);
2023.2.1 by Brian Aker
Merge in BOOL type.
1361
    break;
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1362
  case Table::Field::INTEGER:
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1363
    destination.append(" INT", 4);
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1364
    break;
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1365
  case Table::Field::BIGINT:
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1366
    destination.append(" BIGINT", 7);
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1367
    break;
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1368
  case Table::Field::DECIMAL:
1369
    {
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1370
      destination.append(" DECIMAL(", 9);
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1371
      stringstream ss;
1372
      ss << field.numeric_options().precision() << ",";
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1373
      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.
1374
      destination.append(ss.str());
1375
    }
1376
    break;
1377
  case Table::Field::DATE:
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1378
    destination.append(" DATE", 5);
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1379
    break;
1999.4.10 by Brian Aker
This fixes the bug where we were not displaying the correct field type in
1380
  case Table::Field::EPOCH:
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1381
    destination.append(" TIMESTAMP",  10);
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1382
    break;
1383
  case Table::Field::DATETIME:
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1384
    destination.append(" DATETIME",  9);
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1385
    break;
1999.4.7 by Brian Aker
Merge in first pass of TIME type (closer to EPOCH time).
1386
  case Table::Field::TIME:
2023.2.3 by Brian Aker
Merge in fixes for DD to make use of BOOLEAN as a type.
1387
    destination.append(" TIME",  5);
1999.4.7 by Brian Aker
Merge in first pass of TIME type (closer to EPOCH time).
1388
    break;
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1389
  }
1390
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1391
  if (field.type() == Table::Field::INTEGER || 
1392
      field.type() == Table::Field::BIGINT)
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1393
  {
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1394
    if (field.has_constraints() &&
1395
        field.constraints().has_is_unsigned() &&
1396
        field.constraints().is_unsigned())
1397
    {
1398
      destination.append(" UNSIGNED", 9);
1399
    }
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1400
  }
1401
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1402
  if (field.type() == Table::Field::BLOB ||
1403
      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
1404
  {
1638.10.11 by Stewart Smith
fix varchar/varbinary and blob/text for statement_transform of table definition
1405
    if (field.string_options().has_collation()
1743.5.1 by LinuxJedi
Make SHOW CREATE TABLE type uppercase and always show collate
1406
        && 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.
1407
    {
1408
      destination.append(" COLLATE ", 9);
1409
      destination.append(field.string_options().collation());
1410
    }
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1411
  }
1308.2.11 by Jay Pipes
* Adds CREATE TABLE as a specific CreateTableStatement message in the
1412
1638.10.13 by Stewart Smith
NOT NULL comes after COLLATE in CREATE TABLE
1413
  if (field.has_constraints() &&
1414
      ! field.constraints().is_nullable())
1415
  {
1416
    destination.append(" NOT NULL", 9);
1417
  }
1999.4.10 by Brian Aker
This fixes the bug where we were not displaying the correct field type in
1418
  else if (field.type() == Table::Field::EPOCH)
1638.10.15 by Stewart Smith
TIMESTAMP fields are default NOT NULL for some bonghits reason, so we get to have explicit NULLability.
1419
    destination.append(" NULL", 5);
1638.10.13 by Stewart Smith
NOT NULL comes after COLLATE in CREATE TABLE
1420
1638.10.16 by Stewart Smith
fix up AUTO_INCREMENT must be after NOT NULL in statement_transform
1421
  if (field.type() == Table::Field::INTEGER || 
1422
      field.type() == Table::Field::BIGINT)
1423
  {
1424
    /* AUTO_INCREMENT must be after NOT NULL */
1425
    if (field.has_numeric_options() &&
1426
        field.numeric_options().is_autoincrement())
1427
    {
1428
      destination.append(" AUTO_INCREMENT", 15);
1429
    }
1430
  }
1431
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1432
  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.
1433
  {
1434
    destination.append(" DEFAULT ", 9);
1638.10.28 by Stewart Smith
fix a lot of quoting and escaping of things in SHOW CREATE TABLE in statement_transform
1435
    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.
1436
  }
1638.10.20 by Stewart Smith
present DEFAULT and ON UPDATE correctly in statement_transform
1437
  else if (field.options().has_default_expression())
1438
  {
1439
    destination.append(" DEFAULT ", 9);
1440
    destination.append(field.options().default_expression());
1441
  }
1442
  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
1443
  {
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1444
    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.
1445
    if (v.length() == 0)
1446
      destination.append(" DEFAULT ''", 11);
1447
    else
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1448
    {
1638.10.24 by Stewart Smith
fix display of VARBINARY default values in SHOW CREATE TABLE. Always use printable characters by encoding in hex.
1449
      destination.append(" DEFAULT 0x", 11);
1450
      for (size_t x= 0; x < v.length(); x++)
1451
      {
1452
        char hex[3];
1453
        snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
1454
        destination.append(hex, 2);
1455
      }
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1456
    }
1457
  }
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.
1458
  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.
1459
           && 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.
1460
           && field.type() != Table::Field::BLOB)
1638.10.8 by Stewart Smith
fix DEFAULT NULL and NOT NULL for statement_transform
1461
  {
1462
    destination.append(" DEFAULT NULL", 13);
1463
  }
1464
1638.10.20 by Stewart Smith
present DEFAULT and ON UPDATE correctly in statement_transform
1465
  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.
1466
  {
1467
    destination.append(" ON UPDATE ", 11);
1638.10.20 by Stewart Smith
present DEFAULT and ON UPDATE correctly in statement_transform
1468
    destination.append(field.options().update_expression());
1638.3.1 by Stewart Smith
TimestampFieldOptions in the table proto contains nothing that we use. remove it.
1469
  }
1308.2.4 by Jay Pipes
Adds DROP TABLE to the list of non RAW_SQL statements in replication stream
1470
1471
  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.
1472
  {
1473
    destination.append(" COMMENT ", 9);
1638.10.28 by Stewart Smith
fix a lot of quoting and escaping of things in SHOW CREATE TABLE in statement_transform
1474
    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.
1475
  }
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
1476
  return NONE;
1477
}
1478
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1479
bool shouldQuoteFieldValue(Table::Field::FieldType in_type)
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
1480
{
1481
  switch (in_type)
1482
  {
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1483
  case Table::Field::DOUBLE:
1484
  case Table::Field::DECIMAL:
1485
  case Table::Field::INTEGER:
1486
  case Table::Field::BIGINT:
1143.2.4 by Jay Pipes
New transaction proto file containing message definitions to be
1487
    return false;
1488
  default:
1489
    return true;
1490
  } 
1491
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
1492
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1493
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.
1494
{
1495
  switch (type) {
1496
  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.
1497
    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.
1498
  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.
1499
    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.
1500
  case DRIZZLE_TYPE_NULL:
1501
    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.
1502
    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.
1503
  case DRIZZLE_TYPE_TIMESTAMP:
1999.4.10 by Brian Aker
This fixes the bug where we were not displaying the correct field type in
1504
    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.
1505
  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.
1506
    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.
1507
  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.
1508
    return Table::Field::DATETIME;
1999.4.7 by Brian Aker
Merge in first pass of TIME type (closer to EPOCH time).
1509
  case DRIZZLE_TYPE_TIME:
1510
    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.
1511
  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.
1512
    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.
1513
  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.
1514
    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.
1515
  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.
1516
    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.
1517
  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.
1518
    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.
1519
  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.
1520
    return Table::Field::BLOB;
1996.2.1 by Brian Aker
uuid type code.
1521
  case DRIZZLE_TYPE_UUID:
1522
    return Table::Field::UUID;
2023.2.2 by Brian Aker
Merge in BOOL change to BOOLEAN.
1523
  case DRIZZLE_TYPE_BOOLEAN:
1524
    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.
1525
  }
1526
1527
  assert(false);
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1528
  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.
1529
}
1530
1336.2.1 by Jay Pipes
Move transactionContainsBulkSegment() to statement transform library.
1531
bool transactionContainsBulkSegment(const Transaction &transaction)
1532
{
1533
  size_t num_statements= transaction.statement_size();
1534
  if (num_statements == 0)
1535
    return false;
1536
1537
  /*
1538
   * Only INSERT, UPDATE, and DELETE statements can possibly
1539
   * have bulk segments.  So, we loop through the statements
1540
   * checking for segment_id > 1 in those specific submessages.
1541
   */
1542
  size_t x;
1543
  for (x= 0; x < num_statements; ++x)
1544
  {
1545
    const Statement &statement= transaction.statement(x);
1546
    Statement::Type type= statement.type();
1547
1548
    switch (type)
1549
    {
1550
      case Statement::INSERT:
1551
        if (statement.insert_data().segment_id() > 1)
1552
          return true;
1553
        break;
1554
      case Statement::UPDATE:
1555
        if (statement.update_data().segment_id() > 1)
1556
          return true;
1557
        break;
1558
      case Statement::DELETE:
1559
        if (statement.delete_data().segment_id() > 1)
1560
          return true;
1561
        break;
1562
      default:
1563
        break;
1564
    }
1565
  }
1566
  return false;
1567
}
1568
1308.2.5 by Jay Pipes
Adds ability to take a Field message and convert it to its SQL field attributes list.
1569
} /* namespace message */
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
1570
} /* namespace drizzled */