~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
2430.2.4 by Olaf van der Spek
Use data()
30
namespace drizzled {
1253.1.3 by Monty Taylor
MEM_ROOT == memory::Root
31
2254 by Brian Aker
Shift CHARSET_INFO to charset_info_st
32
extern const charset_info_st *system_charset_info;
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
33
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
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);
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.
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
  }
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
58
59
  pfkey->set_match(match_opt_arg);
60
  pfkey->set_update_option(update_opt_arg);
61
  pfkey->set_delete_option(delete_opt_arg);
2430.2.4 by Olaf van der Spek
Use data()
62
  pfkey->set_references_table_name(table->table.data());
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
63
2183.2.10 by Olaf van der Spek
Use List::begin()
64
  List<Key_part_spec>::iterator col_it(cols.begin());
2433.1.1 by Olaf van der Spek
Refactor
65
  while (Key_part_spec* keypart= col_it++)
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
66
  {
2430.2.4 by Olaf van der Spek
Use data()
67
    pfkey->add_column_names(keypart->field_name.data());
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
  }
69
2183.2.10 by Olaf van der Spek
Use List::begin()
70
  List<Key_part_spec>::iterator ref_it(ref_cols.begin());
2433.1.1 by Olaf van der Spek
Refactor
71
  while (Key_part_spec* keypart= ref_it++)
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
72
  {
2430.2.4 by Olaf van der Spek
Use data()
73
    pfkey->add_references_columns(keypart->field_name.data());
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
  }
75
76
}
77
2201.1.2 by Olaf van der Spek
Fix EOL
78
/**
79
  Make a deep copy of each list element.
80
81
  @note A template function and not a template method of class List
82
  is employed because of explicit template instantiation:
83
  in server code there are explicit instantiations of List<T> and
84
  an explicit instantiation of a template requires that any method
85
  of the instantiated class used in the template can be resolved.
86
  Evidently not all template arguments have clone() method with
87
  the right signature.
88
89
  @return You must query the error state in Session for out-of-memory
90
  situation after calling this function.
91
*/
92
93
template <typename T>
94
void list_copy_and_replace_each_value(List<T> &list, memory::Root *mem_root)
95
{
96
  /* Make a deep copy of each element */
97
  typename List<T>::iterator it(list.begin());
2318.6.63 by Olaf van der Spek
Refactor
98
  while (T* el= it++)
2201.1.2 by Olaf van der Spek
Fix EOL
99
    it.replace(el->clone(mem_root));
100
}
2183.2.24 by Olaf van der Spek
Remove inline keyword
101
1253.1.3 by Monty Taylor
MEM_ROOT == memory::Root
102
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
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
  {
2183.2.17 by Olaf van der Spek
Use List::size()
132
    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
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' */
2183.2.17 by Olaf van der Spek
Use List::size()
143
  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
144
    return true;                                // Can't be prefix
145
2183.2.10 by Olaf van der Spek
Use List::begin()
146
  List<Key_part_spec>::iterator col_it1(a->columns.begin());
147
  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
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;
2179.1.6 by Olaf van der Spek
x
154
    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
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
*/
1052.2.3 by Nathan Williams
No actual code changes. Changed Create_field to CreateField to be consistent with coding standards.
186
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
187
{
2183.2.10 by Olaf van der Spek
Use List::begin()
188
  List<Key_part_spec>::iterator cols(columns.begin());
2433.1.1 by Olaf van der Spek
Refactor
189
  while (Key_part_spec* column= cols++)
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
190
  {
2433.1.1 by Olaf van der Spek
Refactor
191
    List<CreateField>::iterator it= table_fields.begin();
192
    CreateField* sql_field;
193
    while ((sql_field= it++) 
2456.1.4 by Olaf van der Spek
Refactor
194
      && system_charset_info->strcasecmp(column->field_name.data(), sql_field->field_name))
2433.1.1 by Olaf van der Spek
Refactor
195
    {
196
    }
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
197
    if (!sql_field)
198
    {
2430.2.4 by Olaf van der Spek
Use data()
199
      my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.data());
934.2.20 by Jay Pipes
Move Foreign_key implementation into its own implementation file and out of session.cc
200
      return true;
201
    }
202
  }
203
  return false;
204
}
205
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
206
} /* namespace drizzled */