~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-10-02 14:17:48 UTC
  • mfrom: (1.1.1 upstream)
  • mto: (2.1.17 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20101002141748-m6vbfbfjhrw1153e
Tags: 2010.09.1802-1
* New upstream release.
* Removed pid-file argument hack.
* Updated GPL-2 address to be new address.
* Directly copy in drizzledump.1 since debian doesn't have sphinx 1.0 yet.
* Link to jquery from libjs-jquery. Add it as a depend.
* Add drizzled.8 symlink to the install files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
#include "drizzled/message/statement_transform.h"
35
35
#include "drizzled/message/transaction.pb.h"
36
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"
37
40
 
38
41
#include <string>
39
42
#include <vector>
40
43
#include <sstream>
 
44
#include <cstdio>
41
45
 
42
46
using namespace std;
43
47
 
47
51
namespace message
48
52
{
49
53
 
 
54
static void escapeEmbeddedQuotes(string &s, const char quote='\'')
 
55
{
 
56
  string::iterator it;
 
57
 
 
58
  for (it= s.begin(); it != s.end(); ++it)
 
59
  {
 
60
    if (*it == quote)
 
61
    {
 
62
      it= s.insert(it, quote);
 
63
      ++it;  // advance back to the quote
 
64
    }
 
65
  }
 
66
}
 
67
 
 
68
/* Incredibly similar to append_unescaped() in table.cc, but for std::string */
 
69
static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
 
70
{
 
71
  const char *pos= input.c_str();
 
72
  const char *end= input.c_str()+input.length();
 
73
  res->push_back(quote);
 
74
 
 
75
  for (; pos != end ; pos++)
 
76
  {
 
77
    uint32_t mblen;
 
78
    if (use_mb(default_charset_info) &&
 
79
        (mblen= my_ismbchar(default_charset_info, pos, end)))
 
80
    {
 
81
      res->append(pos, mblen);
 
82
      pos+= mblen - 1;
 
83
      if (pos >= end)
 
84
        break;
 
85
      continue;
 
86
    }
 
87
 
 
88
    switch (*pos) {
 
89
    case 0:                             /* Must be escaped for 'mysql' */
 
90
      res->push_back('\\');
 
91
      res->push_back('0');
 
92
      break;
 
93
    case '\n':                          /* Must be escaped for logs */
 
94
      res->push_back('\\');
 
95
      res->push_back('n');
 
96
      break;
 
97
    case '\r':
 
98
      res->push_back('\\');             /* This gives better readability */
 
99
      res->push_back('r');
 
100
      break;
 
101
    case '\\':
 
102
      res->push_back('\\');             /* Because of the sql syntax */
 
103
      res->push_back('\\');
 
104
      break;
 
105
    default:
 
106
      if (*pos == quote) /* SQL syntax for quoting a quote */
 
107
      {
 
108
        res->push_back(quote);
 
109
        res->push_back(quote);
 
110
      }
 
111
      else
 
112
        res->push_back(*pos);
 
113
      break;
 
114
    }
 
115
  }
 
116
  res->push_back(quote);
 
117
}
 
118
 
50
119
enum TransformSqlError
51
120
transformStatementToSql(const Statement &source,
52
121
                        vector<string> &sql_strings,
322
391
 
323
392
    const FieldMetadata &field_metadata= header.field_metadata(x);
324
393
 
325
 
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
394
    if (record.is_null(x))
 
395
    {
 
396
      should_quote_field_value= false;
 
397
    }
 
398
    else 
 
399
    {
 
400
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
401
    }
326
402
 
327
403
    if (should_quote_field_value)
328
404
      destination.push_back('\'');
329
405
 
330
 
    if (field_metadata.type() == Table::Field::BLOB)
 
406
    if (record.is_null(x))
331
407
    {
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());
 
408
      destination.append("NULL");
340
409
    }
341
410
    else
342
411
    {
343
 
      destination.append(record.insert_value(x));
 
412
      if (field_metadata.type() == Table::Field::BLOB)
 
413
      {
 
414
        /*
 
415
         * We do this here because BLOB data is returned
 
416
         * in a string correctly, but calling append()
 
417
         * without a length will result in only the string
 
418
         * up to a \0 being output here.
 
419
         */
 
420
        string raw_data(record.insert_value(x));
 
421
        destination.append(raw_data.c_str(), raw_data.size());
 
422
      }
 
423
      else
 
424
      {
 
425
        string tmp(record.insert_value(x));
 
426
        escapeEmbeddedQuotes(tmp);
 
427
        destination.append(tmp);
 
428
      }
344
429
    }
345
430
 
346
431
    if (should_quote_field_value)
403
488
      }
404
489
      else
405
490
      {
406
 
        destination.append(data.record(x).insert_value(y));
 
491
        string tmp(data.record(x).insert_value(y));
 
492
        escapeEmbeddedQuotes(tmp);
 
493
        destination.append(tmp);
407
494
      }
408
495
 
409
496
      if (should_quote_field_value)
467
554
    destination.push_back(quoted_identifier);
468
555
    destination.push_back('=');
469
556
 
470
 
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
557
    if (record.is_null(x))
 
558
    {
 
559
      should_quote_field_value= false;
 
560
    }
 
561
    else 
 
562
    {
 
563
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
 
564
    }    
471
565
 
472
566
    if (should_quote_field_value)
473
567
      destination.push_back('\'');
474
568
 
475
 
    if (field_metadata.type() == Table::Field::BLOB)
 
569
    if (record.is_null(x))
476
570
    {
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());
 
571
      destination.append("NULL");
485
572
    }
486
 
    else
 
573
    else 
487
574
    {
488
 
      destination.append(record.after_value(x));
 
575
      if (field_metadata.type() == Table::Field::BLOB)
 
576
      {
 
577
        /*
 
578
         * We do this here because BLOB data is returned
 
579
         * in a string correctly, but calling append()
 
580
         * without a length will result in only the string
 
581
         * up to a \0 being output here.
 
582
         */
 
583
        string raw_data(record.after_value(x));
 
584
        destination.append(raw_data.c_str(), raw_data.size());
 
585
      }
 
586
      else 
 
587
      {
 
588
        string tmp(record.after_value(x));
 
589
        escapeEmbeddedQuotes(tmp);
 
590
        destination.append(tmp);
 
591
      }
489
592
    }
490
593
 
491
594
    if (should_quote_field_value)
607
710
    }
608
711
    else
609
712
    {
610
 
      destination.append(record.key_value(x));
 
713
      string tmp(record.key_value(x));
 
714
      escapeEmbeddedQuotes(tmp);
 
715
      destination.append(tmp);
611
716
    }
612
717
 
613
718
    if (should_quote_field_value)
676
781
      }
677
782
      else
678
783
      {
679
 
        destination.append(data.record(x).key_value(y));
 
784
        string tmp(data.record(x).key_value(y));
 
785
        escapeEmbeddedQuotes(tmp);
 
786
        destination.append(tmp);
680
787
      }
681
788
 
682
789
      if (should_quote_field_value)
819
926
enum TransformSqlError
820
927
transformTableDefinitionToSql(const Table &table,
821
928
                              string &destination,
822
 
                              enum TransformSqlVariant sql_variant)
 
929
                              enum TransformSqlVariant sql_variant, bool with_schema)
823
930
{
824
931
  char quoted_identifier= '`';
825
932
  if (sql_variant == ANSI)
831
938
    destination.append("TEMPORARY ", 10);
832
939
  
833
940
  destination.append("TABLE ", 6);
834
 
  destination.push_back(quoted_identifier);
835
 
  destination.append(table.name());
836
 
  destination.push_back(quoted_identifier);
 
941
  if (with_schema)
 
942
  {
 
943
    append_escaped_string(&destination, table.schema(), quoted_identifier);
 
944
    destination.push_back('.');
 
945
  }
 
946
  append_escaped_string(&destination, table.name(), quoted_identifier);
837
947
  destination.append(" (\n", 3);
838
948
 
839
949
  enum TransformSqlError result= NONE;
845
955
    if (x != 0)
846
956
      destination.append(",\n", 2);
847
957
 
 
958
    destination.append("  ");
 
959
 
848
960
    result= transformFieldDefinitionToSql(field, destination, sql_variant);
849
 
    
 
961
 
850
962
    if (result != NONE)
851
963
      return result;
852
964
  }
868
980
    if (result != NONE)
869
981
      return result;
870
982
  }
 
983
 
 
984
  size_t num_foreign_keys= table.fk_constraint_size();
 
985
 
 
986
  if (num_foreign_keys > 0)
 
987
    destination.append(",\n", 2);
 
988
 
 
989
  for (size_t x= 0; x < num_foreign_keys; ++x)
 
990
  {
 
991
    const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
 
992
 
 
993
    if (x != 0)
 
994
      destination.append(",\n", 2);
 
995
 
 
996
    result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
 
997
 
 
998
    if (result != NONE)
 
999
      return result;
 
1000
  }
 
1001
 
871
1002
  destination.append("\n)", 2);
872
1003
 
873
1004
  /* Add ENGINE = " clause */
874
1005
  if (table.has_engine())
875
1006
  {
876
 
    const Table::StorageEngine &engine= table.engine();
877
 
    destination.append("\nENGINE = ", 10);
878
 
    destination.append(engine.name());
 
1007
    destination.append(" ENGINE=", 8);
 
1008
    destination.append(table.engine().name());
879
1009
 
880
 
    size_t num_engine_options= engine.option_size();
 
1010
    size_t num_engine_options= table.engine().options_size();
 
1011
    if (num_engine_options > 0)
 
1012
      destination.append(" ", 1);
881
1013
    for (size_t x= 0; x < num_engine_options; ++x)
882
1014
    {
883
 
      const Table::StorageEngine::EngineOption &option= engine.option(x);
884
 
      destination.push_back('\n');
885
 
      destination.append(option.option_name());
886
 
      destination.append(" = ", 3);
887
 
      destination.append(option.option_value());
888
 
      destination.push_back('\n');
 
1015
      const Engine::Option &option= table.engine().options(x);
 
1016
      destination.append(option.name());
 
1017
      destination.append("='", 2);
 
1018
      destination.append(option.state());
 
1019
      destination.append("'", 1);
 
1020
      if(x != num_engine_options-1)
 
1021
        destination.append(", ", 2);
889
1022
    }
890
1023
  }
891
1024
 
907
1040
 
908
1041
  if (options.has_comment())
909
1042
  {
910
 
    destination.append("\nCOMMENT = '", 12);
911
 
    destination.append(options.comment());
912
 
    destination.push_back('\'');
 
1043
    destination.append(" COMMENT=", 9);
 
1044
    append_escaped_string(&destination, options.comment());
913
1045
  }
914
1046
 
915
1047
  if (options.has_collation())
916
1048
  {
917
 
    destination.append("\nCOLLATE = ", 11);
 
1049
    destination.append(" COLLATE = ", 11);
918
1050
    destination.append(options.collation());
919
1051
  }
920
1052
 
921
 
  if (options.has_auto_increment())
922
 
  {
923
 
    ss << options.auto_increment();
924
 
    destination.append("\nAUTOINCREMENT_OFFSET = ", 24);
925
 
    destination.append(ss.str());
926
 
    ss.clear();
927
 
  }
928
 
  
929
 
  if (options.has_row_type())
930
 
  {
931
 
    ss << options.row_type();
932
 
    destination.append("\nROW_TYPE = ", 12);
933
 
    destination.append(ss.str());
934
 
    ss.clear();
935
 
  }
936
 
 
937
1053
  if (options.has_data_file_name())
938
1054
  {
939
1055
    destination.append("\nDATA_FILE_NAME = '", 19);
964
1080
    ss.clear();
965
1081
  }
966
1082
 
967
 
  if (options.has_auto_increment_value())
 
1083
  if (options.has_user_set_auto_increment_value()
 
1084
      && options.has_auto_increment_value())
968
1085
  {
969
1086
    ss << options.auto_increment_value();
970
 
    destination.append("\nAUTO_INCREMENT = ", 18);
 
1087
    destination.append(" AUTO_INCREMENT=", 16);
971
1088
    destination.append(ss.str());
972
1089
    ss.clear();
973
1090
  }
980
1097
    ss.clear();
981
1098
  }
982
1099
 
983
 
  if (options.has_key_block_size())
984
 
  {
985
 
    ss << options.key_block_size();
986
 
    destination.append("\nKEY_BLOCK_SIZE = ", 18);
987
 
    destination.append(ss.str());
988
 
    ss.clear();
989
 
  }
990
 
 
991
 
  if (options.has_block_size())
992
 
  {
993
 
    ss << options.block_size();
994
 
    destination.append("\nBLOCK_SIZE = ", 14);
995
 
    destination.append(ss.str());
996
 
    ss.clear();
997
 
  }
998
 
 
999
 
  if (options.has_pack_keys() &&
1000
 
      options.pack_keys())
1001
 
    destination.append("\nPACK_KEYS = TRUE", 17);
1002
 
  if (options.has_pack_record() &&
1003
 
      options.pack_record())
1004
 
    destination.append("\nPACK_RECORD = TRUE", 19);
1005
1100
  if (options.has_checksum() &&
1006
1101
      options.checksum())
1007
1102
    destination.append("\nCHECKSUM = TRUE", 16);
1022
1117
  if (sql_variant == ANSI)
1023
1118
    quoted_identifier= '"';
1024
1119
 
 
1120
  destination.append("  ", 2);
 
1121
 
1025
1122
  if (index.is_primary())
1026
1123
    destination.append("PRIMARY ", 8);
1027
1124
  else if (index.is_unique())
1028
1125
    destination.append("UNIQUE ", 7);
1029
1126
 
1030
1127
  destination.append("KEY ", 4);
1031
 
  destination.push_back(quoted_identifier);
1032
 
  destination.append(index.name());
1033
 
  destination.push_back(quoted_identifier);
1034
 
  destination.append(" (", 2);
1035
 
  
 
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
 
1036
1138
  size_t num_parts= index.index_part_size();
1037
1139
  for (size_t x= 0; x < num_parts; ++x)
1038
1140
  {
1056
1158
    {
1057
1159
      if (part.has_compare_length())
1058
1160
      {
1059
 
        size_t compare_length_in_chars= part.compare_length();
1060
 
        
1061
 
        /* hack: compare_length() is bytes, not chars, but
1062
 
         * only for VARCHAR. Ass. */
1063
 
        if (field.type() == Table::Field::VARCHAR)
1064
 
          compare_length_in_chars/= 4;
1065
 
 
1066
 
        if (compare_length_in_chars != field.string_options().length())
 
1161
        if (part.compare_length() != field.string_options().length())
1067
1162
        {
1068
1163
          stringstream ss;
1069
1164
          destination.push_back('(');
1070
 
          ss << compare_length_in_chars;
 
1165
          ss << part.compare_length();
1071
1166
          destination.append(ss.str());
1072
1167
          destination.push_back(')');
1073
1168
        }
1076
1171
  }
1077
1172
  destination.push_back(')');
1078
1173
 
 
1174
  switch (index.type())
 
1175
  {
 
1176
  case Table::Index::UNKNOWN_INDEX:
 
1177
    break;
 
1178
  case Table::Index::BTREE:
 
1179
    destination.append(" USING BTREE", 12);
 
1180
    break;
 
1181
  case Table::Index::RTREE:
 
1182
    destination.append(" USING RTREE", 12);
 
1183
    break;
 
1184
  case Table::Index::HASH:
 
1185
    destination.append(" USING HASH", 11);
 
1186
    break;
 
1187
  case Table::Index::FULLTEXT:
 
1188
    destination.append(" USING FULLTEXT", 15);
 
1189
    break;
 
1190
  }
 
1191
 
 
1192
  if (index.has_comment())
 
1193
  {
 
1194
    destination.append(" COMMENT ", 9);
 
1195
    append_escaped_string(&destination, index.comment());
 
1196
  }
 
1197
 
 
1198
  return NONE;
 
1199
}
 
1200
 
 
1201
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
 
1202
{
 
1203
  switch (opt)
 
1204
  {
 
1205
  case Table::ForeignKeyConstraint::OPTION_UNDEF:
 
1206
    break;
 
1207
  case Table::ForeignKeyConstraint::OPTION_RESTRICT:
 
1208
    destination.append("RESTRICT");
 
1209
    break;
 
1210
  case Table::ForeignKeyConstraint::OPTION_CASCADE:
 
1211
    destination.append("CASCADE");
 
1212
    break;
 
1213
  case Table::ForeignKeyConstraint::OPTION_SET_NULL:
 
1214
    destination.append("SET NULL");
 
1215
    break;
 
1216
  case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
 
1217
    destination.append("NO ACTION");
 
1218
    break;
 
1219
  case Table::ForeignKeyConstraint::OPTION_DEFAULT:
 
1220
    destination.append("SET DEFAULT");
 
1221
    break;
 
1222
  }
 
1223
}
 
1224
 
 
1225
enum TransformSqlError
 
1226
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
 
1227
                                             const Table &,
 
1228
                                             string &destination,
 
1229
                                             enum TransformSqlVariant sql_variant)
 
1230
{
 
1231
  char quoted_identifier= '`';
 
1232
  if (sql_variant == ANSI)
 
1233
    quoted_identifier= '"';
 
1234
 
 
1235
  destination.append("  ", 2);
 
1236
 
 
1237
  if (fkey.has_name())
 
1238
  {
 
1239
    destination.append("CONSTRAINT ", 11);
 
1240
    append_escaped_string(&destination, fkey.name(), quoted_identifier);
 
1241
    destination.append(" ", 1);
 
1242
  }
 
1243
 
 
1244
  destination.append("FOREIGN KEY (", 13);
 
1245
 
 
1246
  for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
 
1247
  {
 
1248
    if (x != 0)
 
1249
      destination.append(", ");
 
1250
 
 
1251
    append_escaped_string(&destination, fkey.column_names(x),
 
1252
                          quoted_identifier);
 
1253
  }
 
1254
 
 
1255
  destination.append(") REFERENCES ", 13);
 
1256
 
 
1257
  append_escaped_string(&destination, fkey.references_table_name(),
 
1258
                        quoted_identifier);
 
1259
  destination.append(" (", 2);
 
1260
 
 
1261
  for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
 
1262
  {
 
1263
    if (x != 0)
 
1264
      destination.append(", ");
 
1265
 
 
1266
    append_escaped_string(&destination, fkey.references_columns(x),
 
1267
                          quoted_identifier);
 
1268
  }
 
1269
 
 
1270
  destination.push_back(')');
 
1271
 
 
1272
  if (fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
 
1273
  {
 
1274
    destination.append(" ON UPDATE ", 11);
 
1275
    transformForeignKeyOptionToSql(fkey.update_option(), destination);
 
1276
  }
 
1277
 
 
1278
  if (fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
 
1279
  {
 
1280
    destination.append(" ON DELETE ", 11);
 
1281
    transformForeignKeyOptionToSql(fkey.delete_option(), destination);
 
1282
  }
 
1283
 
1079
1284
  return NONE;
1080
1285
}
1081
1286
 
1085
1290
                              enum TransformSqlVariant sql_variant)
1086
1291
{
1087
1292
  char quoted_identifier= '`';
 
1293
  char quoted_default;
 
1294
 
1088
1295
  if (sql_variant == ANSI)
1089
1296
    quoted_identifier= '"';
1090
1297
 
1091
 
  destination.push_back(quoted_identifier);
1092
 
  destination.append(field.name());
1093
 
  destination.push_back(quoted_identifier);
 
1298
  if (sql_variant == DRIZZLE)
 
1299
    quoted_default= '\'';
 
1300
  else
 
1301
    quoted_default= quoted_identifier;
 
1302
 
 
1303
  append_escaped_string(&destination, field.name(), quoted_identifier);
1094
1304
 
1095
1305
  Table::Field::FieldType field_type= field.type();
1096
1306
 
1098
1308
  {
1099
1309
    case Table::Field::DOUBLE:
1100
1310
    destination.append(" DOUBLE", 7);
 
1311
    if (field.has_numeric_options()
 
1312
        && field.numeric_options().has_precision())
 
1313
    {
 
1314
      stringstream ss;
 
1315
      ss << "(" << field.numeric_options().precision() << ",";
 
1316
      ss << field.numeric_options().scale() << ")";
 
1317
      destination.append(ss.str());
 
1318
    }
1101
1319
    break;
1102
1320
  case Table::Field::VARCHAR:
1103
1321
    {
1104
 
      destination.append(" VARCHAR(", 9);
 
1322
      if (field.string_options().has_collation()
 
1323
          && field.string_options().collation().compare("binary") == 0)
 
1324
        destination.append(" VARBINARY(", 11);
 
1325
      else
 
1326
        destination.append(" VARCHAR(", 9);
 
1327
 
1105
1328
      stringstream ss;
1106
1329
      ss << field.string_options().length() << ")";
1107
1330
      destination.append(ss.str());
1108
1331
    }
1109
1332
    break;
1110
1333
  case Table::Field::BLOB:
1111
 
    destination.append(" BLOB", 5);
 
1334
    {
 
1335
      if (field.string_options().has_collation()
 
1336
          && field.string_options().collation().compare("binary") == 0)
 
1337
        destination.append(" BLOB", 5);
 
1338
      else
 
1339
        destination.append(" TEXT", 5);
 
1340
    }
1112
1341
    break;
1113
1342
  case Table::Field::ENUM:
1114
1343
    {
1115
 
      size_t num_field_values= field.set_options().field_value_size();
 
1344
      size_t num_field_values= field.enumeration_values().field_value_size();
1116
1345
      destination.append(" ENUM(", 6);
1117
1346
      for (size_t x= 0; x < num_field_values; ++x)
1118
1347
      {
1119
 
        const string &type= field.set_options().field_value(x);
 
1348
        const string &type= field.enumeration_values().field_value(x);
1120
1349
 
1121
1350
        if (x != 0)
1122
1351
          destination.push_back(',');
1165
1394
    }
1166
1395
  }
1167
1396
 
 
1397
  if (field.type() == Table::Field::BLOB ||
 
1398
      field.type() == Table::Field::VARCHAR)
 
1399
  {
 
1400
    if (field.string_options().has_collation()
 
1401
        && field.string_options().collation().compare("binary"))
 
1402
    {
 
1403
      destination.append(" COLLATE ", 9);
 
1404
      destination.append(field.string_options().collation());
 
1405
    }
 
1406
  }
1168
1407
 
1169
 
  if (! (field.has_constraints() &&
1170
 
         field.constraints().is_nullable()))
 
1408
  if (field.has_constraints() &&
 
1409
      ! field.constraints().is_nullable())
1171
1410
  {
1172
 
    destination.append(" NOT", 4);
 
1411
    destination.append(" NOT NULL", 9);
1173
1412
  }
1174
 
  destination.append(" NULL", 5);
 
1413
  else if (field.type() == Table::Field::TIMESTAMP)
 
1414
    destination.append(" NULL", 5);
1175
1415
 
1176
1416
  if (field.type() == Table::Field::INTEGER || 
1177
1417
      field.type() == Table::Field::BIGINT)
1184
1424
    }
1185
1425
  }
1186
1426
 
1187
 
  if (field.type() == Table::Field::BLOB ||
1188
 
      field.type() == Table::Field::VARCHAR)
1189
 
  {
1190
 
    if (field.string_options().has_collation())
1191
 
    {
1192
 
      destination.append(" COLLATE ", 9);
1193
 
      destination.append(field.string_options().collation());
1194
 
    }
1195
 
  }
1196
 
 
1197
1427
  if (field.options().has_default_value())
1198
1428
  {
1199
1429
    destination.append(" DEFAULT ", 9);
1200
 
    destination.push_back(quoted_identifier);
1201
 
    destination.append(field.options().default_value());
1202
 
    destination.push_back(quoted_identifier);
1203
 
  }
1204
 
 
1205
 
  if (field.options().has_default_bin_value())
 
1430
    append_escaped_string(&destination, field.options().default_value());
 
1431
  }
 
1432
  else if (field.options().has_default_expression())
 
1433
  {
 
1434
    destination.append(" DEFAULT ", 9);
 
1435
    destination.append(field.options().default_expression());
 
1436
  }
 
1437
  else if (field.options().has_default_bin_value())
1206
1438
  {
1207
1439
    const string &v= field.options().default_bin_value();
1208
 
    destination.append(" DEFAULT 0x", 11);
1209
 
    for (size_t x= 0; x < v.length(); x++)
 
1440
    if (v.length() == 0)
 
1441
      destination.append(" DEFAULT ''", 11);
 
1442
    else
1210
1443
    {
1211
 
      printf("%.2x", *(v.c_str() + x));
 
1444
      destination.append(" DEFAULT 0x", 11);
 
1445
      for (size_t x= 0; x < v.length(); x++)
 
1446
      {
 
1447
        char hex[3];
 
1448
        snprintf(hex, sizeof(hex), "%.2X", *(v.c_str() + x));
 
1449
        destination.append(hex, 2);
 
1450
      }
1212
1451
    }
1213
1452
  }
 
1453
  else if (field.options().has_default_null()
 
1454
           && field.options().default_null()
 
1455
           && field.type() != Table::Field::BLOB)
 
1456
  {
 
1457
    destination.append(" DEFAULT NULL", 13);
 
1458
  }
1214
1459
 
1215
 
  if (field.type() == Table::Field::TIMESTAMP)
1216
 
    if (field.timestamp_options().has_auto_updates() &&
1217
 
        field.timestamp_options().auto_updates())
1218
 
      destination.append(" ON UPDATE CURRENT_TIMESTAMP", 28);
 
1460
  if (field.has_options() && field.options().has_update_expression())
 
1461
  {
 
1462
    destination.append(" ON UPDATE ", 11);
 
1463
    destination.append(field.options().update_expression());
 
1464
  }
1219
1465
 
1220
1466
  if (field.has_comment())
1221
1467
  {
1222
1468
    destination.append(" COMMENT ", 9);
1223
 
    destination.push_back(quoted_identifier);
1224
 
    destination.append(field.comment());
1225
 
    destination.push_back(quoted_identifier);
 
1469
    append_escaped_string(&destination, field.comment(), quoted_default);
1226
1470
  }
1227
1471
  return NONE;
1228
1472
}
1235
1479
  case Table::Field::DECIMAL:
1236
1480
  case Table::Field::INTEGER:
1237
1481
  case Table::Field::BIGINT:
1238
 
  case Table::Field::ENUM:
1239
1482
    return false;
1240
1483
  default:
1241
1484
    return true;
1274
1517
  return Table::Field::INTEGER; /* unreachable */
1275
1518
}
1276
1519
 
 
1520
bool transactionContainsBulkSegment(const Transaction &transaction)
 
1521
{
 
1522
  size_t num_statements= transaction.statement_size();
 
1523
  if (num_statements == 0)
 
1524
    return false;
 
1525
 
 
1526
  /*
 
1527
   * Only INSERT, UPDATE, and DELETE statements can possibly
 
1528
   * have bulk segments.  So, we loop through the statements
 
1529
   * checking for segment_id > 1 in those specific submessages.
 
1530
   */
 
1531
  size_t x;
 
1532
  for (x= 0; x < num_statements; ++x)
 
1533
  {
 
1534
    const Statement &statement= transaction.statement(x);
 
1535
    Statement::Type type= statement.type();
 
1536
 
 
1537
    switch (type)
 
1538
    {
 
1539
      case Statement::INSERT:
 
1540
        if (statement.insert_data().segment_id() > 1)
 
1541
          return true;
 
1542
        break;
 
1543
      case Statement::UPDATE:
 
1544
        if (statement.update_data().segment_id() > 1)
 
1545
          return true;
 
1546
        break;
 
1547
      case Statement::DELETE:
 
1548
        if (statement.delete_data().segment_id() > 1)
 
1549
          return true;
 
1550
        break;
 
1551
      default:
 
1552
        break;
 
1553
    }
 
1554
  }
 
1555
  return false;
 
1556
}
 
1557
 
1277
1558
} /* namespace message */
1278
1559
} /* namespace drizzled */