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