~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/foreign_key.cc

  • Committer: Daniel Nichter
  • Date: 2011-10-23 16:01:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2448.
  • Revision ID: daniel@percona.com-20111023160137-7ac3blgz8z4tf8za
Add Administration Getting Started and Logging.  Capitalize SQL clause keywords.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
#include <config.h>
 
21
 
 
22
#include <string>
 
23
 
 
24
#include <drizzled/foreign_key.h>
 
25
#include <drizzled/error.h>
 
26
#include <drizzled/create_field.h>
 
27
#include <drizzled/internal/my_sys.h>
 
28
#include <drizzled/table_ident.h>
 
29
 
 
30
namespace drizzled
 
31
{
 
32
 
 
33
extern const charset_info_st *system_charset_info;
 
34
 
 
35
void add_foreign_key_to_table_message(
 
36
    message::Table *table_message,
 
37
    const char* fkey_name,
 
38
    List<Key_part_spec> &cols,
 
39
    Table_ident *table,
 
40
    List<Key_part_spec> &ref_cols,
 
41
    message::Table::ForeignKeyConstraint::ForeignKeyOption delete_opt_arg,
 
42
    message::Table::ForeignKeyConstraint::ForeignKeyOption update_opt_arg,
 
43
    message::Table::ForeignKeyConstraint::ForeignKeyMatchOption match_opt_arg)
 
44
{
 
45
  message::Table::ForeignKeyConstraint *pfkey= table_message->add_fk_constraint();
 
46
  if (fkey_name)
 
47
    pfkey->set_name(fkey_name);
 
48
  else if (table_message->has_name())
 
49
  {
 
50
    std::string name(table_message->name());
 
51
    char number[20];
 
52
 
 
53
    name.append("_ibfk_");
 
54
    snprintf(number, sizeof(number), "%d", table_message->fk_constraint_size());
 
55
    name.append(number);
 
56
 
 
57
    pfkey->set_name(name);
 
58
  }
 
59
 
 
60
  pfkey->set_match(match_opt_arg);
 
61
  pfkey->set_update_option(update_opt_arg);
 
62
  pfkey->set_delete_option(delete_opt_arg);
 
63
 
 
64
  pfkey->set_references_table_name(table->table.str);
 
65
 
 
66
  Key_part_spec *keypart;
 
67
  List<Key_part_spec>::iterator col_it(cols.begin());
 
68
  while ((keypart= col_it++))
 
69
  {
 
70
    pfkey->add_column_names(keypart->field_name.str);
 
71
  }
 
72
 
 
73
  List<Key_part_spec>::iterator ref_it(ref_cols.begin());
 
74
  while ((keypart= ref_it++))
 
75
  {
 
76
    pfkey->add_references_columns(keypart->field_name.str);
 
77
  }
 
78
 
 
79
}
 
80
 
 
81
/**
 
82
  Make a deep copy of each list element.
 
83
 
 
84
  @note A template function and not a template method of class List
 
85
  is employed because of explicit template instantiation:
 
86
  in server code there are explicit instantiations of List<T> and
 
87
  an explicit instantiation of a template requires that any method
 
88
  of the instantiated class used in the template can be resolved.
 
89
  Evidently not all template arguments have clone() method with
 
90
  the right signature.
 
91
 
 
92
  @return You must query the error state in Session for out-of-memory
 
93
  situation after calling this function.
 
94
*/
 
95
 
 
96
template <typename T>
 
97
void list_copy_and_replace_each_value(List<T> &list, memory::Root *mem_root)
 
98
{
 
99
  /* Make a deep copy of each element */
 
100
  typename List<T>::iterator it(list.begin());
 
101
  while (T* el= it++)
 
102
    it.replace(el->clone(mem_root));
 
103
}
 
104
 
 
105
Foreign_key::Foreign_key(const Foreign_key &rhs, memory::Root *mem_root)
 
106
  :Key(rhs),
 
107
  ref_table(rhs.ref_table),
 
108
  ref_columns(rhs.ref_columns),
 
109
  delete_opt(rhs.delete_opt),
 
110
  update_opt(rhs.update_opt),
 
111
  match_opt(rhs.match_opt)
 
112
{
 
113
  list_copy_and_replace_each_value(ref_columns, mem_root);
 
114
}
 
115
 
 
116
/*
 
117
  Test if a foreign key (= generated key) is a prefix of the given key
 
118
  (ignoring key name, key type and order of columns)
 
119
 
 
120
  NOTES:
 
121
    This is only used to test if an index for a FOREIGN KEY exists
 
122
 
 
123
  IMPLEMENTATION
 
124
    We only compare field names
 
125
 
 
126
  RETURN
 
127
    0   Generated key is a prefix of other key
 
128
    1   Not equal
 
129
*/
 
130
bool foreign_key_prefix(Key *a, Key *b)
 
131
{
 
132
  /* Ensure that 'a' is the generated key */
 
133
  if (a->generated)
 
134
  {
 
135
    if (b->generated && a->columns.size() > b->columns.size())
 
136
      std::swap(a, b);                       // Put shorter key in 'a'
 
137
  }
 
138
  else
 
139
  {
 
140
    if (!b->generated)
 
141
      return true;                              // No foreign key
 
142
    std::swap(a, b);                       // Put generated key in 'a'
 
143
  }
 
144
 
 
145
  /* Test if 'a' is a prefix of 'b' */
 
146
  if (a->columns.size() > b->columns.size())
 
147
    return true;                                // Can't be prefix
 
148
 
 
149
  List<Key_part_spec>::iterator col_it1(a->columns.begin());
 
150
  List<Key_part_spec>::iterator col_it2(b->columns.begin());
 
151
  const Key_part_spec *col1, *col2;
 
152
 
 
153
#ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
 
154
  while ((col1= col_it1++))
 
155
  {
 
156
    bool found= 0;
 
157
    col_it2=b->columns.begin();
 
158
    while ((col2= col_it2++))
 
159
    {
 
160
      if (*col1 == *col2)
 
161
      {
 
162
        found= true;
 
163
        break;
 
164
      }
 
165
    }
 
166
    if (!found)
 
167
      return true;                              // Error
 
168
  }
 
169
  return false;                                 // Is prefix
 
170
#else
 
171
  while ((col1= col_it1++))
 
172
  {
 
173
    col2= col_it2++;
 
174
    if (!(*col1 == *col2))
 
175
      return true;
 
176
  }
 
177
  return false;                                 // Is prefix
 
178
#endif
 
179
}
 
180
 
 
181
/*
 
182
  Check if the foreign key options are compatible with columns
 
183
  on which the FK is created.
 
184
 
 
185
  RETURN
 
186
    0   Key valid
 
187
    1   Key invalid
 
188
*/
 
189
bool Foreign_key::validate(List<CreateField> &table_fields)
 
190
{
 
191
  CreateField  *sql_field;
 
192
  Key_part_spec *column;
 
193
  List<Key_part_spec>::iterator cols(columns.begin());
 
194
  List<CreateField>::iterator it(table_fields.begin());
 
195
  while ((column= cols++))
 
196
  {
 
197
    it= table_fields.begin();
 
198
    while ((sql_field= it++) &&
 
199
           my_strcasecmp(system_charset_info,
 
200
                         column->field_name.str,
 
201
                         sql_field->field_name)) {}
 
202
    if (!sql_field)
 
203
    {
 
204
      my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
 
205
      return true;
 
206
    }
 
207
  }
 
208
  return false;
 
209
}
 
210
 
 
211
} /* namespace drizzled */