1 /* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "sql/dd/impl/types/foreign_key_impl.h"
24
25 #include <stddef.h>
26 #include <sstream>
27 #include <string>
28
29 #include "my_rapidjson_size_t.h" // IWYU pragma: keep
30
31 #include <rapidjson/document.h>
32 #include <rapidjson/prettywriter.h>
33
34 #include "m_string.h"
35 #include "my_inttypes.h"
36 #include "my_sys.h"
37 #include "mysqld_error.h" // ER_*
38 #include "sql/dd/impl/raw/raw_record.h" // Raw_record
39 #include "sql/dd/impl/sdi_impl.h" // sdi read/write functions
40 #include "sql/dd/impl/tables/foreign_key_column_usage.h" // Foreign_key_column_usage
41 #include "sql/dd/impl/tables/foreign_keys.h" // Foreign_keys
42 #include "sql/dd/impl/transaction_impl.h" // Open_dictionary_tables_ctx
43 #include "sql/dd/impl/types/foreign_key_element_impl.h" // Foreign_key_element_impl
44 #include "sql/dd/impl/types/table_impl.h" // Table_impl
45 #include "sql/dd/impl/types/weak_object_impl.h"
46 #include "sql/dd/string_type.h" // dd::String_type
47 #include "sql/dd/types/foreign_key_element.h"
48 #include "sql/dd/types/index.h" // Index
49 #include "sql/dd/types/object_table.h"
50 #include "sql/dd/types/weak_object.h"
51 #include "sql/error_handler.h" // Internal_error_handler
52 #include "sql/sql_class.h"
53 #include "sql/sql_error.h"
54
55 using dd::tables::Foreign_key_column_usage;
56 using dd::tables::Foreign_keys;
57
58 namespace dd {
59
60 class Sdi_rcontext;
61 class Sdi_wcontext;
62
63 ///////////////////////////////////////////////////////////////////////////
64 // Foreign_key_impl implementation.
65 ///////////////////////////////////////////////////////////////////////////
66
Foreign_key_impl()67 Foreign_key_impl::Foreign_key_impl()
68 : m_match_option(OPTION_NONE),
69 m_update_rule(RULE_NO_ACTION),
70 m_delete_rule(RULE_NO_ACTION),
71 m_table(nullptr),
72 m_elements() {}
73
Foreign_key_impl(Table_impl * table)74 Foreign_key_impl::Foreign_key_impl(Table_impl *table)
75 : m_match_option(OPTION_NONE),
76 m_update_rule(RULE_NO_ACTION),
77 m_delete_rule(RULE_NO_ACTION),
78 m_table(table),
79 m_elements() {}
80
81 ///////////////////////////////////////////////////////////////////////////
82
table() const83 const Table &Foreign_key_impl::table() const { return *m_table; }
84
table()85 Table &Foreign_key_impl::table() { return *m_table; }
86
87 ///////////////////////////////////////////////////////////////////////////
88
89 class Foreign_key_name_error_handler : public Internal_error_handler {
90 const char *name;
91
92 public:
Foreign_key_name_error_handler(const char * name_arg)93 Foreign_key_name_error_handler(const char *name_arg) : name(name_arg) {}
94
handle_condition(THD *,uint sql_errno,const char *,Sql_condition::enum_severity_level *,const char *)95 virtual bool handle_condition(THD *, uint sql_errno, const char *,
96 Sql_condition::enum_severity_level *,
97 const char *) {
98 if (sql_errno == ER_DUP_ENTRY) {
99 my_error(ER_FK_DUP_NAME, MYF(0), name);
100 return true;
101 }
102 return false;
103 }
104 };
105
store(Open_dictionary_tables_ctx * otx)106 bool Foreign_key_impl::store(Open_dictionary_tables_ctx *otx) {
107 /*
108 Translate ER_DUP_ENTRY errors to the more user-friendly ER_FK_DUP_NAME.
109 We should not report ER_DUP_ENTRY in any other cases (that would be
110 a code bug).
111 */
112 Foreign_key_name_error_handler error_handler(name().c_str());
113 otx->get_thd()->push_internal_handler(&error_handler);
114 bool error = Weak_object_impl::store(otx);
115 otx->get_thd()->pop_internal_handler();
116 return error;
117 }
118
119 ///////////////////////////////////////////////////////////////////////////
120
validate() const121 bool Foreign_key_impl::validate() const {
122 if (!m_table) {
123 my_error(ER_INVALID_DD_OBJECT, MYF(0), DD_table::instance().name().c_str(),
124 "No table object associated with this foreign key.");
125 return true;
126 }
127
128 if (m_referenced_table_catalog_name.empty()) {
129 my_error(ER_INVALID_DD_OBJECT, MYF(0), DD_table::instance().name().c_str(),
130 "Referenced table catalog name is not set.");
131 return true;
132 }
133
134 if (m_referenced_table_schema_name.empty()) {
135 my_error(ER_INVALID_DD_OBJECT, MYF(0), DD_table::instance().name().c_str(),
136 "Referenced table schema name is not set.");
137 return true;
138 }
139
140 if (m_referenced_table_name.empty()) {
141 my_error(ER_INVALID_DD_OBJECT, MYF(0), DD_table::instance().name().c_str(),
142 "Referenced table name is not set.");
143 return true;
144 }
145
146 return false;
147 }
148
149 ///////////////////////////////////////////////////////////////////////////
150
restore_children(Open_dictionary_tables_ctx * otx)151 bool Foreign_key_impl::restore_children(Open_dictionary_tables_ctx *otx) {
152 return m_elements.restore_items(
153 this, otx, otx->get_table<Foreign_key_element>(),
154 Foreign_key_column_usage::create_key_by_foreign_key_id(this->id()));
155 }
156
157 ///////////////////////////////////////////////////////////////////////////
158
store_children(Open_dictionary_tables_ctx * otx)159 bool Foreign_key_impl::store_children(Open_dictionary_tables_ctx *otx) {
160 return m_elements.store_items(otx);
161 }
162
163 ///////////////////////////////////////////////////////////////////////////
164
drop_children(Open_dictionary_tables_ctx * otx) const165 bool Foreign_key_impl::drop_children(Open_dictionary_tables_ctx *otx) const {
166 return m_elements.drop_items(
167 otx, otx->get_table<Foreign_key_element>(),
168 Foreign_key_column_usage::create_key_by_foreign_key_id(this->id()));
169 }
170
171 ///////////////////////////////////////////////////////////////////////////
172
restore_attributes(const Raw_record & r)173 bool Foreign_key_impl::restore_attributes(const Raw_record &r) {
174 if (check_parent_consistency(m_table,
175 r.read_ref_id(Foreign_keys::FIELD_TABLE_ID)))
176 return true;
177
178 restore_id(r, Foreign_keys::FIELD_ID);
179 restore_name(r, Foreign_keys::FIELD_NAME);
180
181 m_unique_constraint_name =
182 r.read_str(Foreign_keys::FIELD_UNIQUE_CONSTRAINT_NAME, "");
183
184 m_match_option =
185 (enum_match_option)r.read_int(Foreign_keys::FIELD_MATCH_OPTION);
186 m_update_rule = (enum_rule)r.read_int(Foreign_keys::FIELD_UPDATE_RULE);
187 m_delete_rule = (enum_rule)r.read_int(Foreign_keys::FIELD_DELETE_RULE);
188
189 m_referenced_table_catalog_name =
190 r.read_str(Foreign_keys::FIELD_REFERENCED_TABLE_CATALOG);
191 m_referenced_table_schema_name =
192 r.read_str(Foreign_keys::FIELD_REFERENCED_TABLE_SCHEMA);
193 m_referenced_table_name = r.read_str(Foreign_keys::FIELD_REFERENCED_TABLE);
194
195 return false;
196 }
197
198 ///////////////////////////////////////////////////////////////////////////
199
store_attributes(Raw_record * r)200 bool Foreign_key_impl::store_attributes(Raw_record *r) {
201 return store_id(r, Foreign_keys::FIELD_ID) ||
202 r->store(Foreign_keys::FIELD_SCHEMA_ID, m_table->schema_id()) ||
203 r->store(Foreign_keys::FIELD_TABLE_ID, m_table->id()) ||
204 store_name(r, Foreign_keys::FIELD_NAME) ||
205 r->store(Foreign_keys::FIELD_UNIQUE_CONSTRAINT_NAME,
206 m_unique_constraint_name, m_unique_constraint_name.empty()) ||
207 r->store(Foreign_keys::FIELD_MATCH_OPTION, m_match_option) ||
208 r->store(Foreign_keys::FIELD_UPDATE_RULE, m_update_rule) ||
209 r->store(Foreign_keys::FIELD_DELETE_RULE, m_delete_rule) ||
210 r->store(Foreign_keys::FIELD_REFERENCED_TABLE_CATALOG,
211 m_referenced_table_catalog_name) ||
212 r->store(Foreign_keys::FIELD_REFERENCED_TABLE_SCHEMA,
213 m_referenced_table_schema_name) ||
214 r->store(Foreign_keys::FIELD_REFERENCED_TABLE,
215 m_referenced_table_name);
216 }
217
218 ///////////////////////////////////////////////////////////////////////////
219
220 static_assert(Foreign_keys::NUMBER_OF_FIELDS == 12,
221 "Foreign_keys definition has changed, check if serialize() and "
222 "deserialize() need to be updated!");
serialize(Sdi_wcontext * wctx,Sdi_writer * w) const223 void Foreign_key_impl::serialize(Sdi_wcontext *wctx, Sdi_writer *w) const {
224 w->StartObject();
225 Entity_object_impl::serialize(wctx, w);
226
227 write_enum(w, m_match_option, STRING_WITH_LEN("match_option"));
228 write_enum(w, m_update_rule, STRING_WITH_LEN("update_rule"));
229 write_enum(w, m_delete_rule, STRING_WITH_LEN("delete_rule"));
230
231 write(w, m_unique_constraint_name, STRING_WITH_LEN("unique_constraint_name"));
232
233 write(w, m_referenced_table_catalog_name,
234 STRING_WITH_LEN("referenced_table_catalog_name"));
235
236 write(w, m_referenced_table_schema_name,
237 STRING_WITH_LEN("referenced_table_schema_name"));
238
239 write(w, m_referenced_table_name, STRING_WITH_LEN("referenced_table_name"));
240
241 serialize_each(wctx, w, m_elements, STRING_WITH_LEN("elements"));
242 w->EndObject();
243 }
244
245 ///////////////////////////////////////////////////////////////////////////
246
deserialize(Sdi_rcontext * rctx,const RJ_Value & val)247 bool Foreign_key_impl::deserialize(Sdi_rcontext *rctx, const RJ_Value &val) {
248 Entity_object_impl::deserialize(rctx, val);
249 read_enum(&m_match_option, val, "match_option");
250 read_enum(&m_update_rule, val, "update_rule");
251 read_enum(&m_delete_rule, val, "delete_rule");
252
253 read(&m_unique_constraint_name, val, "unique_constraint_name");
254
255 read(&m_referenced_table_catalog_name, val, "referenced_table_catalog_name");
256 read(&m_referenced_table_schema_name, val, "referenced_table_schema_name");
257 read(&m_referenced_table_name, val, "referenced_table_name");
258 deserialize_each(
259 rctx, [this]() { return add_element(); }, val, "elements");
260 return false;
261 }
262
263 ///////////////////////////////////////////////////////////////////////////
264
265 /* purecov: begin inspected */
debug_print(String_type & outb) const266 void Foreign_key_impl::debug_print(String_type &outb) const {
267 dd::Stringstream_type ss;
268 ss << "FOREIGN_KEY OBJECT: { "
269 << "m_id: {OID: " << id() << "}; "
270 << "m_name: " << name() << "; "
271 << "m_unique_constraint_name: " << m_unique_constraint_name << "; "
272 << "m_match_option: " << m_match_option << "; "
273 << "m_update_rule: " << m_update_rule << "; "
274 << "m_delete_rule: " << m_delete_rule << "; ";
275
276 {
277 for (const Foreign_key_element *e : elements()) {
278 String_type ob;
279 e->debug_print(ob);
280 ss << ob;
281 }
282 }
283
284 ss << " }";
285
286 outb = ss.str();
287 }
288 /* purecov: end */
289
290 /////////////////////////////////////////////////////////////////////////
291
add_element()292 Foreign_key_element *Foreign_key_impl::add_element() {
293 Foreign_key_element_impl *e =
294 new (std::nothrow) Foreign_key_element_impl(this);
295 m_elements.push_back(e);
296 return e;
297 }
298
299 /////////////////////////////////////////////////////////////////////////
300
Foreign_key_impl(const Foreign_key_impl & src,Table_impl * parent)301 Foreign_key_impl::Foreign_key_impl(const Foreign_key_impl &src,
302 Table_impl *parent)
303 : Weak_object(src),
304 Entity_object_impl(src),
305 m_match_option(src.m_match_option),
306 m_update_rule(src.m_update_rule),
307 m_delete_rule(src.m_delete_rule),
308 m_unique_constraint_name(src.m_unique_constraint_name),
309 m_referenced_table_catalog_name(src.m_referenced_table_catalog_name),
310 m_referenced_table_schema_name(src.m_referenced_table_schema_name),
311 m_referenced_table_name(src.m_referenced_table_name),
312 m_table(parent),
313 m_elements() {
314 m_elements.deep_copy(src.m_elements, this);
315 }
316
317 ///////////////////////////////////////////////////////////////////////////
318
object_table() const319 const Object_table &Foreign_key_impl::object_table() const {
320 return DD_table::instance();
321 }
322
323 ///////////////////////////////////////////////////////////////////////////
324
register_tables(Open_dictionary_tables_ctx * otx)325 void Foreign_key_impl::register_tables(Open_dictionary_tables_ctx *otx) {
326 otx->add_table<Foreign_keys>();
327
328 otx->register_tables<Foreign_key_element>();
329 }
330
331 ///////////////////////////////////////////////////////////////////////////
332
333 } // namespace dd
334