Drizzled Public API Documentation

foreign_key.cc
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 extern const charset_info_st *system_charset_info;
33 
34 void add_foreign_key_to_table_message(
35  message::Table *table_message,
36  const char* fkey_name,
37  List<Key_part_spec> &cols,
38  Table_ident *table,
39  List<Key_part_spec> &ref_cols,
40  message::Table::ForeignKeyConstraint::ForeignKeyOption delete_opt_arg,
41  message::Table::ForeignKeyConstraint::ForeignKeyOption update_opt_arg,
42  message::Table::ForeignKeyConstraint::ForeignKeyMatchOption match_opt_arg)
43 {
44  message::Table::ForeignKeyConstraint *pfkey= table_message->add_fk_constraint();
45  if (fkey_name)
46  pfkey->set_name(fkey_name);
47  else if (table_message->has_name())
48  {
49  std::string name(table_message->name());
50  char number[20];
51 
52  name.append("_ibfk_");
53  snprintf(number, sizeof(number), "%d", table_message->fk_constraint_size());
54  name.append(number);
55 
56  pfkey->set_name(name);
57  }
58 
59  pfkey->set_match(match_opt_arg);
60  pfkey->set_update_option(update_opt_arg);
61  pfkey->set_delete_option(delete_opt_arg);
62  pfkey->set_references_table_name(table->table.data());
63 
64  List<Key_part_spec>::iterator col_it(cols.begin());
65  while (Key_part_spec* keypart= col_it++)
66  {
67  pfkey->add_column_names(keypart->field_name.data());
68  }
69 
70  List<Key_part_spec>::iterator ref_it(ref_cols.begin());
71  while (Key_part_spec* keypart= ref_it++)
72  {
73  pfkey->add_references_columns(keypart->field_name.data());
74  }
75 
76 }
77 
93 template <typename T>
95 {
96  /* Make a deep copy of each element */
97  typename List<T>::iterator it(list.begin());
98  while (T* el= it++)
99  it.replace(el->clone(mem_root));
100 }
101 
102 Foreign_key::Foreign_key(const Foreign_key &rhs, memory::Root *mem_root)
103  :Key(rhs),
104  ref_table(rhs.ref_table),
105  ref_columns(rhs.ref_columns),
106  delete_opt(rhs.delete_opt),
107  update_opt(rhs.update_opt),
108  match_opt(rhs.match_opt)
109 {
110  list_copy_and_replace_each_value(ref_columns, mem_root);
111 }
112 
113 /*
114  Test if a foreign key (= generated key) is a prefix of the given key
115  (ignoring key name, key type and order of columns)
116 
117  NOTES:
118  This is only used to test if an index for a FOREIGN KEY exists
119 
120  IMPLEMENTATION
121  We only compare field names
122 
123  RETURN
124  0 Generated key is a prefix of other key
125  1 Not equal
126 */
127 bool foreign_key_prefix(Key *a, Key *b)
128 {
129  /* Ensure that 'a' is the generated key */
130  if (a->generated)
131  {
132  if (b->generated && a->columns.size() > b->columns.size())
133  std::swap(a, b); // Put shorter key in 'a'
134  }
135  else
136  {
137  if (!b->generated)
138  return true; // No foreign key
139  std::swap(a, b); // Put generated key in 'a'
140  }
141 
142  /* Test if 'a' is a prefix of 'b' */
143  if (a->columns.size() > b->columns.size())
144  return true; // Can't be prefix
145 
146  List<Key_part_spec>::iterator col_it1(a->columns.begin());
147  List<Key_part_spec>::iterator col_it2(b->columns.begin());
148  const Key_part_spec *col1, *col2;
149 
150 #ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
151  while ((col1= col_it1++))
152  {
153  bool found= 0;
154  col_it2=b->columns.begin();
155  while ((col2= col_it2++))
156  {
157  if (*col1 == *col2)
158  {
159  found= true;
160  break;
161  }
162  }
163  if (!found)
164  return true; // Error
165  }
166  return false; // Is prefix
167 #else
168  while ((col1= col_it1++))
169  {
170  col2= col_it2++;
171  if (!(*col1 == *col2))
172  return true;
173  }
174  return false; // Is prefix
175 #endif
176 }
177 
178 /*
179  Check if the foreign key options are compatible with columns
180  on which the FK is created.
181 
182  RETURN
183  0 Key valid
184  1 Key invalid
185 */
186 bool Foreign_key::validate(List<CreateField> &table_fields)
187 {
188  List<Key_part_spec>::iterator cols(columns.begin());
189  while (Key_part_spec* column= cols++)
190  {
191  List<CreateField>::iterator it= table_fields.begin();
192  CreateField* sql_field;
193  while ((sql_field= it++)
194  && system_charset_info->strcasecmp(column->field_name.data(), sql_field->field_name))
195  {
196  }
197  if (!sql_field)
198  {
199  my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.data());
200  return true;
201  }
202  }
203  return false;
204 }
205 
206 } /* namespace drizzled */