~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

  • Committer: Paul McCullagh
  • Date: 2010-09-16 15:26:41 UTC
  • mto: (1771.3.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 1785.
  • Revision ID: paul.mccullagh@primebase.org-20100916152641-9mwb1hga0qwz41nu
Merged with 1.1 trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2009 Sun Microsystems, Inc.
5
 
 *  Copyright (C) 2010 Jay Pipes
 
4
 *  Copyright (C) 2009 Sun Microsystems
 
5
 *  Copyright (c) 2010 Jay Pipes
6
6
 *
7
7
 *  Authors:
8
8
 *
29
29
 * Statement messages to other formats, including SQL strings.
30
30
 */
31
31
 
32
 
#include <config.h>
 
32
#include "config.h"
33
33
 
34
 
#include <boost/lexical_cast.hpp>
35
 
#include <drizzled/message/statement_transform.h>
36
 
#include <drizzled/message/transaction.pb.h>
37
 
#include <drizzled/message/table.pb.h>
38
 
#include <drizzled/charset.h>
39
 
#include <drizzled/charset_info.h>
40
 
#include <drizzled/global_charset_info.h>
 
34
#include "drizzled/message/statement_transform.h"
 
35
#include "drizzled/message/transaction.pb.h"
 
36
#include "drizzled/message/table.pb.h"
 
37
#include "drizzled/charset.h"
 
38
#include "drizzled/charset_info.h"
 
39
#include "drizzled/global_charset_info.h"
41
40
 
42
41
#include <string>
43
42
#include <vector>
52
51
namespace message
53
52
{
54
53
 
55
 
static void escapeEmbeddedQuotes(string &s, const char quote='\'')
56
 
{
57
 
  string::iterator it;
58
 
 
59
 
  for (it= s.begin(); it != s.end(); ++it)
60
 
  {
61
 
    if (*it == quote)
62
 
    {
63
 
      it= s.insert(it, quote);
64
 
      ++it;  // advance back to the quote
65
 
    }
66
 
  }
67
 
}
68
 
 
69
54
/* Incredibly similar to append_unescaped() in table.cc, but for std::string */
70
55
static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
71
56
{
127
112
 
128
113
  switch (source.type())
129
114
  {
130
 
  case Statement::ROLLBACK_STATEMENT:
131
 
    {
132
 
      break;
133
 
    }
134
 
  case Statement::ROLLBACK:
135
 
    {
136
 
      sql_strings.push_back("ROLLBACK");
137
 
      break;
138
 
    }
139
115
  case Statement::INSERT:
140
116
    {
141
117
      if (! source.has_insert_header())
152
128
      const InsertHeader &insert_header= source.insert_header();
153
129
      const InsertData &insert_data= source.insert_data();
154
130
      size_t num_keys= insert_data.record_size();
 
131
      size_t x;
155
132
 
156
133
      if (num_keys > 1 && ! already_in_transaction)
157
134
        sql_strings.push_back("START TRANSACTION");
158
135
 
159
 
      for (size_t x= 0; x < num_keys; ++x)
 
136
      for (x= 0; x < num_keys; ++x)
160
137
      {
161
138
        string destination;
162
139
 
317
294
      sql_strings.push_back(destination);
318
295
    }
319
296
    break;
320
 
  case Statement::ALTER_SCHEMA:
321
 
    {
322
 
      assert(source.has_alter_schema_statement());
323
 
      string destination;
324
 
      error= transformAlterSchemaStatementToSql(source.alter_schema_statement(),
325
 
                                                destination,
326
 
                                                sql_variant);
327
 
      sql_strings.push_back(destination);
328
 
    }
329
 
    break;
330
297
  case Statement::SET_VARIABLE:
331
298
    {
332
299
      assert(source.has_set_variable_statement());
422
389
    if (should_quote_field_value)
423
390
      destination.push_back('\'');
424
391
 
425
 
    if (record.is_null(x))
 
392
    if (field_metadata.type() == Table::Field::BLOB)
426
393
    {
427
 
      destination.append("NULL");
 
394
      /* 
 
395
        * We do this here because BLOB data is returned
 
396
        * in a string correctly, but calling append()
 
397
        * without a length will result in only the string
 
398
        * up to a \0 being output here.
 
399
        */
 
400
      string raw_data(record.insert_value(x));
 
401
      destination.append(raw_data.c_str(), raw_data.size());
428
402
    }
429
403
    else
430
404
    {
431
 
      if (field_metadata.type() == Table::Field::BLOB)
432
 
      {
433
 
        /*
434
 
         * We do this here because BLOB data is returned
435
 
         * in a string correctly, but calling append()
436
 
         * without a length will result in only the string
437
 
         * up to a \0 being output here.
438
 
         */
439
 
        string raw_data(record.insert_value(x));
440
 
        destination.append(raw_data.c_str(), raw_data.size());
441
 
      }
442
 
      else
443
 
      {
444
 
        string tmp(record.insert_value(x));
445
 
        escapeEmbeddedQuotes(tmp);
446
 
        destination.append(tmp);
447
 
      }
 
405
      if (record.is_null(x))
 
406
      {
 
407
        destination.append("NULL");
 
408
      }
 
409
      else 
 
410
      {
 
411
        destination.append(record.insert_value(x));
 
412
      } 
448
413
    }
449
414
 
450
415
    if (should_quote_field_value)
507
472
      }
508
473
      else
509
474
      {
510
 
        string tmp(data.record(x).insert_value(y));
511
 
        escapeEmbeddedQuotes(tmp);
512
 
        destination.append(tmp);
 
475
        destination.append(data.record(x).insert_value(y));
513
476
      }
514
477
 
515
478
      if (should_quote_field_value)
585
548
    if (should_quote_field_value)
586
549
      destination.push_back('\'');
587
550
 
588
 
    if (record.is_null(x))
 
551
    if (field_metadata.type() == Table::Field::BLOB)
589
552
    {
590
 
      destination.append("NULL");
 
553
      /* 
 
554
       * We do this here because BLOB data is returned
 
555
       * in a string correctly, but calling append()
 
556
       * without a length will result in only the string
 
557
       * up to a \0 being output here.
 
558
       */
 
559
      string raw_data(record.after_value(x));
 
560
      destination.append(raw_data.c_str(), raw_data.size());
591
561
    }
592
 
    else 
 
562
    else
593
563
    {
594
 
      if (field_metadata.type() == Table::Field::BLOB)
 
564
      if (record.is_null(x))
595
565
      {
596
 
        /*
597
 
         * We do this here because BLOB data is returned
598
 
         * in a string correctly, but calling append()
599
 
         * without a length will result in only the string
600
 
         * up to a \0 being output here.
601
 
         */
602
 
        string raw_data(record.after_value(x));
603
 
        destination.append(raw_data.c_str(), raw_data.size());
 
566
        destination.append("NULL");
604
567
      }
605
 
      else 
 
568
      else
606
569
      {
607
 
        string tmp(record.after_value(x));
608
 
        escapeEmbeddedQuotes(tmp);
609
 
        destination.append(tmp);
 
570
        destination.append(record.after_value(x));
610
571
      }
611
572
    }
612
573
 
729
690
    }
730
691
    else
731
692
    {
732
 
      string tmp(record.key_value(x));
733
 
      escapeEmbeddedQuotes(tmp);
734
 
      destination.append(tmp);
 
693
      destination.append(record.key_value(x));
735
694
    }
736
695
 
737
696
    if (should_quote_field_value)
800
759
      }
801
760
      else
802
761
      {
803
 
        string tmp(data.record(x).key_value(y));
804
 
        escapeEmbeddedQuotes(tmp);
805
 
        destination.append(tmp);
 
762
        destination.append(data.record(x).key_value(y));
806
763
      }
807
764
 
808
765
      if (should_quote_field_value)
815
772
}
816
773
 
817
774
enum TransformSqlError
818
 
transformAlterSchemaStatementToSql(const AlterSchemaStatement &statement,
819
 
                                   string &destination,
820
 
                                   enum TransformSqlVariant sql_variant)
821
 
{
822
 
  const Schema &before= statement.before();
823
 
  const Schema &after= statement.after();
824
 
 
825
 
  /* Make sure we are given the before and after for the same object */
826
 
  if (before.uuid() != after.uuid())
827
 
    return UUID_MISMATCH;
828
 
 
829
 
  char quoted_identifier= '`';
830
 
  if (sql_variant == ANSI)
831
 
    quoted_identifier= '"';
832
 
 
833
 
  destination.append("ALTER SCHEMA ");
834
 
  destination.push_back(quoted_identifier);
835
 
  destination.append(before.name());
836
 
  destination.push_back(quoted_identifier);
837
 
 
838
 
  /*
839
 
   * Diff our schemas. Currently, only collation can change so a
840
 
   * diff of the two structures is not really necessary.
841
 
   */
842
 
  destination.append(" COLLATE = ");
843
 
  destination.append(after.collation());
844
 
 
845
 
  return NONE;
846
 
}
847
 
 
848
 
enum TransformSqlError
849
775
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
850
776
                                  string &destination,
851
777
                                  enum TransformSqlVariant sql_variant)
873
799
 
874
800
  const Schema &schema= statement.schema();
875
801
 
876
 
  destination.append("CREATE SCHEMA ");
 
802
  destination.append("CREATE SCHEMA ", 14);
877
803
  destination.push_back(quoted_identifier);
878
804
  destination.append(schema.name());
879
805
  destination.push_back(quoted_identifier);
880
806
 
881
807
  if (schema.has_collation())
882
808
  {
883
 
    destination.append(" COLLATE ");
 
809
    destination.append(" COLLATE ", 9);
884
810
    destination.append(schema.collation());
885
811
  }
886
812
 
887
 
  if (schema.has_replication_options() and schema.replication_options().has_dont_replicate() and schema.replication_options().dont_replicate())
888
 
  {
889
 
    destination.append(" REPLICATION = FALSE");
890
 
  }
891
 
 
892
813
  return NONE;
893
814
}
894
815
 
903
824
 
904
825
  const TableMetadata &table_metadata= statement.table_metadata();
905
826
 
906
 
  destination.append("DROP TABLE ");
 
827
  destination.append("DROP TABLE ", 11);
907
828
 
908
829
  /* Add the IF EXISTS clause if necessary */
909
830
  if (statement.has_if_exists_clause() &&
910
831
      statement.if_exists_clause() == true)
911
832
  {
912
 
    destination.append("IF EXISTS ");
 
833
    destination.append("IF EXISTS ", 10);
913
834
  }
914
835
 
915
836
  destination.push_back(quoted_identifier);
934
855
 
935
856
  const TableMetadata &table_metadata= statement.table_metadata();
936
857
 
937
 
  destination.append("TRUNCATE TABLE ");
 
858
  destination.append("TRUNCATE TABLE ", 15);
938
859
  destination.push_back(quoted_identifier);
939
860
  destination.append(table_metadata.schema_name());
940
861
  destination.push_back(quoted_identifier);
955
876
  const FieldMetadata &variable_metadata= statement.variable_metadata();
956
877
  bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
957
878
 
958
 
  destination.append("SET GLOBAL "); /* Only global variables are replicated */
 
879
  destination.append("SET GLOBAL ", 11); /* Only global variables are replicated */
959
880
  destination.append(variable_metadata.name());
960
881
  destination.push_back('=');
961
882
 
987
908
  if (sql_variant == ANSI)
988
909
    quoted_identifier= '"';
989
910
 
990
 
  destination.append("CREATE ");
 
911
  destination.append("CREATE ", 7);
991
912
 
992
913
  if (table.type() == Table::TEMPORARY)
993
 
    destination.append("TEMPORARY ");
 
914
    destination.append("TEMPORARY ", 10);
994
915
  
995
 
  destination.append("TABLE ");
 
916
  destination.append("TABLE ", 6);
996
917
  if (with_schema)
997
918
  {
998
919
    append_escaped_string(&destination, table.schema(), quoted_identifier);
999
920
    destination.push_back('.');
1000
921
  }
1001
922
  append_escaped_string(&destination, table.name(), quoted_identifier);
1002
 
  destination.append(" (\n");
 
923
  destination.append(" (\n", 3);
1003
924
 
1004
925
  enum TransformSqlError result= NONE;
1005
926
  size_t num_fields= table.field_size();
1008
929
    const Table::Field &field= table.field(x);
1009
930
 
1010
931
    if (x != 0)
1011
 
      destination.append(",\n");
 
932
      destination.append(",\n", 2);
1012
933
 
1013
934
    destination.append("  ");
1014
935
 
1021
942
  size_t num_indexes= table.indexes_size();
1022
943
  
1023
944
  if (num_indexes > 0)
1024
 
    destination.append(",\n");
 
945
    destination.append(",\n", 2);
1025
946
 
1026
947
  for (size_t x= 0; x < num_indexes; ++x)
1027
948
  {
1028
949
    const message::Table::Index &index= table.indexes(x);
1029
950
 
1030
951
    if (x != 0)
1031
 
      destination.append(",\n");
 
952
      destination.append(",\n", 2);
1032
953
 
1033
954
    result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
1034
955
    
1039
960
  size_t num_foreign_keys= table.fk_constraint_size();
1040
961
 
1041
962
  if (num_foreign_keys > 0)
1042
 
    destination.append(",\n");
 
963
    destination.append(",\n", 2);
1043
964
 
1044
965
  for (size_t x= 0; x < num_foreign_keys; ++x)
1045
966
  {
1046
967
    const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
1047
968
 
1048
969
    if (x != 0)
1049
 
      destination.append(",\n");
 
970
      destination.append(",\n", 2);
1050
971
 
1051
972
    result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1052
973
 
1054
975
      return result;
1055
976
  }
1056
977
 
1057
 
  destination.append("\n)");
 
978
  destination.append("\n)", 2);
1058
979
 
1059
980
  /* Add ENGINE = " clause */
1060
981
  if (table.has_engine())
1061
982
  {
1062
 
    destination.append(" ENGINE=");
 
983
    destination.append(" ENGINE=", 8);
1063
984
    destination.append(table.engine().name());
1064
985
 
1065
986
    size_t num_engine_options= table.engine().options_size();
1069
990
    {
1070
991
      const Engine::Option &option= table.engine().options(x);
1071
992
      destination.append(option.name());
1072
 
      destination.append("='");
 
993
      destination.append("='", 2);
1073
994
      destination.append(option.state());
1074
 
      destination.append("'");
1075
 
      if (x != num_engine_options-1)
1076
 
      {
1077
 
        destination.append(", ");
1078
 
      }
 
995
      destination.append("'", 1);
 
996
      if(x != num_engine_options-1)
 
997
        destination.append(", ", 2);
1079
998
    }
1080
999
  }
1081
1000
 
1093
1012
  if (sql_variant == ANSI)
1094
1013
    return NONE; /* ANSI does not support table options... */
1095
1014
 
 
1015
  stringstream ss;
 
1016
 
1096
1017
  if (options.has_comment())
1097
1018
  {
1098
 
    destination.append(" COMMENT=");
 
1019
    destination.append(" COMMENT=", 9);
1099
1020
    append_escaped_string(&destination, options.comment());
1100
1021
  }
1101
1022
 
1102
1023
  if (options.has_collation())
1103
1024
  {
1104
 
    destination.append(" COLLATE = ");
 
1025
    destination.append(" COLLATE = ", 11);
1105
1026
    destination.append(options.collation());
1106
1027
  }
1107
1028
 
1108
1029
  if (options.has_data_file_name())
1109
1030
  {
1110
 
    destination.append("\nDATA_FILE_NAME = '");
 
1031
    destination.append("\nDATA_FILE_NAME = '", 19);
1111
1032
    destination.append(options.data_file_name());
1112
1033
    destination.push_back('\'');
1113
1034
  }
1114
1035
 
1115
1036
  if (options.has_index_file_name())
1116
1037
  {
1117
 
    destination.append("\nINDEX_FILE_NAME = '");
 
1038
    destination.append("\nINDEX_FILE_NAME = '", 20);
1118
1039
    destination.append(options.index_file_name());
1119
1040
    destination.push_back('\'');
1120
1041
  }
1121
1042
 
1122
1043
  if (options.has_max_rows())
1123
1044
  {
1124
 
    destination.append("\nMAX_ROWS = ");
1125
 
    destination.append(boost::lexical_cast<string>(options.max_rows()));
 
1045
    ss << options.max_rows();
 
1046
    destination.append("\nMAX_ROWS = ", 12);
 
1047
    destination.append(ss.str());
 
1048
    ss.clear();
1126
1049
  }
1127
1050
 
1128
1051
  if (options.has_min_rows())
1129
1052
  {
1130
 
    destination.append("\nMIN_ROWS = ");
1131
 
    destination.append(boost::lexical_cast<string>(options.min_rows()));
 
1053
    ss << options.min_rows();
 
1054
    destination.append("\nMIN_ROWS = ", 12);
 
1055
    destination.append(ss.str());
 
1056
    ss.clear();
1132
1057
  }
1133
1058
 
1134
1059
  if (options.has_user_set_auto_increment_value()
1135
1060
      && options.has_auto_increment_value())
1136
1061
  {
1137
 
    destination.append(" AUTO_INCREMENT=");
1138
 
    destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
 
1062
    ss << options.auto_increment_value();
 
1063
    destination.append(" AUTO_INCREMENT=", 16);
 
1064
    destination.append(ss.str());
 
1065
    ss.clear();
1139
1066
  }
1140
1067
 
1141
1068
  if (options.has_avg_row_length())
1142
1069
  {
1143
 
    destination.append("\nAVG_ROW_LENGTH = ");
1144
 
    destination.append(boost::lexical_cast<string>(options.avg_row_length()));
1145
 
  }
1146
 
 
1147
 
  if (options.has_checksum() && options.checksum())
1148
 
    destination.append("\nCHECKSUM = TRUE");
1149
 
 
1150
 
  if (options.has_page_checksum() && options.page_checksum())
1151
 
    destination.append("\nPAGE_CHECKSUM = TRUE");
1152
 
 
1153
 
  if (options.has_dont_replicate() and options.dont_replicate())
1154
 
  {
1155
 
    destination.append(" REPLICATION = FALSE");
1156
 
  }
 
1070
    ss << options.avg_row_length();
 
1071
    destination.append("\nAVG_ROW_LENGTH = ", 18);
 
1072
    destination.append(ss.str());
 
1073
    ss.clear();
 
1074
  }
 
1075
 
 
1076
  if (options.has_checksum() &&
 
1077
      options.checksum())
 
1078
    destination.append("\nCHECKSUM = TRUE", 16);
 
1079
  if (options.has_page_checksum() &&
 
1080
      options.page_checksum())
 
1081
    destination.append("\nPAGE_CHECKSUM = TRUE", 21);
1157
1082
 
1158
1083
  return NONE;
1159
1084
}
1171
1096
  destination.append("  ", 2);
1172
1097
 
1173
1098
  if (index.is_primary())
1174
 
    destination.append("PRIMARY ");
 
1099
    destination.append("PRIMARY ", 8);
1175
1100
  else if (index.is_unique())
1176
 
    destination.append("UNIQUE ");
 
1101
    destination.append("UNIQUE ", 7);
1177
1102
 
1178
1103
  destination.append("KEY ", 4);
1179
1104
  if (! (index.is_primary() && index.name().compare("PRIMARY")==0))
1211
1136
      {
1212
1137
        if (part.compare_length() != field.string_options().length())
1213
1138
        {
 
1139
          stringstream ss;
1214
1140
          destination.push_back('(');
1215
 
          destination.append(boost::lexical_cast<string>(part.compare_length()));
 
1141
          ss << part.compare_length();
 
1142
          destination.append(ss.str());
1216
1143
          destination.push_back(')');
1217
1144
        }
1218
1145
      }
1225
1152
  case Table::Index::UNKNOWN_INDEX:
1226
1153
    break;
1227
1154
  case Table::Index::BTREE:
1228
 
    destination.append(" USING BTREE");
 
1155
    destination.append(" USING BTREE", 12);
1229
1156
    break;
1230
1157
  case Table::Index::RTREE:
1231
 
    destination.append(" USING RTREE");
 
1158
    destination.append(" USING RTREE", 12);
1232
1159
    break;
1233
1160
  case Table::Index::HASH:
1234
 
    destination.append(" USING HASH");
 
1161
    destination.append(" USING HASH", 11);
1235
1162
    break;
1236
1163
  case Table::Index::FULLTEXT:
1237
 
    destination.append(" USING FULLTEXT");
 
1164
    destination.append(" USING FULLTEXT", 15);
1238
1165
    break;
1239
1166
  }
1240
1167
 
1241
1168
  if (index.has_comment())
1242
1169
  {
1243
 
    destination.append(" COMMENT ");
 
1170
    destination.append(" COMMENT ", 9);
1244
1171
    append_escaped_string(&destination, index.comment());
1245
1172
  }
1246
1173
 
1251
1178
{
1252
1179
  switch (opt)
1253
1180
  {
 
1181
  case Table::ForeignKeyConstraint::OPTION_UNDEF:
 
1182
    break;
1254
1183
  case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1255
1184
    destination.append("RESTRICT");
1256
1185
    break;
1260
1189
  case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1261
1190
    destination.append("SET NULL");
1262
1191
    break;
1263
 
  case Table::ForeignKeyConstraint::OPTION_UNDEF:
1264
1192
  case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1265
1193
    destination.append("NO ACTION");
1266
1194
    break;
1267
 
  case Table::ForeignKeyConstraint::OPTION_SET_DEFAULT:
 
1195
  case Table::ForeignKeyConstraint::OPTION_DEFAULT:
1268
1196
    destination.append("SET DEFAULT");
1269
1197
    break;
1270
1198
  }
1280
1208
  if (sql_variant == ANSI)
1281
1209
    quoted_identifier= '"';
1282
1210
 
1283
 
  destination.append("  ");
 
1211
  destination.append("  ", 2);
1284
1212
 
1285
1213
  if (fkey.has_name())
1286
1214
  {
1287
 
    destination.append("CONSTRAINT ");
 
1215
    destination.append("CONSTRAINT ", 11);
1288
1216
    append_escaped_string(&destination, fkey.name(), quoted_identifier);
1289
1217
    destination.append(" ", 1);
1290
1218
  }
1291
1219
 
1292
 
  destination.append("FOREIGN KEY (");
 
1220
  destination.append("FOREIGN KEY (", 13);
1293
1221
 
1294
1222
  for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1295
1223
  {
1300
1228
                          quoted_identifier);
1301
1229
  }
1302
1230
 
1303
 
  destination.append(") REFERENCES ");
 
1231
  destination.append(") REFERENCES ", 13);
1304
1232
 
1305
1233
  append_escaped_string(&destination, fkey.references_table_name(),
1306
1234
                        quoted_identifier);
1307
 
  destination.append(" (");
 
1235
  destination.append(" (", 2);
1308
1236
 
1309
1237
  for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1310
1238
  {
1317
1245
 
1318
1246
  destination.push_back(')');
1319
1247
 
1320
 
  if (fkey.has_update_option() and fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
 
1248
  if (fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1321
1249
  {
1322
 
    destination.append(" ON UPDATE ");
 
1250
    destination.append(" ON UPDATE ", 11);
1323
1251
    transformForeignKeyOptionToSql(fkey.update_option(), destination);
1324
1252
  }
1325
1253
 
1326
 
  if (fkey.has_delete_option() and fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
 
1254
  if (fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1327
1255
  {
1328
 
    destination.append(" ON DELETE ");
 
1256
    destination.append(" ON DELETE ", 11);
1329
1257
    transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1330
1258
  }
1331
1259
 
1355
1283
  switch (field_type)
1356
1284
  {
1357
1285
    case Table::Field::DOUBLE:
1358
 
    destination.append(" DOUBLE");
 
1286
    destination.append(" DOUBLE", 7);
1359
1287
    if (field.has_numeric_options()
1360
1288
        && field.numeric_options().has_precision())
1361
1289
    {
1369
1297
    {
1370
1298
      if (field.string_options().has_collation()
1371
1299
          && field.string_options().collation().compare("binary") == 0)
1372
 
        destination.append(" VARBINARY(");
 
1300
        destination.append(" VARBINARY(", 11);
1373
1301
      else
1374
 
        destination.append(" VARCHAR(");
 
1302
        destination.append(" VARCHAR(", 9);
1375
1303
 
1376
 
      destination.append(boost::lexical_cast<string>(field.string_options().length()));
1377
 
      destination.append(")");
 
1304
      stringstream ss;
 
1305
      ss << field.string_options().length() << ")";
 
1306
      destination.append(ss.str());
1378
1307
    }
1379
1308
    break;
1380
1309
  case Table::Field::BLOB:
1381
1310
    {
1382
1311
      if (field.string_options().has_collation()
1383
1312
          && field.string_options().collation().compare("binary") == 0)
1384
 
        destination.append(" BLOB");
 
1313
        destination.append(" BLOB", 5);
1385
1314
      else
1386
 
        destination.append(" TEXT");
 
1315
        destination.append(" TEXT", 5);
1387
1316
    }
1388
1317
    break;
1389
1318
  case Table::Field::ENUM:
1390
1319
    {
1391
1320
      size_t num_field_values= field.enumeration_values().field_value_size();
1392
 
      destination.append(" ENUM(");
 
1321
      destination.append(" ENUM(", 6);
1393
1322
      for (size_t x= 0; x < num_field_values; ++x)
1394
1323
      {
1395
1324
        const string &type= field.enumeration_values().field_value(x);
1404
1333
      destination.push_back(')');
1405
1334
      break;
1406
1335
    }
1407
 
  case Table::Field::UUID:
1408
 
    destination.append(" UUID");
1409
 
    break;
1410
 
  case Table::Field::BOOLEAN:
1411
 
    destination.append(" BOOLEAN");
1412
 
    break;
1413
1336
  case Table::Field::INTEGER:
1414
 
    destination.append(" INT");
 
1337
    destination.append(" INT", 4);
1415
1338
    break;
1416
1339
  case Table::Field::BIGINT:
1417
 
    if (field.has_constraints() and
1418
 
        field.constraints().is_unsigned())
1419
 
    {
1420
 
      destination.append(" BIGINT UNSIGNED");
1421
 
    }
1422
 
    else
1423
 
    {
1424
 
      destination.append(" BIGINT");
1425
 
    }
 
1340
    destination.append(" BIGINT", 7);
1426
1341
    break;
1427
1342
  case Table::Field::DECIMAL:
1428
1343
    {
1429
 
      destination.append(" DECIMAL(");
 
1344
      destination.append(" DECIMAL(", 9);
1430
1345
      stringstream ss;
1431
1346
      ss << field.numeric_options().precision() << ",";
1432
1347
      ss << field.numeric_options().scale() << ")";
1434
1349
    }
1435
1350
    break;
1436
1351
  case Table::Field::DATE:
1437
 
    destination.append(" DATE");
1438
 
    break;
1439
 
 
1440
 
  case Table::Field::EPOCH:
1441
 
    if (field.time_options().microseconds())
1442
 
    {
1443
 
      destination.append(" TIMESTAMP(6)");
1444
 
    }
1445
 
    else
1446
 
    {
1447
 
      destination.append(" TIMESTAMP");
1448
 
    }
1449
 
    break;
1450
 
 
 
1352
    destination.append(" DATE", 5);
 
1353
    break;
 
1354
  case Table::Field::TIMESTAMP:
 
1355
    destination.append(" TIMESTAMP",  10);
 
1356
    break;
1451
1357
  case Table::Field::DATETIME:
1452
 
    destination.append(" DATETIME");
1453
 
    break;
1454
 
  case Table::Field::TIME:
1455
 
    destination.append(" TIME");
1456
 
    break;
 
1358
    destination.append(" DATETIME",  9);
 
1359
    break;
 
1360
  }
 
1361
 
 
1362
  if (field.type() == Table::Field::INTEGER || 
 
1363
      field.type() == Table::Field::BIGINT)
 
1364
  {
 
1365
    if (field.has_constraints() &&
 
1366
        field.constraints().has_is_unsigned() &&
 
1367
        field.constraints().is_unsigned())
 
1368
    {
 
1369
      destination.append(" UNSIGNED", 9);
 
1370
    }
1457
1371
  }
1458
1372
 
1459
1373
  if (field.type() == Table::Field::BLOB ||
1462
1376
    if (field.string_options().has_collation()
1463
1377
        && field.string_options().collation().compare("binary"))
1464
1378
    {
1465
 
      destination.append(" COLLATE ");
 
1379
      destination.append(" COLLATE ", 9);
1466
1380
      destination.append(field.string_options().collation());
1467
1381
    }
1468
1382
  }
1469
1383
 
1470
 
  if (field.has_constraints() and field.constraints().is_unique())
1471
 
  {
1472
 
    destination.append(" UNIQUE");
1473
 
  }
1474
 
 
1475
 
  if (field.has_constraints() && field.constraints().is_notnull())
1476
 
  {
1477
 
    destination.append(" NOT NULL");
1478
 
  }
1479
 
  else if (field.type() == Table::Field::EPOCH)
1480
 
  {
1481
 
    destination.append(" NULL");
1482
 
  }
 
1384
  if (field.has_constraints() &&
 
1385
      ! field.constraints().is_nullable())
 
1386
  {
 
1387
    destination.append(" NOT NULL", 9);
 
1388
  }
 
1389
  else if (field.type() == Table::Field::TIMESTAMP)
 
1390
    destination.append(" NULL", 5);
1483
1391
 
1484
1392
  if (field.type() == Table::Field::INTEGER || 
1485
1393
      field.type() == Table::Field::BIGINT)
1488
1396
    if (field.has_numeric_options() &&
1489
1397
        field.numeric_options().is_autoincrement())
1490
1398
    {
1491
 
      destination.append(" AUTO_INCREMENT");
 
1399
      destination.append(" AUTO_INCREMENT", 15);
1492
1400
    }
1493
1401
  }
1494
1402
 
1495
1403
  if (field.options().has_default_value())
1496
1404
  {
1497
 
    destination.append(" DEFAULT ");
 
1405
    destination.append(" DEFAULT ", 9);
1498
1406
    append_escaped_string(&destination, field.options().default_value());
1499
1407
  }
1500
1408
  else if (field.options().has_default_expression())
1501
1409
  {
1502
 
    destination.append(" DEFAULT ");
 
1410
    destination.append(" DEFAULT ", 9);
1503
1411
    destination.append(field.options().default_expression());
1504
1412
  }
1505
1413
  else if (field.options().has_default_bin_value())
1506
1414
  {
1507
1415
    const string &v= field.options().default_bin_value();
1508
1416
    if (v.length() == 0)
1509
 
    {
1510
 
      destination.append(" DEFAULT ''");
1511
 
    }
 
1417
      destination.append(" DEFAULT ''", 11);
1512
1418
    else
1513
1419
    {
1514
 
      destination.append(" DEFAULT 0x");
 
1420
      destination.append(" DEFAULT 0x", 11);
1515
1421
      for (size_t x= 0; x < v.length(); x++)
1516
1422
      {
1517
1423
        char hex[3];
1524
1430
           && field.options().default_null()
1525
1431
           && field.type() != Table::Field::BLOB)
1526
1432
  {
1527
 
    destination.append(" DEFAULT NULL");
 
1433
    destination.append(" DEFAULT NULL", 13);
1528
1434
  }
1529
1435
 
1530
1436
  if (field.has_options() && field.options().has_update_expression())
1531
1437
  {
1532
 
    destination.append(" ON UPDATE ");
 
1438
    destination.append(" ON UPDATE ", 11);
1533
1439
    destination.append(field.options().update_expression());
1534
1440
  }
1535
1441
 
1536
1442
  if (field.has_comment())
1537
1443
  {
1538
 
    destination.append(" COMMENT ");
 
1444
    destination.append(" COMMENT ", 9);
1539
1445
    append_escaped_string(&destination, field.comment(), quoted_default);
1540
1446
  }
1541
1447
  return NONE;
1549
1455
  case Table::Field::DECIMAL:
1550
1456
  case Table::Field::INTEGER:
1551
1457
  case Table::Field::BIGINT:
 
1458
  case Table::Field::ENUM:
1552
1459
    return false;
1553
1460
  default:
1554
1461
    return true;
1565
1472
  case DRIZZLE_TYPE_NULL:
1566
1473
    assert(false); /* Not a user definable type */
1567
1474
    return Table::Field::INTEGER; /* unreachable */
1568
 
  case DRIZZLE_TYPE_MICROTIME:
1569
1475
  case DRIZZLE_TYPE_TIMESTAMP:
1570
 
    return Table::Field::EPOCH;
 
1476
    return Table::Field::TIMESTAMP;
1571
1477
  case DRIZZLE_TYPE_LONGLONG:
1572
1478
    return Table::Field::BIGINT;
1573
1479
  case DRIZZLE_TYPE_DATETIME:
1574
1480
    return Table::Field::DATETIME;
1575
 
  case DRIZZLE_TYPE_TIME:
1576
 
    return Table::Field::TIME;
1577
1481
  case DRIZZLE_TYPE_DATE:
1578
1482
    return Table::Field::DATE;
1579
1483
  case DRIZZLE_TYPE_VARCHAR:
1584
1488
    return Table::Field::ENUM;
1585
1489
  case DRIZZLE_TYPE_BLOB:
1586
1490
    return Table::Field::BLOB;
1587
 
  case DRIZZLE_TYPE_UUID:
1588
 
    return Table::Field::UUID;
1589
 
  case DRIZZLE_TYPE_BOOLEAN:
1590
 
    return Table::Field::BOOLEAN;
1591
1491
  }
1592
1492
 
1593
1493
  assert(false);