~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

  • Committer: Brian Aker
  • Date: 2010-11-08 18:24:58 UTC
  • mto: (1921.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 1916.
  • Revision ID: brian@tangent.org-20101108182458-twv4hyix43ojno80
Merge in changes such that lock is now broken out into its own directory.

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