~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

  • Committer: Monty Taylor
  • Date: 2010-06-02 22:35:45 UTC
  • mto: This revision was merged to the branch mainline in revision 1586.
  • Revision ID: mordred@inaugust.com-20100602223545-q8ekf9b40a85nwuf
Rearragned unittests into a single exe because of how we need to link it
(thanks lifeless)
Link with server symbols without needing to build a library.
Added an additional atomics test which tests whatever version of the atomics
lib the running platform would actually use.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 
32
32
#include "config.h"
33
33
 
34
 
#include <boost/lexical_cast.hpp>
35
34
#include "drizzled/message/statement_transform.h"
36
35
#include "drizzled/message/transaction.pb.h"
37
36
#include "drizzled/message/table.pb.h"
38
 
#include "drizzled/charset.h"
39
 
#include "drizzled/charset_info.h"
40
 
#include "drizzled/global_charset_info.h"
41
37
 
42
38
#include <string>
43
39
#include <vector>
52
48
namespace message
53
49
{
54
50
 
55
 
static void escapeEmbeddedQuotes(string &s, const char quote='\'')
56
 
{
57
 
  string::iterator it;
58
 
 
59
 
  for (it= s.begin(); it != s.end(); ++it)
60
 
  {
61
 
    if (*it == quote)
62
 
    {
63
 
      it= s.insert(it, quote);
64
 
      ++it;  // advance back to the quote
65
 
    }
66
 
  }
67
 
}
68
 
 
69
 
/* Incredibly similar to append_unescaped() in table.cc, but for std::string */
70
 
static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
71
 
{
72
 
  const char *pos= input.c_str();
73
 
  const char *end= input.c_str()+input.length();
74
 
  res->push_back(quote);
75
 
 
76
 
  for (; pos != end ; pos++)
77
 
  {
78
 
    uint32_t mblen;
79
 
    if (use_mb(default_charset_info) &&
80
 
        (mblen= my_ismbchar(default_charset_info, pos, end)))
81
 
    {
82
 
      res->append(pos, mblen);
83
 
      pos+= mblen - 1;
84
 
      if (pos >= end)
85
 
        break;
86
 
      continue;
87
 
    }
88
 
 
89
 
    switch (*pos) {
90
 
    case 0:                             /* Must be escaped for 'mysql' */
91
 
      res->push_back('\\');
92
 
      res->push_back('0');
93
 
      break;
94
 
    case '\n':                          /* Must be escaped for logs */
95
 
      res->push_back('\\');
96
 
      res->push_back('n');
97
 
      break;
98
 
    case '\r':
99
 
      res->push_back('\\');             /* This gives better readability */
100
 
      res->push_back('r');
101
 
      break;
102
 
    case '\\':
103
 
      res->push_back('\\');             /* Because of the sql syntax */
104
 
      res->push_back('\\');
105
 
      break;
106
 
    default:
107
 
      if (*pos == quote) /* SQL syntax for quoting a quote */
108
 
      {
109
 
        res->push_back(quote);
110
 
        res->push_back(quote);
111
 
      }
112
 
      else
113
 
        res->push_back(*pos);
114
 
      break;
115
 
    }
116
 
  }
117
 
  res->push_back(quote);
118
 
}
119
 
 
120
51
enum TransformSqlError
121
52
transformStatementToSql(const Statement &source,
122
53
                        vector<string> &sql_strings,
127
58
 
128
59
  switch (source.type())
129
60
  {
130
 
  case Statement::ROLLBACK_STATEMENT:
131
 
    {
132
 
      break;
133
 
    }
134
 
  case Statement::ROLLBACK:
135
 
    {
136
 
      sql_strings.push_back("ROLLBACK");
137
 
      break;
138
 
    }
139
61
  case Statement::INSERT:
140
62
    {
141
63
      if (! source.has_insert_header())
401
323
 
402
324
    const FieldMetadata &field_metadata= header.field_metadata(x);
403
325
 
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
 
    }
 
326
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
412
327
 
413
328
    if (should_quote_field_value)
414
329
      destination.push_back('\'');
415
330
 
416
 
    if (record.is_null(x))
 
331
    if (field_metadata.type() == Table::Field::BLOB)
417
332
    {
418
 
      destination.append("NULL");
 
333
      /* 
 
334
        * We do this here because BLOB data is returned
 
335
        * in a string correctly, but calling append()
 
336
        * without a length will result in only the string
 
337
        * up to a \0 being output here.
 
338
        */
 
339
      string raw_data(record.insert_value(x));
 
340
      destination.append(raw_data.c_str(), raw_data.size());
419
341
    }
420
342
    else
421
343
    {
422
 
      if (field_metadata.type() == Table::Field::BLOB)
423
 
      {
424
 
        /*
425
 
         * We do this here because BLOB data is returned
426
 
         * in a string correctly, but calling append()
427
 
         * without a length will result in only the string
428
 
         * up to a \0 being output here.
429
 
         */
430
 
        string raw_data(record.insert_value(x));
431
 
        destination.append(raw_data.c_str(), raw_data.size());
432
 
      }
433
 
      else
434
 
      {
435
 
        string tmp(record.insert_value(x));
436
 
        escapeEmbeddedQuotes(tmp);
437
 
        destination.append(tmp);
438
 
      }
 
344
      destination.append(record.insert_value(x));
439
345
    }
440
346
 
441
347
    if (should_quote_field_value)
498
404
      }
499
405
      else
500
406
      {
501
 
        string tmp(data.record(x).insert_value(y));
502
 
        escapeEmbeddedQuotes(tmp);
503
 
        destination.append(tmp);
 
407
        destination.append(data.record(x).insert_value(y));
504
408
      }
505
409
 
506
410
      if (should_quote_field_value)
564
468
    destination.push_back(quoted_identifier);
565
469
    destination.push_back('=');
566
470
 
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
 
    }    
 
471
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
575
472
 
576
473
    if (should_quote_field_value)
577
474
      destination.push_back('\'');
578
475
 
579
 
    if (record.is_null(x))
 
476
    if (field_metadata.type() == Table::Field::BLOB)
580
477
    {
581
 
      destination.append("NULL");
 
478
      /* 
 
479
       * We do this here because BLOB data is returned
 
480
       * in a string correctly, but calling append()
 
481
       * without a length will result in only the string
 
482
       * up to a \0 being output here.
 
483
       */
 
484
      string raw_data(record.after_value(x));
 
485
      destination.append(raw_data.c_str(), raw_data.size());
582
486
    }
583
 
    else 
 
487
    else
584
488
    {
585
 
      if (field_metadata.type() == Table::Field::BLOB)
586
 
      {
587
 
        /*
588
 
         * We do this here because BLOB data is returned
589
 
         * in a string correctly, but calling append()
590
 
         * without a length will result in only the string
591
 
         * up to a \0 being output here.
592
 
         */
593
 
        string raw_data(record.after_value(x));
594
 
        destination.append(raw_data.c_str(), raw_data.size());
595
 
      }
596
 
      else 
597
 
      {
598
 
        string tmp(record.after_value(x));
599
 
        escapeEmbeddedQuotes(tmp);
600
 
        destination.append(tmp);
601
 
      }
 
489
      destination.append(record.after_value(x));
602
490
    }
603
491
 
604
492
    if (should_quote_field_value)
720
608
    }
721
609
    else
722
610
    {
723
 
      string tmp(record.key_value(x));
724
 
      escapeEmbeddedQuotes(tmp);
725
 
      destination.append(tmp);
 
611
      destination.append(record.key_value(x));
726
612
    }
727
613
 
728
614
    if (should_quote_field_value)
791
677
      }
792
678
      else
793
679
      {
794
 
        string tmp(data.record(x).key_value(y));
795
 
        escapeEmbeddedQuotes(tmp);
796
 
        destination.append(tmp);
 
680
        destination.append(data.record(x).key_value(y));
797
681
      }
798
682
 
799
683
      if (should_quote_field_value)
950
834
  destination.append("TABLE ", 6);
951
835
  if (with_schema)
952
836
  {
953
 
    append_escaped_string(&destination, table.schema(), quoted_identifier);
 
837
    destination.push_back(quoted_identifier);
 
838
    destination.append(table.schema());
 
839
    destination.push_back(quoted_identifier);
954
840
    destination.push_back('.');
955
841
  }
956
 
  append_escaped_string(&destination, table.name(), quoted_identifier);
 
842
  destination.push_back(quoted_identifier);
 
843
  destination.append(table.name());
 
844
  destination.push_back(quoted_identifier);
957
845
  destination.append(" (\n", 3);
958
846
 
959
847
  enum TransformSqlError result= NONE;
965
853
    if (x != 0)
966
854
      destination.append(",\n", 2);
967
855
 
968
 
    destination.append("  ");
969
 
 
970
856
    result= transformFieldDefinitionToSql(field, destination, sql_variant);
971
 
 
 
857
    
972
858
    if (result != NONE)
973
859
      return result;
974
860
  }
990
876
    if (result != NONE)
991
877
      return result;
992
878
  }
993
 
 
994
 
  size_t num_foreign_keys= table.fk_constraint_size();
995
 
 
996
 
  if (num_foreign_keys > 0)
997
 
    destination.append(",\n", 2);
998
 
 
999
 
  for (size_t x= 0; x < num_foreign_keys; ++x)
1000
 
  {
1001
 
    const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
1002
 
 
1003
 
    if (x != 0)
1004
 
      destination.append(",\n", 2);
1005
 
 
1006
 
    result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1007
 
 
1008
 
    if (result != NONE)
1009
 
      return result;
1010
 
  }
1011
 
 
1012
879
  destination.append("\n)", 2);
1013
880
 
1014
881
  /* Add ENGINE = " clause */
1015
882
  if (table.has_engine())
1016
883
  {
1017
 
    destination.append(" ENGINE=", 8);
 
884
    destination.append("\nENGINE = ", 10);
1018
885
    destination.append(table.engine().name());
1019
886
 
1020
887
    size_t num_engine_options= table.engine().options_size();
1021
 
    if (num_engine_options > 0)
1022
 
      destination.append(" ", 1);
1023
888
    for (size_t x= 0; x < num_engine_options; ++x)
1024
889
    {
1025
890
      const Engine::Option &option= table.engine().options(x);
 
891
      destination.push_back('\n');
1026
892
      destination.append(option.name());
1027
 
      destination.append("='", 2);
 
893
      destination.append(" = ", 3);
1028
894
      destination.append(option.state());
1029
 
      destination.append("'", 1);
1030
 
      if(x != num_engine_options-1)
1031
 
        destination.append(", ", 2);
 
895
      destination.push_back('\n');
1032
896
    }
1033
897
  }
1034
898
 
1046
910
  if (sql_variant == ANSI)
1047
911
    return NONE; /* ANSI does not support table options... */
1048
912
 
 
913
  stringstream ss;
 
914
 
1049
915
  if (options.has_comment())
1050
916
  {
1051
 
    destination.append(" COMMENT=", 9);
1052
 
    append_escaped_string(&destination, options.comment());
 
917
    destination.append("\nCOMMENT = '", 12);
 
918
    destination.append(options.comment());
 
919
    destination.push_back('\'');
1053
920
  }
1054
921
 
1055
922
  if (options.has_collation())
1056
923
  {
1057
 
    destination.append(" COLLATE = ", 11);
 
924
    destination.append("\nCOLLATE = ", 11);
1058
925
    destination.append(options.collation());
1059
926
  }
1060
927
 
 
928
  if (options.has_auto_increment())
 
929
  {
 
930
    ss << options.auto_increment();
 
931
    destination.append("\nAUTOINCREMENT_OFFSET = ", 24);
 
932
    destination.append(ss.str());
 
933
    ss.clear();
 
934
  }
 
935
  
 
936
  if (options.has_row_type())
 
937
  {
 
938
    ss << options.row_type();
 
939
    destination.append("\nROW_TYPE = ", 12);
 
940
    destination.append(ss.str());
 
941
    ss.clear();
 
942
  }
 
943
 
1061
944
  if (options.has_data_file_name())
1062
945
  {
1063
946
    destination.append("\nDATA_FILE_NAME = '", 19);
1074
957
 
1075
958
  if (options.has_max_rows())
1076
959
  {
 
960
    ss << options.max_rows();
1077
961
    destination.append("\nMAX_ROWS = ", 12);
1078
 
    destination.append(boost::lexical_cast<string>(options.max_rows()));
 
962
    destination.append(ss.str());
 
963
    ss.clear();
1079
964
  }
1080
965
 
1081
966
  if (options.has_min_rows())
1082
967
  {
 
968
    ss << options.min_rows();
1083
969
    destination.append("\nMIN_ROWS = ", 12);
1084
 
    destination.append(boost::lexical_cast<string>(options.min_rows()));
 
970
    destination.append(ss.str());
 
971
    ss.clear();
1085
972
  }
1086
973
 
1087
 
  if (options.has_user_set_auto_increment_value()
1088
 
      && options.has_auto_increment_value())
 
974
  if (options.has_auto_increment_value())
1089
975
  {
1090
 
    destination.append(" AUTO_INCREMENT=", 16);
1091
 
    destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
 
976
    ss << options.auto_increment_value();
 
977
    destination.append("\nAUTO_INCREMENT = ", 18);
 
978
    destination.append(ss.str());
 
979
    ss.clear();
1092
980
  }
1093
981
 
1094
982
  if (options.has_avg_row_length())
1095
983
  {
 
984
    ss << options.avg_row_length();
1096
985
    destination.append("\nAVG_ROW_LENGTH = ", 18);
1097
 
    destination.append(boost::lexical_cast<string>(options.avg_row_length()));
 
986
    destination.append(ss.str());
 
987
    ss.clear();
1098
988
  }
1099
989
 
1100
990
  if (options.has_checksum() &&
1117
1007
  if (sql_variant == ANSI)
1118
1008
    quoted_identifier= '"';
1119
1009
 
1120
 
  destination.append("  ", 2);
1121
 
 
1122
1010
  if (index.is_primary())
1123
1011
    destination.append("PRIMARY ", 8);
1124
1012
  else if (index.is_unique())
1125
1013
    destination.append("UNIQUE ", 7);
1126
1014
 
1127
1015
  destination.append("KEY ", 4);
1128
 
  if (! (index.is_primary() && index.name().compare("PRIMARY")==0))
1129
 
  {
1130
 
    destination.push_back(quoted_identifier);
1131
 
    destination.append(index.name());
1132
 
    destination.push_back(quoted_identifier);
1133
 
    destination.append(" (", 2);
1134
 
  }
1135
 
  else
1136
 
    destination.append("(", 1);
1137
 
 
 
1016
  destination.push_back(quoted_identifier);
 
1017
  destination.append(index.name());
 
1018
  destination.push_back(quoted_identifier);
 
1019
  destination.append(" (", 2);
 
1020
  
1138
1021
  size_t num_parts= index.index_part_size();
1139
1022
  for (size_t x= 0; x < num_parts; ++x)
1140
1023
  {
1158
1041
    {
1159
1042
      if (part.has_compare_length())
1160
1043
      {
1161
 
        if (part.compare_length() != field.string_options().length())
 
1044
        size_t compare_length_in_chars= part.compare_length();
 
1045
        
 
1046
        /* hack: compare_length() is bytes, not chars, but
 
1047
         * only for VARCHAR. Ass. */
 
1048
        if (field.type() == Table::Field::VARCHAR)
 
1049
          compare_length_in_chars/= 4;
 
1050
 
 
1051
        if (compare_length_in_chars != field.string_options().length())
1162
1052
        {
 
1053
          stringstream ss;
1163
1054
          destination.push_back('(');
1164
 
          destination.append(boost::lexical_cast<string>(part.compare_length()));
 
1055
          ss << compare_length_in_chars;
 
1056
          destination.append(ss.str());
1165
1057
          destination.push_back(')');
1166
1058
        }
1167
1059
      }
1169
1061
  }
1170
1062
  destination.push_back(')');
1171
1063
 
1172
 
  switch (index.type())
1173
 
  {
1174
 
  case Table::Index::UNKNOWN_INDEX:
1175
 
    break;
1176
 
  case Table::Index::BTREE:
1177
 
    destination.append(" USING BTREE", 12);
1178
 
    break;
1179
 
  case Table::Index::RTREE:
1180
 
    destination.append(" USING RTREE", 12);
1181
 
    break;
1182
 
  case Table::Index::HASH:
1183
 
    destination.append(" USING HASH", 11);
1184
 
    break;
1185
 
  case Table::Index::FULLTEXT:
1186
 
    destination.append(" USING FULLTEXT", 15);
1187
 
    break;
1188
 
  }
1189
 
 
1190
 
  if (index.has_comment())
1191
 
  {
1192
 
    destination.append(" COMMENT ", 9);
1193
 
    append_escaped_string(&destination, index.comment());
1194
 
  }
1195
 
 
1196
 
  return NONE;
1197
 
}
1198
 
 
1199
 
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
1200
 
{
1201
 
  switch (opt)
1202
 
  {
1203
 
  case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1204
 
    destination.append("RESTRICT");
1205
 
    break;
1206
 
  case Table::ForeignKeyConstraint::OPTION_CASCADE:
1207
 
    destination.append("CASCADE");
1208
 
    break;
1209
 
  case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1210
 
    destination.append("SET NULL");
1211
 
    break;
1212
 
  case Table::ForeignKeyConstraint::OPTION_UNDEF:
1213
 
  case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1214
 
    destination.append("NO ACTION");
1215
 
    break;
1216
 
  case Table::ForeignKeyConstraint::OPTION_SET_DEFAULT:
1217
 
    destination.append("SET DEFAULT");
1218
 
    break;
1219
 
  }
1220
 
}
1221
 
 
1222
 
enum TransformSqlError
1223
 
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
1224
 
                                             const Table &,
1225
 
                                             string &destination,
1226
 
                                             enum TransformSqlVariant sql_variant)
1227
 
{
1228
 
  char quoted_identifier= '`';
1229
 
  if (sql_variant == ANSI)
1230
 
    quoted_identifier= '"';
1231
 
 
1232
 
  destination.append("  ", 2);
1233
 
 
1234
 
  if (fkey.has_name())
1235
 
  {
1236
 
    destination.append("CONSTRAINT ", 11);
1237
 
    append_escaped_string(&destination, fkey.name(), quoted_identifier);
1238
 
    destination.append(" ", 1);
1239
 
  }
1240
 
 
1241
 
  destination.append("FOREIGN KEY (", 13);
1242
 
 
1243
 
  for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1244
 
  {
1245
 
    if (x != 0)
1246
 
      destination.append(", ");
1247
 
 
1248
 
    append_escaped_string(&destination, fkey.column_names(x),
1249
 
                          quoted_identifier);
1250
 
  }
1251
 
 
1252
 
  destination.append(") REFERENCES ", 13);
1253
 
 
1254
 
  append_escaped_string(&destination, fkey.references_table_name(),
1255
 
                        quoted_identifier);
1256
 
  destination.append(" (", 2);
1257
 
 
1258
 
  for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1259
 
  {
1260
 
    if (x != 0)
1261
 
      destination.append(", ");
1262
 
 
1263
 
    append_escaped_string(&destination, fkey.references_columns(x),
1264
 
                          quoted_identifier);
1265
 
  }
1266
 
 
1267
 
  destination.push_back(')');
1268
 
 
1269
 
  if (fkey.has_update_option() and fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1270
 
  {
1271
 
    destination.append(" ON UPDATE ", 11);
1272
 
    transformForeignKeyOptionToSql(fkey.update_option(), destination);
1273
 
  }
1274
 
 
1275
 
  if (fkey.has_delete_option() and fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1276
 
  {
1277
 
    destination.append(" ON DELETE ", 11);
1278
 
    transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1279
 
  }
1280
 
 
1281
1064
  return NONE;
1282
1065
}
1283
1066
 
1287
1070
                              enum TransformSqlVariant sql_variant)
1288
1071
{
1289
1072
  char quoted_identifier= '`';
1290
 
  char quoted_default;
1291
 
 
1292
1073
  if (sql_variant == ANSI)
1293
1074
    quoted_identifier= '"';
1294
1075
 
1295
 
  if (sql_variant == DRIZZLE)
1296
 
    quoted_default= '\'';
1297
 
  else
1298
 
    quoted_default= quoted_identifier;
1299
 
 
1300
 
  append_escaped_string(&destination, field.name(), quoted_identifier);
 
1076
  destination.push_back(quoted_identifier);
 
1077
  destination.append(field.name());
 
1078
  destination.push_back(quoted_identifier);
1301
1079
 
1302
1080
  Table::Field::FieldType field_type= field.type();
1303
1081
 
1305
1083
  {
1306
1084
    case Table::Field::DOUBLE:
1307
1085
    destination.append(" DOUBLE", 7);
1308
 
    if (field.has_numeric_options()
1309
 
        && field.numeric_options().has_precision())
1310
 
    {
1311
 
      stringstream ss;
1312
 
      ss << "(" << field.numeric_options().precision() << ",";
1313
 
      ss << field.numeric_options().scale() << ")";
1314
 
      destination.append(ss.str());
1315
 
    }
1316
1086
    break;
1317
1087
  case Table::Field::VARCHAR:
1318
1088
    {
1319
 
      if (field.string_options().has_collation()
1320
 
          && field.string_options().collation().compare("binary") == 0)
1321
 
        destination.append(" VARBINARY(", 11);
1322
 
      else
1323
 
        destination.append(" VARCHAR(", 9);
1324
 
 
1325
 
      destination.append(boost::lexical_cast<string>(field.string_options().length()));
1326
 
      destination.append(")");
 
1089
      destination.append(" VARCHAR(", 9);
 
1090
      stringstream ss;
 
1091
      ss << field.string_options().length() << ")";
 
1092
      destination.append(ss.str());
1327
1093
    }
1328
1094
    break;
1329
1095
  case Table::Field::BLOB:
1330
 
    {
1331
 
      if (field.string_options().has_collation()
1332
 
          && field.string_options().collation().compare("binary") == 0)
1333
 
        destination.append(" BLOB", 5);
1334
 
      else
1335
 
        destination.append(" TEXT", 5);
1336
 
    }
 
1096
    destination.append(" BLOB", 5);
1337
1097
    break;
1338
1098
  case Table::Field::ENUM:
1339
1099
    {
1353
1113
      destination.push_back(')');
1354
1114
      break;
1355
1115
    }
1356
 
  case Table::Field::UUID:
1357
 
    destination.append(" UUID", 5);
1358
 
    break;
1359
1116
  case Table::Field::INTEGER:
1360
1117
    destination.append(" INT", 4);
1361
1118
    break;
1393
1150
    }
1394
1151
  }
1395
1152
 
 
1153
 
 
1154
  if (! (field.has_constraints() &&
 
1155
         field.constraints().is_nullable()))
 
1156
  {
 
1157
    destination.append(" NOT", 4);
 
1158
  }
 
1159
  destination.append(" NULL", 5);
 
1160
 
 
1161
  if (field.type() == Table::Field::INTEGER || 
 
1162
      field.type() == Table::Field::BIGINT)
 
1163
  {
 
1164
    /* AUTO_INCREMENT must be after NOT NULL */
 
1165
    if (field.has_numeric_options() &&
 
1166
        field.numeric_options().is_autoincrement())
 
1167
    {
 
1168
      destination.append(" AUTO_INCREMENT", 15);
 
1169
    }
 
1170
  }
 
1171
 
1396
1172
  if (field.type() == Table::Field::BLOB ||
1397
1173
      field.type() == Table::Field::VARCHAR)
1398
1174
  {
1399
 
    if (field.string_options().has_collation()
1400
 
        && field.string_options().collation().compare("binary"))
 
1175
    if (field.string_options().has_collation())
1401
1176
    {
1402
1177
      destination.append(" COLLATE ", 9);
1403
1178
      destination.append(field.string_options().collation());
1404
1179
    }
1405
1180
  }
1406
1181
 
1407
 
  if (field.has_constraints() &&
1408
 
      ! field.constraints().is_nullable())
1409
 
  {
1410
 
    destination.append(" NOT NULL", 9);
1411
 
  }
1412
 
  else if (field.type() == Table::Field::TIMESTAMP)
1413
 
    destination.append(" NULL", 5);
1414
 
 
1415
 
  if (field.type() == Table::Field::INTEGER || 
1416
 
      field.type() == Table::Field::BIGINT)
1417
 
  {
1418
 
    /* AUTO_INCREMENT must be after NOT NULL */
1419
 
    if (field.has_numeric_options() &&
1420
 
        field.numeric_options().is_autoincrement())
1421
 
    {
1422
 
      destination.append(" AUTO_INCREMENT", 15);
1423
 
    }
1424
 
  }
1425
 
 
1426
1182
  if (field.options().has_default_value())
1427
1183
  {
1428
1184
    destination.append(" DEFAULT ", 9);
1429
 
    append_escaped_string(&destination, field.options().default_value());
1430
 
  }
1431
 
  else if (field.options().has_default_expression())
1432
 
  {
1433
 
    destination.append(" DEFAULT ", 9);
1434
 
    destination.append(field.options().default_expression());
1435
 
  }
1436
 
  else if (field.options().has_default_bin_value())
 
1185
    destination.push_back(quoted_identifier);
 
1186
    destination.append(field.options().default_value());
 
1187
    destination.push_back(quoted_identifier);
 
1188
  }
 
1189
 
 
1190
  if (field.options().has_default_bin_value())
1437
1191
  {
1438
1192
    const string &v= field.options().default_bin_value();
1439
 
    if (v.length() == 0)
1440
 
      destination.append(" DEFAULT ''", 11);
1441
 
    else
 
1193
    destination.append(" DEFAULT 0x", 11);
 
1194
    for (size_t x= 0; x < v.length(); x++)
1442
1195
    {
1443
 
      destination.append(" DEFAULT 0x", 11);
1444
 
      for (size_t x= 0; x < v.length(); x++)
1445
 
      {
1446
 
        char hex[3];
1447
 
        snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
1448
 
        destination.append(hex, 2);
1449
 
      }
 
1196
      printf("%.2x", *(v.c_str() + x));
1450
1197
    }
1451
1198
  }
1452
 
  else if (field.options().has_default_null()
1453
 
           && field.options().default_null()
1454
 
           && field.type() != Table::Field::BLOB)
1455
 
  {
1456
 
    destination.append(" DEFAULT NULL", 13);
1457
 
  }
1458
1199
 
1459
 
  if (field.has_options() && field.options().has_update_expression())
1460
 
  {
1461
 
    destination.append(" ON UPDATE ", 11);
1462
 
    destination.append(field.options().update_expression());
1463
 
  }
 
1200
  if (field.type() == Table::Field::TIMESTAMP)
 
1201
    if (field.timestamp_options().has_auto_updates() &&
 
1202
        field.timestamp_options().auto_updates())
 
1203
      destination.append(" ON UPDATE CURRENT_TIMESTAMP", 28);
1464
1204
 
1465
1205
  if (field.has_comment())
1466
1206
  {
1467
1207
    destination.append(" COMMENT ", 9);
1468
 
    append_escaped_string(&destination, field.comment(), quoted_default);
 
1208
    destination.push_back(quoted_identifier);
 
1209
    destination.append(field.comment());
 
1210
    destination.push_back(quoted_identifier);
1469
1211
  }
1470
1212
  return NONE;
1471
1213
}
1478
1220
  case Table::Field::DECIMAL:
1479
1221
  case Table::Field::INTEGER:
1480
1222
  case Table::Field::BIGINT:
 
1223
  case Table::Field::ENUM:
1481
1224
    return false;
1482
1225
  default:
1483
1226
    return true;
1510
1253
    return Table::Field::ENUM;
1511
1254
  case DRIZZLE_TYPE_BLOB:
1512
1255
    return Table::Field::BLOB;
1513
 
  case DRIZZLE_TYPE_UUID:
1514
 
    return Table::Field::UUID;
1515
1256
  }
1516
1257
 
1517
1258
  assert(false);