~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

  • Committer: Stewart Smith
  • Date: 2011-01-14 05:18:23 UTC
  • mto: (2086.1.3 build)
  • mto: This revision was merged to the branch mainline in revision 2087.
  • Revision ID: stewart@flamingspork.com-20110114051823-14fyn2kvg8pc5a15
\r and trailing whitespace removed.

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
5
 
 *  Copyright (c) 2010 Jay Pipes
 
4
 *  Copyright (C) 2009 Sun Microsystems, Inc.
 
5
 *  Copyright (C) 2010 Jay Pipes
6
6
 *
7
7
 *  Authors:
8
8
 *
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_STATEMENT:
 
131
    {
 
132
      break;
 
133
    }
 
134
  case Statement::ROLLBACK:
 
135
    {
 
136
      sql_strings.push_back("ROLLBACK");
 
137
      break;
 
138
    }
60
139
  case Statement::INSERT:
61
140
    {
62
141
      if (! source.has_insert_header())
322
401
 
323
402
    const FieldMetadata &field_metadata= header.field_metadata(x);
324
403
 
325
 
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
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
412
 
327
413
    if (should_quote_field_value)
328
414
      destination.push_back('\'');
329
415
 
330
 
    if (field_metadata.type() == Table::Field::BLOB)
 
416
    if (record.is_null(x))
331
417
    {
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());
 
418
      destination.append("NULL");
340
419
    }
341
420
    else
342
421
    {
343
 
      destination.append(record.insert_value(x));
 
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
439
    }
345
440
 
346
441
    if (should_quote_field_value)
403
498
      }
404
499
      else
405
500
      {
406
 
        destination.append(data.record(x).insert_value(y));
 
501
        string tmp(data.record(x).insert_value(y));
 
502
        escapeEmbeddedQuotes(tmp);
 
503
        destination.append(tmp);
407
504
      }
408
505
 
409
506
      if (should_quote_field_value)
467
564
    destination.push_back(quoted_identifier);
468
565
    destination.push_back('=');
469
566
 
470
 
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
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
575
 
472
576
    if (should_quote_field_value)
473
577
      destination.push_back('\'');
474
578
 
475
 
    if (field_metadata.type() == Table::Field::BLOB)
 
579
    if (record.is_null(x))
476
580
    {
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());
 
581
      destination.append("NULL");
485
582
    }
486
 
    else
 
583
    else 
487
584
    {
488
 
      destination.append(record.after_value(x));
 
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
602
    }
490
603
 
491
604
    if (should_quote_field_value)
607
720
    }
608
721
    else
609
722
    {
610
 
      destination.append(record.key_value(x));
 
723
      string tmp(record.key_value(x));
 
724
      escapeEmbeddedQuotes(tmp);
 
725
      destination.append(tmp);
611
726
    }
612
727
 
613
728
    if (should_quote_field_value)
676
791
      }
677
792
      else
678
793
      {
679
 
        destination.append(data.record(x).key_value(y));
 
794
        string tmp(data.record(x).key_value(y));
 
795
        escapeEmbeddedQuotes(tmp);
 
796
        destination.append(tmp);
680
797
      }
681
798
 
682
799
      if (should_quote_field_value)
833
950
  destination.append("TABLE ", 6);
834
951
  if (with_schema)
835
952
  {
836
 
    destination.push_back(quoted_identifier);
837
 
    destination.append(table.schema());
838
 
    destination.push_back(quoted_identifier);
 
953
    append_escaped_string(&destination, table.schema(), quoted_identifier);
839
954
    destination.push_back('.');
840
955
  }
841
 
  destination.push_back(quoted_identifier);
842
 
  destination.append(table.name());
843
 
  destination.push_back(quoted_identifier);
 
956
  append_escaped_string(&destination, table.name(), quoted_identifier);
844
957
  destination.append(" (\n", 3);
845
958
 
846
959
  enum TransformSqlError result= NONE;
852
965
    if (x != 0)
853
966
      destination.append(",\n", 2);
854
967
 
 
968
    destination.append("  ");
 
969
 
855
970
    result= transformFieldDefinitionToSql(field, destination, sql_variant);
856
 
    
 
971
 
857
972
    if (result != NONE)
858
973
      return result;
859
974
  }
875
990
    if (result != NONE)
876
991
      return result;
877
992
  }
 
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
 
878
1012
  destination.append("\n)", 2);
879
1013
 
880
1014
  /* Add ENGINE = " clause */
881
1015
  if (table.has_engine())
882
1016
  {
883
 
    const Table::StorageEngine &engine= table.engine();
884
 
    destination.append("\nENGINE = ", 10);
885
 
    destination.append(engine.name());
 
1017
    destination.append(" ENGINE=", 8);
 
1018
    destination.append(table.engine().name());
886
1019
 
887
 
    size_t num_engine_options= engine.option_size();
 
1020
    size_t num_engine_options= table.engine().options_size();
 
1021
    if (num_engine_options > 0)
 
1022
      destination.append(" ", 1);
888
1023
    for (size_t x= 0; x < num_engine_options; ++x)
889
1024
    {
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');
 
1025
      const Engine::Option &option= table.engine().options(x);
 
1026
      destination.append(option.name());
 
1027
      destination.append("='", 2);
 
1028
      destination.append(option.state());
 
1029
      destination.append("'", 1);
 
1030
      if(x != num_engine_options-1)
 
1031
        destination.append(", ", 2);
896
1032
    }
897
1033
  }
898
1034
 
910
1046
  if (sql_variant == ANSI)
911
1047
    return NONE; /* ANSI does not support table options... */
912
1048
 
913
 
  stringstream ss;
914
 
 
915
1049
  if (options.has_comment())
916
1050
  {
917
 
    destination.append("\nCOMMENT = '", 12);
918
 
    destination.append(options.comment());
919
 
    destination.push_back('\'');
 
1051
    destination.append(" COMMENT=", 9);
 
1052
    append_escaped_string(&destination, options.comment());
920
1053
  }
921
1054
 
922
1055
  if (options.has_collation())
923
1056
  {
924
 
    destination.append("\nCOLLATE = ", 11);
 
1057
    destination.append(" COLLATE = ", 11);
925
1058
    destination.append(options.collation());
926
1059
  }
927
1060
 
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
1061
  if (options.has_data_file_name())
945
1062
  {
946
1063
    destination.append("\nDATA_FILE_NAME = '", 19);
957
1074
 
958
1075
  if (options.has_max_rows())
959
1076
  {
960
 
    ss << options.max_rows();
961
1077
    destination.append("\nMAX_ROWS = ", 12);
962
 
    destination.append(ss.str());
963
 
    ss.clear();
 
1078
    destination.append(boost::lexical_cast<string>(options.max_rows()));
964
1079
  }
965
1080
 
966
1081
  if (options.has_min_rows())
967
1082
  {
968
 
    ss << options.min_rows();
969
1083
    destination.append("\nMIN_ROWS = ", 12);
970
 
    destination.append(ss.str());
971
 
    ss.clear();
 
1084
    destination.append(boost::lexical_cast<string>(options.min_rows()));
972
1085
  }
973
1086
 
974
 
  if (options.has_auto_increment_value())
 
1087
  if (options.has_user_set_auto_increment_value()
 
1088
      && options.has_auto_increment_value())
975
1089
  {
976
 
    ss << options.auto_increment_value();
977
 
    destination.append("\nAUTO_INCREMENT = ", 18);
978
 
    destination.append(ss.str());
979
 
    ss.clear();
 
1090
    destination.append(" AUTO_INCREMENT=", 16);
 
1091
    destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
980
1092
  }
981
1093
 
982
1094
  if (options.has_avg_row_length())
983
1095
  {
984
 
    ss << options.avg_row_length();
985
1096
    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);
 
1097
    destination.append(boost::lexical_cast<string>(options.avg_row_length()));
 
1098
  }
 
1099
 
1012
1100
  if (options.has_checksum() &&
1013
1101
      options.checksum())
1014
1102
    destination.append("\nCHECKSUM = TRUE", 16);
1029
1117
  if (sql_variant == ANSI)
1030
1118
    quoted_identifier= '"';
1031
1119
 
 
1120
  destination.append("  ", 2);
 
1121
 
1032
1122
  if (index.is_primary())
1033
1123
    destination.append("PRIMARY ", 8);
1034
1124
  else if (index.is_unique())
1035
1125
    destination.append("UNIQUE ", 7);
1036
1126
 
1037
1127
  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
 
  
 
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
 
1043
1138
  size_t num_parts= index.index_part_size();
1044
1139
  for (size_t x= 0; x < num_parts; ++x)
1045
1140
  {
1063
1158
    {
1064
1159
      if (part.has_compare_length())
1065
1160
      {
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())
 
1161
        if (part.compare_length() != field.string_options().length())
1074
1162
        {
1075
 
          stringstream ss;
1076
1163
          destination.push_back('(');
1077
 
          ss << compare_length_in_chars;
1078
 
          destination.append(ss.str());
 
1164
          destination.append(boost::lexical_cast<string>(part.compare_length()));
1079
1165
          destination.push_back(')');
1080
1166
        }
1081
1167
      }
1083
1169
  }
1084
1170
  destination.push_back(')');
1085
1171
 
 
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
 
1086
1281
  return NONE;
1087
1282
}
1088
1283
 
1092
1287
                              enum TransformSqlVariant sql_variant)
1093
1288
{
1094
1289
  char quoted_identifier= '`';
 
1290
  char quoted_default;
 
1291
 
1095
1292
  if (sql_variant == ANSI)
1096
1293
    quoted_identifier= '"';
1097
1294
 
1098
 
  destination.push_back(quoted_identifier);
1099
 
  destination.append(field.name());
1100
 
  destination.push_back(quoted_identifier);
 
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);
1101
1301
 
1102
1302
  Table::Field::FieldType field_type= field.type();
1103
1303
 
1105
1305
  {
1106
1306
    case Table::Field::DOUBLE:
1107
1307
    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
    }
1108
1316
    break;
1109
1317
  case Table::Field::VARCHAR:
1110
1318
    {
1111
 
      destination.append(" VARCHAR(", 9);
1112
 
      stringstream ss;
1113
 
      ss << field.string_options().length() << ")";
1114
 
      destination.append(ss.str());
 
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(")");
1115
1327
    }
1116
1328
    break;
1117
1329
  case Table::Field::BLOB:
1118
 
    destination.append(" BLOB", 5);
 
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
    }
1119
1337
    break;
1120
1338
  case Table::Field::ENUM:
1121
1339
    {
1135
1353
      destination.push_back(')');
1136
1354
      break;
1137
1355
    }
 
1356
  case Table::Field::UUID:
 
1357
    destination.append(" UUID", 5);
 
1358
    break;
 
1359
  case Table::Field::BOOLEAN:
 
1360
    destination.append(" BOOLEAN", 8);
 
1361
    break;
1138
1362
  case Table::Field::INTEGER:
1139
1363
    destination.append(" INT", 4);
1140
1364
    break;
1153
1377
  case Table::Field::DATE:
1154
1378
    destination.append(" DATE", 5);
1155
1379
    break;
1156
 
  case Table::Field::TIMESTAMP:
1157
 
    destination.append(" TIMESTAMP",  10);
 
1380
 
 
1381
  case Table::Field::EPOCH:
 
1382
    if (field.time_options().microseconds())
 
1383
    {
 
1384
      destination.append(" TIMESTAMP(6)");
 
1385
    }
 
1386
    else
 
1387
    {
 
1388
      destination.append(" TIMESTAMP",  10);
 
1389
    }
1158
1390
    break;
 
1391
 
1159
1392
  case Table::Field::DATETIME:
1160
1393
    destination.append(" DATETIME",  9);
1161
1394
    break;
 
1395
  case Table::Field::TIME:
 
1396
    destination.append(" TIME",  5);
 
1397
    break;
1162
1398
  }
1163
1399
 
1164
1400
  if (field.type() == Table::Field::INTEGER || 
1172
1408
    }
1173
1409
  }
1174
1410
 
 
1411
  if (field.type() == Table::Field::BLOB ||
 
1412
      field.type() == Table::Field::VARCHAR)
 
1413
  {
 
1414
    if (field.string_options().has_collation()
 
1415
        && field.string_options().collation().compare("binary"))
 
1416
    {
 
1417
      destination.append(" COLLATE ", 9);
 
1418
      destination.append(field.string_options().collation());
 
1419
    }
 
1420
  }
1175
1421
 
1176
 
  if (! (field.has_constraints() &&
1177
 
         field.constraints().is_nullable()))
1178
 
  {
1179
 
    destination.append(" NOT", 4);
1180
 
  }
1181
 
  destination.append(" NULL", 5);
 
1422
  if (field.has_constraints() && field.constraints().is_notnull())
 
1423
  {
 
1424
    destination.append(" NOT NULL", 9);
 
1425
  }
 
1426
  else if (field.type() == Table::Field::EPOCH)
 
1427
  {
 
1428
    destination.append(" NULL", 5);
 
1429
  }
1182
1430
 
1183
1431
  if (field.type() == Table::Field::INTEGER || 
1184
1432
      field.type() == Table::Field::BIGINT)
1191
1439
    }
1192
1440
  }
1193
1441
 
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
1442
  if (field.options().has_default_value())
1205
1443
  {
1206
1444
    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())
 
1445
    append_escaped_string(&destination, field.options().default_value());
 
1446
  }
 
1447
  else if (field.options().has_default_expression())
 
1448
  {
 
1449
    destination.append(" DEFAULT ", 9);
 
1450
    destination.append(field.options().default_expression());
 
1451
  }
 
1452
  else if (field.options().has_default_bin_value())
1213
1453
  {
1214
1454
    const string &v= field.options().default_bin_value();
1215
 
    destination.append(" DEFAULT 0x", 11);
1216
 
    for (size_t x= 0; x < v.length(); x++)
 
1455
    if (v.length() == 0)
 
1456
      destination.append(" DEFAULT ''", 11);
 
1457
    else
1217
1458
    {
1218
 
      printf("%.2x", *(v.c_str() + x));
 
1459
      destination.append(" DEFAULT 0x", 11);
 
1460
      for (size_t x= 0; x < v.length(); x++)
 
1461
      {
 
1462
        char hex[3];
 
1463
        snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
 
1464
        destination.append(hex, 2);
 
1465
      }
1219
1466
    }
1220
1467
  }
 
1468
  else if (field.options().has_default_null()
 
1469
           && field.options().default_null()
 
1470
           && field.type() != Table::Field::BLOB)
 
1471
  {
 
1472
    destination.append(" DEFAULT NULL", 13);
 
1473
  }
1221
1474
 
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);
 
1475
  if (field.has_options() && field.options().has_update_expression())
 
1476
  {
 
1477
    destination.append(" ON UPDATE ", 11);
 
1478
    destination.append(field.options().update_expression());
 
1479
  }
1226
1480
 
1227
1481
  if (field.has_comment())
1228
1482
  {
1229
1483
    destination.append(" COMMENT ", 9);
1230
 
    destination.push_back(quoted_identifier);
1231
 
    destination.append(field.comment());
1232
 
    destination.push_back(quoted_identifier);
 
1484
    append_escaped_string(&destination, field.comment(), quoted_default);
1233
1485
  }
1234
1486
  return NONE;
1235
1487
}
1242
1494
  case Table::Field::DECIMAL:
1243
1495
  case Table::Field::INTEGER:
1244
1496
  case Table::Field::BIGINT:
1245
 
  case Table::Field::ENUM:
1246
1497
    return false;
1247
1498
  default:
1248
1499
    return true;
1259
1510
  case DRIZZLE_TYPE_NULL:
1260
1511
    assert(false); /* Not a user definable type */
1261
1512
    return Table::Field::INTEGER; /* unreachable */
 
1513
  case DRIZZLE_TYPE_MICROTIME:
1262
1514
  case DRIZZLE_TYPE_TIMESTAMP:
1263
 
    return Table::Field::TIMESTAMP;
 
1515
    return Table::Field::EPOCH;
1264
1516
  case DRIZZLE_TYPE_LONGLONG:
1265
1517
    return Table::Field::BIGINT;
1266
1518
  case DRIZZLE_TYPE_DATETIME:
1267
1519
    return Table::Field::DATETIME;
 
1520
  case DRIZZLE_TYPE_TIME:
 
1521
    return Table::Field::TIME;
1268
1522
  case DRIZZLE_TYPE_DATE:
1269
1523
    return Table::Field::DATE;
1270
1524
  case DRIZZLE_TYPE_VARCHAR:
1275
1529
    return Table::Field::ENUM;
1276
1530
  case DRIZZLE_TYPE_BLOB:
1277
1531
    return Table::Field::BLOB;
 
1532
  case DRIZZLE_TYPE_UUID:
 
1533
    return Table::Field::UUID;
 
1534
  case DRIZZLE_TYPE_BOOLEAN:
 
1535
    return Table::Field::BOOLEAN;
1278
1536
  }
1279
1537
 
1280
1538
  assert(false);