~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

  • Committer: Stewart Smith
  • Date: 2010-08-12 16:48:46 UTC
  • mto: This revision was merged to the branch mainline in revision 1707.
  • Revision ID: stewart@flamingspork.com-20100812164846-s9bhy47g60bvqs41
bug lp:611379 Equivalent queries with Impossible where return different results

The following two equivalent queries return different results in maria 5.2 and 5.3 (and identical results in mysql 5.5.5) :

SELECT SUM( DISTINCT table1 .`pk` ) FROM B table1 STRAIGHT_JOIN ( BB table2 JOIN CC ON table2 .`col_varchar_key` ) ON table2 .`pk` ;

SELECT * FROM ( SELECT SUM( DISTINCT table1 .`pk` ) FROM B table1 STRAIGHT_JOIN ( BB table2 JOIN CC ON table2 .`col_varchar_key` ) ON table2 .`pk` );

MariaDB returns 0 on the second query and NULL on the first, whereas MySQL returns NULL on both. In MariaDB, both EXPLAIN plans agree that "Impossible WHERE noticed after reading const tables"



We have some slightly different output in drizzle:

main.bug_lp611379 [ fail ]
drizzletest: At line 9: query 'explain select * from (select sum(distinct t1.a) from t1,t2 where t1.a=t2.a)
as t' failed: 1048: Column 'sum(distinct t1.a)' cannot be null

but the fix gets us the correct query results, although with slightly different execution plans.



This fix is directly ported from MariaDB.

Show diffs side-by-side

added added

removed removed

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