~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/message/statement_transform.cc

  • Committer: Monty Taylor
  • Date: 2010-05-12 05:00:55 UTC
  • mto: (1527.1.5 staging)
  • mto: This revision was merged to the branch mainline in revision 1529.
  • Revision ID: mordred@inaugust.com-20100512050055-i0kvg8xpr9dupz54
Wrap the libraries in if BUILD_*_PLUGIN so that they don't build when we're
disabling.

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"
41
37
 
42
38
#include <string>
43
39
#include <vector>
52
48
namespace message
53
49
{
54
50
 
55
 
static void escapeEmbeddedQuotes(string &s, const char quote='\'')
56
 
{
57
 
  string::iterator it;
58
 
 
59
 
  for (it= s.begin(); it != s.end(); ++it)
60
 
  {
61
 
    if (*it == quote)
62
 
    {
63
 
      it= s.insert(it, quote);
64
 
      ++it;  // advance back to the quote
65
 
    }
66
 
  }
67
 
}
68
 
 
69
 
/* Incredibly similar to append_unescaped() in table.cc, but for std::string */
70
 
static void append_escaped_string(std::string *res, const std::string &input, const char quote='\'')
71
 
{
72
 
  const char *pos= input.c_str();
73
 
  const char *end= input.c_str()+input.length();
74
 
  res->push_back(quote);
75
 
 
76
 
  for (; pos != end ; pos++)
77
 
  {
78
 
    uint32_t mblen;
79
 
    if (use_mb(default_charset_info) &&
80
 
        (mblen= my_ismbchar(default_charset_info, pos, end)))
81
 
    {
82
 
      res->append(pos, mblen);
83
 
      pos+= mblen - 1;
84
 
      if (pos >= end)
85
 
        break;
86
 
      continue;
87
 
    }
88
 
 
89
 
    switch (*pos) {
90
 
    case 0:                             /* Must be escaped for 'mysql' */
91
 
      res->push_back('\\');
92
 
      res->push_back('0');
93
 
      break;
94
 
    case '\n':                          /* Must be escaped for logs */
95
 
      res->push_back('\\');
96
 
      res->push_back('n');
97
 
      break;
98
 
    case '\r':
99
 
      res->push_back('\\');             /* This gives better readability */
100
 
      res->push_back('r');
101
 
      break;
102
 
    case '\\':
103
 
      res->push_back('\\');             /* Because of the sql syntax */
104
 
      res->push_back('\\');
105
 
      break;
106
 
    default:
107
 
      if (*pos == quote) /* SQL syntax for quoting a quote */
108
 
      {
109
 
        res->push_back(quote);
110
 
        res->push_back(quote);
111
 
      }
112
 
      else
113
 
        res->push_back(*pos);
114
 
      break;
115
 
    }
116
 
  }
117
 
  res->push_back(quote);
118
 
}
119
 
 
120
51
enum TransformSqlError
121
52
transformStatementToSql(const Statement &source,
122
53
                        vector<string> &sql_strings,
127
58
 
128
59
  switch (source.type())
129
60
  {
130
 
  case Statement::ROLLBACK_STATEMENT:
131
 
    {
132
 
      break;
133
 
    }
134
 
  case Statement::ROLLBACK:
135
 
    {
136
 
      sql_strings.push_back("ROLLBACK");
137
 
      break;
138
 
    }
139
61
  case Statement::INSERT:
140
62
    {
141
63
      if (! source.has_insert_header())
152
74
      const InsertHeader &insert_header= source.insert_header();
153
75
      const InsertData &insert_data= source.insert_data();
154
76
      size_t num_keys= insert_data.record_size();
 
77
      size_t x;
155
78
 
156
79
      if (num_keys > 1 && ! already_in_transaction)
157
80
        sql_strings.push_back("START TRANSACTION");
158
81
 
159
 
      for (size_t x= 0; x < num_keys; ++x)
 
82
      for (x= 0; x < num_keys; ++x)
160
83
      {
161
84
        string destination;
162
85
 
317
240
      sql_strings.push_back(destination);
318
241
    }
319
242
    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
243
  case Statement::SET_VARIABLE:
331
244
    {
332
245
      assert(source.has_set_variable_statement());
410
323
 
411
324
    const FieldMetadata &field_metadata= header.field_metadata(x);
412
325
 
413
 
    if (record.is_null(x))
414
 
    {
415
 
      should_quote_field_value= false;
416
 
    }
417
 
    else 
418
 
    {
419
 
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
420
 
    }
 
326
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
421
327
 
422
328
    if (should_quote_field_value)
423
329
      destination.push_back('\'');
424
330
 
425
 
    if (record.is_null(x))
 
331
    if (field_metadata.type() == Table::Field::BLOB)
426
332
    {
427
 
      destination.append("NULL");
 
333
      /* 
 
334
        * We do this here because BLOB data is returned
 
335
        * in a string correctly, but calling append()
 
336
        * without a length will result in only the string
 
337
        * up to a \0 being output here.
 
338
        */
 
339
      string raw_data(record.insert_value(x));
 
340
      destination.append(raw_data.c_str(), raw_data.size());
428
341
    }
429
342
    else
430
343
    {
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
 
      }
 
344
      destination.append(record.insert_value(x));
448
345
    }
449
346
 
450
347
    if (should_quote_field_value)
507
404
      }
508
405
      else
509
406
      {
510
 
        string tmp(data.record(x).insert_value(y));
511
 
        escapeEmbeddedQuotes(tmp);
512
 
        destination.append(tmp);
 
407
        destination.append(data.record(x).insert_value(y));
513
408
      }
514
409
 
515
410
      if (should_quote_field_value)
573
468
    destination.push_back(quoted_identifier);
574
469
    destination.push_back('=');
575
470
 
576
 
    if (record.is_null(x))
577
 
    {
578
 
      should_quote_field_value= false;
579
 
    }
580
 
    else 
581
 
    {
582
 
      should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
583
 
    }    
 
471
    should_quote_field_value= shouldQuoteFieldValue(field_metadata.type());
584
472
 
585
473
    if (should_quote_field_value)
586
474
      destination.push_back('\'');
587
475
 
588
 
    if (record.is_null(x))
 
476
    if (field_metadata.type() == Table::Field::BLOB)
589
477
    {
590
 
      destination.append("NULL");
 
478
      /* 
 
479
       * We do this here because BLOB data is returned
 
480
       * in a string correctly, but calling append()
 
481
       * without a length will result in only the string
 
482
       * up to a \0 being output here.
 
483
       */
 
484
      string raw_data(record.after_value(x));
 
485
      destination.append(raw_data.c_str(), raw_data.size());
591
486
    }
592
 
    else 
 
487
    else
593
488
    {
594
 
      if (field_metadata.type() == Table::Field::BLOB)
595
 
      {
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());
604
 
      }
605
 
      else 
606
 
      {
607
 
        string tmp(record.after_value(x));
608
 
        escapeEmbeddedQuotes(tmp);
609
 
        destination.append(tmp);
610
 
      }
 
489
      destination.append(record.after_value(x));
611
490
    }
612
491
 
613
492
    if (should_quote_field_value)
729
608
    }
730
609
    else
731
610
    {
732
 
      string tmp(record.key_value(x));
733
 
      escapeEmbeddedQuotes(tmp);
734
 
      destination.append(tmp);
 
611
      destination.append(record.key_value(x));
735
612
    }
736
613
 
737
614
    if (should_quote_field_value)
800
677
      }
801
678
      else
802
679
      {
803
 
        string tmp(data.record(x).key_value(y));
804
 
        escapeEmbeddedQuotes(tmp);
805
 
        destination.append(tmp);
 
680
        destination.append(data.record(x).key_value(y));
806
681
      }
807
682
 
808
683
      if (should_quote_field_value)
815
690
}
816
691
 
817
692
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
693
transformDropSchemaStatementToSql(const DropSchemaStatement &statement,
850
694
                                  string &destination,
851
695
                                  enum TransformSqlVariant sql_variant)
873
717
 
874
718
  const Schema &schema= statement.schema();
875
719
 
876
 
  destination.append("CREATE SCHEMA ");
 
720
  destination.append("CREATE SCHEMA ", 14);
877
721
  destination.push_back(quoted_identifier);
878
722
  destination.append(schema.name());
879
723
  destination.push_back(quoted_identifier);
880
724
 
881
725
  if (schema.has_collation())
882
726
  {
883
 
    destination.append(" COLLATE ");
 
727
    destination.append(" COLLATE ", 9);
884
728
    destination.append(schema.collation());
885
729
  }
886
730
 
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
731
  return NONE;
893
732
}
894
733
 
903
742
 
904
743
  const TableMetadata &table_metadata= statement.table_metadata();
905
744
 
906
 
  destination.append("DROP TABLE ");
 
745
  destination.append("DROP TABLE ", 11);
907
746
 
908
747
  /* Add the IF EXISTS clause if necessary */
909
748
  if (statement.has_if_exists_clause() &&
910
749
      statement.if_exists_clause() == true)
911
750
  {
912
 
    destination.append("IF EXISTS ");
 
751
    destination.append("IF EXISTS ", 10);
913
752
  }
914
753
 
915
754
  destination.push_back(quoted_identifier);
934
773
 
935
774
  const TableMetadata &table_metadata= statement.table_metadata();
936
775
 
937
 
  destination.append("TRUNCATE TABLE ");
 
776
  destination.append("TRUNCATE TABLE ", 15);
938
777
  destination.push_back(quoted_identifier);
939
778
  destination.append(table_metadata.schema_name());
940
779
  destination.push_back(quoted_identifier);
955
794
  const FieldMetadata &variable_metadata= statement.variable_metadata();
956
795
  bool should_quote_field_value= shouldQuoteFieldValue(variable_metadata.type());
957
796
 
958
 
  destination.append("SET GLOBAL "); /* Only global variables are replicated */
 
797
  destination.append("SET GLOBAL ", 11); /* Only global variables are replicated */
959
798
  destination.append(variable_metadata.name());
960
799
  destination.push_back('=');
961
800
 
987
826
  if (sql_variant == ANSI)
988
827
    quoted_identifier= '"';
989
828
 
990
 
  destination.append("CREATE ");
 
829
  destination.append("CREATE ", 7);
991
830
 
992
831
  if (table.type() == Table::TEMPORARY)
993
 
    destination.append("TEMPORARY ");
 
832
    destination.append("TEMPORARY ", 10);
994
833
  
995
 
  destination.append("TABLE ");
 
834
  destination.append("TABLE ", 6);
996
835
  if (with_schema)
997
836
  {
998
 
    append_escaped_string(&destination, table.schema(), quoted_identifier);
 
837
    destination.push_back(quoted_identifier);
 
838
    destination.append(table.schema());
 
839
    destination.push_back(quoted_identifier);
999
840
    destination.push_back('.');
1000
841
  }
1001
 
  append_escaped_string(&destination, table.name(), quoted_identifier);
1002
 
  destination.append(" (\n");
 
842
  destination.push_back(quoted_identifier);
 
843
  destination.append(table.name());
 
844
  destination.push_back(quoted_identifier);
 
845
  destination.append(" (\n", 3);
1003
846
 
1004
847
  enum TransformSqlError result= NONE;
1005
848
  size_t num_fields= table.field_size();
1008
851
    const Table::Field &field= table.field(x);
1009
852
 
1010
853
    if (x != 0)
1011
 
      destination.append(",\n");
1012
 
 
1013
 
    destination.append("  ");
 
854
      destination.append(",\n", 2);
1014
855
 
1015
856
    result= transformFieldDefinitionToSql(field, destination, sql_variant);
1016
 
 
 
857
    
1017
858
    if (result != NONE)
1018
859
      return result;
1019
860
  }
1021
862
  size_t num_indexes= table.indexes_size();
1022
863
  
1023
864
  if (num_indexes > 0)
1024
 
    destination.append(",\n");
 
865
    destination.append(",\n", 2);
1025
866
 
1026
867
  for (size_t x= 0; x < num_indexes; ++x)
1027
868
  {
1028
869
    const message::Table::Index &index= table.indexes(x);
1029
870
 
1030
871
    if (x != 0)
1031
 
      destination.append(",\n");
 
872
      destination.append(",\n", 2);
1032
873
 
1033
874
    result= transformIndexDefinitionToSql(index, table, destination, sql_variant);
1034
875
    
1035
876
    if (result != NONE)
1036
877
      return result;
1037
878
  }
1038
 
 
1039
 
  size_t num_foreign_keys= table.fk_constraint_size();
1040
 
 
1041
 
  if (num_foreign_keys > 0)
1042
 
    destination.append(",\n");
1043
 
 
1044
 
  for (size_t x= 0; x < num_foreign_keys; ++x)
1045
 
  {
1046
 
    const message::Table::ForeignKeyConstraint &fkey= table.fk_constraint(x);
1047
 
 
1048
 
    if (x != 0)
1049
 
      destination.append(",\n");
1050
 
 
1051
 
    result= transformForeignKeyConstraintDefinitionToSql(fkey, table, destination, sql_variant);
1052
 
 
1053
 
    if (result != NONE)
1054
 
      return result;
1055
 
  }
1056
 
 
1057
 
  destination.append("\n)");
 
879
  destination.append("\n)", 2);
1058
880
 
1059
881
  /* Add ENGINE = " clause */
1060
882
  if (table.has_engine())
1061
883
  {
1062
 
    destination.append(" ENGINE=");
1063
 
    destination.append(table.engine().name());
 
884
    const Table::StorageEngine &engine= table.engine();
 
885
    destination.append("\nENGINE = ", 10);
 
886
    destination.append(engine.name());
1064
887
 
1065
 
    size_t num_engine_options= table.engine().options_size();
1066
 
    if (num_engine_options > 0)
1067
 
      destination.append(" ", 1);
 
888
    size_t num_engine_options= engine.option_size();
1068
889
    for (size_t x= 0; x < num_engine_options; ++x)
1069
890
    {
1070
 
      const Engine::Option &option= table.engine().options(x);
1071
 
      destination.append(option.name());
1072
 
      destination.append("='");
1073
 
      destination.append(option.state());
1074
 
      destination.append("'");
1075
 
      if (x != num_engine_options-1)
1076
 
      {
1077
 
        destination.append(", ");
1078
 
      }
 
891
      const Table::StorageEngine::EngineOption &option= engine.option(x);
 
892
      destination.push_back('\n');
 
893
      destination.append(option.option_name());
 
894
      destination.append(" = ", 3);
 
895
      destination.append(option.option_value());
 
896
      destination.push_back('\n');
1079
897
    }
1080
898
  }
1081
899
 
1093
911
  if (sql_variant == ANSI)
1094
912
    return NONE; /* ANSI does not support table options... */
1095
913
 
 
914
  stringstream ss;
 
915
 
1096
916
  if (options.has_comment())
1097
917
  {
1098
 
    destination.append(" COMMENT=");
1099
 
    append_escaped_string(&destination, options.comment());
 
918
    destination.append("\nCOMMENT = '", 12);
 
919
    destination.append(options.comment());
 
920
    destination.push_back('\'');
1100
921
  }
1101
922
 
1102
923
  if (options.has_collation())
1103
924
  {
1104
 
    destination.append(" COLLATE = ");
 
925
    destination.append("\nCOLLATE = ", 11);
1105
926
    destination.append(options.collation());
1106
927
  }
1107
928
 
 
929
  if (options.has_auto_increment())
 
930
  {
 
931
    ss << options.auto_increment();
 
932
    destination.append("\nAUTOINCREMENT_OFFSET = ", 24);
 
933
    destination.append(ss.str());
 
934
    ss.clear();
 
935
  }
 
936
  
 
937
  if (options.has_row_type())
 
938
  {
 
939
    ss << options.row_type();
 
940
    destination.append("\nROW_TYPE = ", 12);
 
941
    destination.append(ss.str());
 
942
    ss.clear();
 
943
  }
 
944
 
1108
945
  if (options.has_data_file_name())
1109
946
  {
1110
 
    destination.append("\nDATA_FILE_NAME = '");
 
947
    destination.append("\nDATA_FILE_NAME = '", 19);
1111
948
    destination.append(options.data_file_name());
1112
949
    destination.push_back('\'');
1113
950
  }
1114
951
 
1115
952
  if (options.has_index_file_name())
1116
953
  {
1117
 
    destination.append("\nINDEX_FILE_NAME = '");
 
954
    destination.append("\nINDEX_FILE_NAME = '", 20);
1118
955
    destination.append(options.index_file_name());
1119
956
    destination.push_back('\'');
1120
957
  }
1121
958
 
1122
959
  if (options.has_max_rows())
1123
960
  {
1124
 
    destination.append("\nMAX_ROWS = ");
1125
 
    destination.append(boost::lexical_cast<string>(options.max_rows()));
 
961
    ss << options.max_rows();
 
962
    destination.append("\nMAX_ROWS = ", 12);
 
963
    destination.append(ss.str());
 
964
    ss.clear();
1126
965
  }
1127
966
 
1128
967
  if (options.has_min_rows())
1129
968
  {
1130
 
    destination.append("\nMIN_ROWS = ");
1131
 
    destination.append(boost::lexical_cast<string>(options.min_rows()));
 
969
    ss << options.min_rows();
 
970
    destination.append("\nMIN_ROWS = ", 12);
 
971
    destination.append(ss.str());
 
972
    ss.clear();
1132
973
  }
1133
974
 
1134
 
  if (options.has_user_set_auto_increment_value()
1135
 
      && options.has_auto_increment_value())
 
975
  if (options.has_auto_increment_value())
1136
976
  {
1137
 
    destination.append(" AUTO_INCREMENT=");
1138
 
    destination.append(boost::lexical_cast<string>(options.auto_increment_value()));
 
977
    ss << options.auto_increment_value();
 
978
    destination.append("\nAUTO_INCREMENT = ", 18);
 
979
    destination.append(ss.str());
 
980
    ss.clear();
1139
981
  }
1140
982
 
1141
983
  if (options.has_avg_row_length())
1142
984
  {
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
 
  }
 
985
    ss << options.avg_row_length();
 
986
    destination.append("\nAVG_ROW_LENGTH = ", 18);
 
987
    destination.append(ss.str());
 
988
    ss.clear();
 
989
  }
 
990
 
 
991
  if (options.has_key_block_size())
 
992
  {
 
993
    ss << options.key_block_size();
 
994
    destination.append("\nKEY_BLOCK_SIZE = ", 18);
 
995
    destination.append(ss.str());
 
996
    ss.clear();
 
997
  }
 
998
 
 
999
  if (options.has_block_size())
 
1000
  {
 
1001
    ss << options.block_size();
 
1002
    destination.append("\nBLOCK_SIZE = ", 14);
 
1003
    destination.append(ss.str());
 
1004
    ss.clear();
 
1005
  }
 
1006
 
 
1007
  if (options.has_pack_keys() &&
 
1008
      options.pack_keys())
 
1009
    destination.append("\nPACK_KEYS = TRUE", 17);
 
1010
  if (options.has_pack_record() &&
 
1011
      options.pack_record())
 
1012
    destination.append("\nPACK_RECORD = TRUE", 19);
 
1013
  if (options.has_checksum() &&
 
1014
      options.checksum())
 
1015
    destination.append("\nCHECKSUM = TRUE", 16);
 
1016
  if (options.has_page_checksum() &&
 
1017
      options.page_checksum())
 
1018
    destination.append("\nPAGE_CHECKSUM = TRUE", 21);
1157
1019
 
1158
1020
  return NONE;
1159
1021
}
1168
1030
  if (sql_variant == ANSI)
1169
1031
    quoted_identifier= '"';
1170
1032
 
1171
 
  destination.append("  ", 2);
1172
 
 
1173
1033
  if (index.is_primary())
1174
 
    destination.append("PRIMARY ");
 
1034
    destination.append("PRIMARY ", 8);
1175
1035
  else if (index.is_unique())
1176
 
    destination.append("UNIQUE ");
 
1036
    destination.append("UNIQUE ", 7);
1177
1037
 
1178
1038
  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
 
 
 
1039
  destination.push_back(quoted_identifier);
 
1040
  destination.append(index.name());
 
1041
  destination.push_back(quoted_identifier);
 
1042
  destination.append(" (", 2);
 
1043
  
1189
1044
  size_t num_parts= index.index_part_size();
1190
1045
  for (size_t x= 0; x < num_parts; ++x)
1191
1046
  {
1209
1064
    {
1210
1065
      if (part.has_compare_length())
1211
1066
      {
1212
 
        if (part.compare_length() != field.string_options().length())
 
1067
        size_t compare_length_in_chars= part.compare_length();
 
1068
        
 
1069
        /* hack: compare_length() is bytes, not chars, but
 
1070
         * only for VARCHAR. Ass. */
 
1071
        if (field.type() == Table::Field::VARCHAR)
 
1072
          compare_length_in_chars/= 4;
 
1073
 
 
1074
        if (compare_length_in_chars != field.string_options().length())
1213
1075
        {
 
1076
          stringstream ss;
1214
1077
          destination.push_back('(');
1215
 
          destination.append(boost::lexical_cast<string>(part.compare_length()));
 
1078
          ss << compare_length_in_chars;
 
1079
          destination.append(ss.str());
1216
1080
          destination.push_back(')');
1217
1081
        }
1218
1082
      }
1220
1084
  }
1221
1085
  destination.push_back(')');
1222
1086
 
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
 
  return NONE;
1248
 
}
1249
 
 
1250
 
static void transformForeignKeyOptionToSql(Table::ForeignKeyConstraint::ForeignKeyOption opt, string &destination)
1251
 
{
1252
 
  switch (opt)
1253
 
  {
1254
 
  case Table::ForeignKeyConstraint::OPTION_RESTRICT:
1255
 
    destination.append("RESTRICT");
1256
 
    break;
1257
 
  case Table::ForeignKeyConstraint::OPTION_CASCADE:
1258
 
    destination.append("CASCADE");
1259
 
    break;
1260
 
  case Table::ForeignKeyConstraint::OPTION_SET_NULL:
1261
 
    destination.append("SET NULL");
1262
 
    break;
1263
 
  case Table::ForeignKeyConstraint::OPTION_UNDEF:
1264
 
  case Table::ForeignKeyConstraint::OPTION_NO_ACTION:
1265
 
    destination.append("NO ACTION");
1266
 
    break;
1267
 
  case Table::ForeignKeyConstraint::OPTION_SET_DEFAULT:
1268
 
    destination.append("SET DEFAULT");
1269
 
    break;
1270
 
  }
1271
 
}
1272
 
 
1273
 
enum TransformSqlError
1274
 
transformForeignKeyConstraintDefinitionToSql(const Table::ForeignKeyConstraint &fkey,
1275
 
                                             const Table &,
1276
 
                                             string &destination,
1277
 
                                             enum TransformSqlVariant sql_variant)
1278
 
{
1279
 
  char quoted_identifier= '`';
1280
 
  if (sql_variant == ANSI)
1281
 
    quoted_identifier= '"';
1282
 
 
1283
 
  destination.append("  ");
1284
 
 
1285
 
  if (fkey.has_name())
1286
 
  {
1287
 
    destination.append("CONSTRAINT ");
1288
 
    append_escaped_string(&destination, fkey.name(), quoted_identifier);
1289
 
    destination.append(" ", 1);
1290
 
  }
1291
 
 
1292
 
  destination.append("FOREIGN KEY (");
1293
 
 
1294
 
  for (ssize_t x= 0; x < fkey.column_names_size(); ++x)
1295
 
  {
1296
 
    if (x != 0)
1297
 
      destination.append(", ");
1298
 
 
1299
 
    append_escaped_string(&destination, fkey.column_names(x),
1300
 
                          quoted_identifier);
1301
 
  }
1302
 
 
1303
 
  destination.append(") REFERENCES ");
1304
 
 
1305
 
  append_escaped_string(&destination, fkey.references_table_name(),
1306
 
                        quoted_identifier);
1307
 
  destination.append(" (");
1308
 
 
1309
 
  for (ssize_t x= 0; x < fkey.references_columns_size(); ++x)
1310
 
  {
1311
 
    if (x != 0)
1312
 
      destination.append(", ");
1313
 
 
1314
 
    append_escaped_string(&destination, fkey.references_columns(x),
1315
 
                          quoted_identifier);
1316
 
  }
1317
 
 
1318
 
  destination.push_back(')');
1319
 
 
1320
 
  if (fkey.has_update_option() and fkey.update_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1321
 
  {
1322
 
    destination.append(" ON UPDATE ");
1323
 
    transformForeignKeyOptionToSql(fkey.update_option(), destination);
1324
 
  }
1325
 
 
1326
 
  if (fkey.has_delete_option() and fkey.delete_option() != Table::ForeignKeyConstraint::OPTION_UNDEF)
1327
 
  {
1328
 
    destination.append(" ON DELETE ");
1329
 
    transformForeignKeyOptionToSql(fkey.delete_option(), destination);
1330
 
  }
1331
 
 
1332
1087
  return NONE;
1333
1088
}
1334
1089
 
1338
1093
                              enum TransformSqlVariant sql_variant)
1339
1094
{
1340
1095
  char quoted_identifier= '`';
1341
 
  char quoted_default;
1342
 
 
1343
1096
  if (sql_variant == ANSI)
1344
1097
    quoted_identifier= '"';
1345
1098
 
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);
 
1099
  destination.push_back(quoted_identifier);
 
1100
  destination.append(field.name());
 
1101
  destination.push_back(quoted_identifier);
1352
1102
 
1353
1103
  Table::Field::FieldType field_type= field.type();
1354
1104
 
1355
1105
  switch (field_type)
1356
1106
  {
1357
1107
    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
 
    }
 
1108
    destination.append(" DOUBLE", 7);
1367
1109
    break;
1368
1110
  case Table::Field::VARCHAR:
1369
1111
    {
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(")");
 
1112
      destination.append(" VARCHAR(", 9);
 
1113
      stringstream ss;
 
1114
      ss << field.string_options().length() << ")";
 
1115
      destination.append(ss.str());
1378
1116
    }
1379
1117
    break;
1380
1118
  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
 
    }
 
1119
    destination.append(" BLOB", 5);
1388
1120
    break;
1389
1121
  case Table::Field::ENUM:
1390
1122
    {
1391
1123
      size_t num_field_values= field.enumeration_values().field_value_size();
1392
 
      destination.append(" ENUM(");
 
1124
      destination.append(" ENUM(", 6);
1393
1125
      for (size_t x= 0; x < num_field_values; ++x)
1394
1126
      {
1395
1127
        const string &type= field.enumeration_values().field_value(x);
1404
1136
      destination.push_back(')');
1405
1137
      break;
1406
1138
    }
1407
 
  case Table::Field::UUID:
1408
 
    destination.append(" UUID");
1409
 
    break;
1410
 
  case Table::Field::BOOLEAN:
1411
 
    destination.append(" BOOLEAN");
1412
 
    break;
1413
1139
  case Table::Field::INTEGER:
1414
 
    destination.append(" INT");
 
1140
    destination.append(" INT", 4);
1415
1141
    break;
1416
1142
  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
 
    }
 
1143
    destination.append(" BIGINT", 7);
1426
1144
    break;
1427
1145
  case Table::Field::DECIMAL:
1428
1146
    {
1429
 
      destination.append(" DECIMAL(");
 
1147
      destination.append(" DECIMAL(", 9);
1430
1148
      stringstream ss;
1431
1149
      ss << field.numeric_options().precision() << ",";
1432
1150
      ss << field.numeric_options().scale() << ")";
1434
1152
    }
1435
1153
    break;
1436
1154
  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
 
 
 
1155
    destination.append(" DATE", 5);
 
1156
    break;
 
1157
  case Table::Field::TIMESTAMP:
 
1158
    destination.append(" TIMESTAMP",  10);
 
1159
    break;
1451
1160
  case Table::Field::DATETIME:
1452
 
    destination.append(" DATETIME");
1453
 
    break;
1454
 
  case Table::Field::TIME:
1455
 
    destination.append(" TIME");
1456
 
    break;
 
1161
    destination.append(" DATETIME",  9);
 
1162
    break;
 
1163
  }
 
1164
 
 
1165
  if (field.type() == Table::Field::INTEGER || 
 
1166
      field.type() == Table::Field::BIGINT)
 
1167
  {
 
1168
    if (field.has_constraints() &&
 
1169
        field.constraints().has_is_unsigned() &&
 
1170
        field.constraints().is_unsigned())
 
1171
    {
 
1172
      destination.append(" UNSIGNED", 9);
 
1173
    }
 
1174
  }
 
1175
 
 
1176
 
 
1177
  if (! (field.has_constraints() &&
 
1178
         field.constraints().is_nullable()))
 
1179
  {
 
1180
    destination.append(" NOT", 4);
 
1181
  }
 
1182
  destination.append(" NULL", 5);
 
1183
 
 
1184
  if (field.type() == Table::Field::INTEGER || 
 
1185
      field.type() == Table::Field::BIGINT)
 
1186
  {
 
1187
    /* AUTO_INCREMENT must be after NOT NULL */
 
1188
    if (field.has_numeric_options() &&
 
1189
        field.numeric_options().is_autoincrement())
 
1190
    {
 
1191
      destination.append(" AUTO_INCREMENT", 15);
 
1192
    }
1457
1193
  }
1458
1194
 
1459
1195
  if (field.type() == Table::Field::BLOB ||
1460
1196
      field.type() == Table::Field::VARCHAR)
1461
1197
  {
1462
 
    if (field.string_options().has_collation()
1463
 
        && field.string_options().collation().compare("binary"))
 
1198
    if (field.string_options().has_collation())
1464
1199
    {
1465
 
      destination.append(" COLLATE ");
 
1200
      destination.append(" COLLATE ", 9);
1466
1201
      destination.append(field.string_options().collation());
1467
1202
    }
1468
1203
  }
1469
1204
 
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
1205
  if (field.options().has_default_value())
1496
1206
  {
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())
 
1207
    destination.append(" DEFAULT ", 9);
 
1208
    destination.push_back(quoted_identifier);
 
1209
    destination.append(field.options().default_value());
 
1210
    destination.push_back(quoted_identifier);
 
1211
  }
 
1212
 
 
1213
  if (field.options().has_default_bin_value())
1506
1214
  {
1507
1215
    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");
 
1216
    destination.append(" DEFAULT 0x", 11);
 
1217
    for (size_t x= 0; x < v.length(); x++)
 
1218
    {
 
1219
      printf("%.2x", *(v.c_str() + x));
 
1220
    }
1528
1221
  }
1529
1222
 
1530
 
  if (field.has_options() && field.options().has_update_expression())
1531
 
  {
1532
 
    destination.append(" ON UPDATE ");
1533
 
    destination.append(field.options().update_expression());
1534
 
  }
 
1223
  if (field.type() == Table::Field::TIMESTAMP)
 
1224
    if (field.timestamp_options().has_auto_updates() &&
 
1225
        field.timestamp_options().auto_updates())
 
1226
      destination.append(" ON UPDATE CURRENT_TIMESTAMP", 28);
1535
1227
 
1536
1228
  if (field.has_comment())
1537
1229
  {
1538
 
    destination.append(" COMMENT ");
1539
 
    append_escaped_string(&destination, field.comment(), quoted_default);
 
1230
    destination.append(" COMMENT ", 9);
 
1231
    destination.push_back(quoted_identifier);
 
1232
    destination.append(field.comment());
 
1233
    destination.push_back(quoted_identifier);
1540
1234
  }
1541
1235
  return NONE;
1542
1236
}
1549
1243
  case Table::Field::DECIMAL:
1550
1244
  case Table::Field::INTEGER:
1551
1245
  case Table::Field::BIGINT:
 
1246
  case Table::Field::ENUM:
1552
1247
    return false;
1553
1248
  default:
1554
1249
    return true;
1565
1260
  case DRIZZLE_TYPE_NULL:
1566
1261
    assert(false); /* Not a user definable type */
1567
1262
    return Table::Field::INTEGER; /* unreachable */
1568
 
  case DRIZZLE_TYPE_MICROTIME:
1569
1263
  case DRIZZLE_TYPE_TIMESTAMP:
1570
 
    return Table::Field::EPOCH;
 
1264
    return Table::Field::TIMESTAMP;
1571
1265
  case DRIZZLE_TYPE_LONGLONG:
1572
1266
    return Table::Field::BIGINT;
1573
1267
  case DRIZZLE_TYPE_DATETIME:
1574
1268
    return Table::Field::DATETIME;
1575
 
  case DRIZZLE_TYPE_TIME:
1576
 
    return Table::Field::TIME;
1577
1269
  case DRIZZLE_TYPE_DATE:
1578
1270
    return Table::Field::DATE;
1579
1271
  case DRIZZLE_TYPE_VARCHAR:
1584
1276
    return Table::Field::ENUM;
1585
1277
  case DRIZZLE_TYPE_BLOB:
1586
1278
    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
1279
  }
1592
1280
 
1593
1281
  assert(false);