~drizzle-trunk/drizzle/development

934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
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
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
20
#include <config.h>
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
21
22
#include <string>
23
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
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>
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
29
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
30
namespace drizzled
31
{
1253.1.3 by Monty Taylor
MEM_ROOT == memory::Root
32
2254 by Brian Aker
Shift CHARSET_INFO to charset_info_st
33
extern const charset_info_st *system_charset_info;
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
34
1638.10.78 by Stewart Smith
separate out adding the foreign key to the table protobuf message from mysql_prepare_create_table and call a function to do it directly from the parser where we set up the foreign key structures
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);
1638.10.80 by Stewart Smith
fix storing and manipulating foreign keys in the proto around ALTER TABLE, CREATE TABLE and ALTER TABLE ADD/DROP FOREIGN KEY. We also (mostly) emulate the naming of innodb foreign keys in the upper layer.
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
  }
1638.10.78 by Stewart Smith
separate out adding the foreign key to the table protobuf message from mysql_prepare_create_table and call a function to do it directly from the parser where we set up the foreign key structures
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;
2183.2.10 by Olaf van der Spek
Use List::begin()
67
  List<Key_part_spec>::iterator col_it(cols.begin());
1638.10.78 by Stewart Smith
separate out adding the foreign key to the table protobuf message from mysql_prepare_create_table and call a function to do it directly from the parser where we set up the foreign key structures
68
  while ((keypart= col_it++))
69
  {
70
    pfkey->add_column_names(keypart->field_name.str);
71
  }
72
2183.2.10 by Olaf van der Spek
Use List::begin()
73
  List<Key_part_spec>::iterator ref_it(ref_cols.begin());
1638.10.78 by Stewart Smith
separate out adding the foreign key to the table protobuf message from mysql_prepare_create_table and call a function to do it directly from the parser where we set up the foreign key structures
74
  while ((keypart= ref_it++))
75
  {
76
    pfkey->add_references_columns(keypart->field_name.str);
77
  }
78
79
}
80
2201.1.2 by Olaf van der Spek
Fix EOL
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
  T *el;
102
  while ((el= it++))
103
    it.replace(el->clone(mem_root));
104
}
2183.2.24 by Olaf van der Spek
Remove inline keyword
105
1253.1.3 by Monty Taylor
MEM_ROOT == memory::Root
106
Foreign_key::Foreign_key(const Foreign_key &rhs, memory::Root *mem_root)
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
107
  :Key(rhs),
108
  ref_table(rhs.ref_table),
109
  ref_columns(rhs.ref_columns),
110
  delete_opt(rhs.delete_opt),
111
  update_opt(rhs.update_opt),
112
  match_opt(rhs.match_opt)
113
{
114
  list_copy_and_replace_each_value(ref_columns, mem_root);
115
}
116
117
/*
118
  Test if a foreign key (= generated key) is a prefix of the given key
119
  (ignoring key name, key type and order of columns)
120
121
  NOTES:
122
    This is only used to test if an index for a FOREIGN KEY exists
123
124
  IMPLEMENTATION
125
    We only compare field names
126
127
  RETURN
128
    0	Generated key is a prefix of other key
129
    1	Not equal
130
*/
131
bool foreign_key_prefix(Key *a, Key *b)
132
{
133
  /* Ensure that 'a' is the generated key */
134
  if (a->generated)
135
  {
2183.2.17 by Olaf van der Spek
Use List::size()
136
    if (b->generated && a->columns.size() > b->columns.size())
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
137
      std::swap(a, b);                       // Put shorter key in 'a'
138
  }
139
  else
140
  {
141
    if (!b->generated)
142
      return true;                              // No foreign key
143
    std::swap(a, b);                       // Put generated key in 'a'
144
  }
145
146
  /* Test if 'a' is a prefix of 'b' */
2183.2.17 by Olaf van der Spek
Use List::size()
147
  if (a->columns.size() > b->columns.size())
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
148
    return true;                                // Can't be prefix
149
2183.2.10 by Olaf van der Spek
Use List::begin()
150
  List<Key_part_spec>::iterator col_it1(a->columns.begin());
151
  List<Key_part_spec>::iterator col_it2(b->columns.begin());
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
152
  const Key_part_spec *col1, *col2;
153
154
#ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
155
  while ((col1= col_it1++))
156
  {
157
    bool found= 0;
2179.1.6 by Olaf van der Spek
x
158
    col_it2=b->columns.begin();
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
159
    while ((col2= col_it2++))
160
    {
161
      if (*col1 == *col2)
162
      {
163
        found= true;
164
	break;
165
      }
166
    }
167
    if (!found)
168
      return true;                              // Error
169
  }
170
  return false;                                 // Is prefix
171
#else
172
  while ((col1= col_it1++))
173
  {
174
    col2= col_it2++;
175
    if (!(*col1 == *col2))
176
      return true;
177
  }
178
  return false;                                 // Is prefix
179
#endif
180
}
181
182
/*
183
  Check if the foreign key options are compatible with columns
184
  on which the FK is created.
185
186
  RETURN
187
    0   Key valid
188
    1   Key invalid
189
*/
1052.2.3 by Nathan Williams
No actual code changes. Changed Create_field to CreateField to be consistent with coding standards.
190
bool Foreign_key::validate(List<CreateField> &table_fields)
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
191
{
1052.2.3 by Nathan Williams
No actual code changes. Changed Create_field to CreateField to be consistent with coding standards.
192
  CreateField  *sql_field;
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
193
  Key_part_spec *column;
2183.2.10 by Olaf van der Spek
Use List::begin()
194
  List<Key_part_spec>::iterator cols(columns.begin());
195
  List<CreateField>::iterator it(table_fields.begin());
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
196
  while ((column= cols++))
197
  {
2183.2.1 by Olaf van der Spek
x
198
    it= table_fields.begin();
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
199
    while ((sql_field= it++) &&
200
           my_strcasecmp(system_charset_info,
201
                         column->field_name.str,
202
                         sql_field->field_name)) {}
203
    if (!sql_field)
204
    {
205
      my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
206
      return true;
207
    }
208
  }
209
  return false;
210
}
211
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
212
} /* namespace drizzled */