1 /* Copyright (c) 2019, 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 #ifndef SQL_CHECK_CONSTRAINT_INCLUDED
24 #define SQL_CHECK_CONSTRAINT_INCLUDED
25 
26 #include "lex_string.h"          // LEX_STRING
27 #include "sql/mem_root_array.h"  // Mem_root_array
28 
29 class Alter_column;
30 class Alter_drop;
31 class Create_field;
32 class Item;
33 class String;
34 struct TABLE;
35 class THD;
36 class Value_generator;
37 
38 /**
39   Class to represent the check constraint specifications obtained from the SQL
40   statement parse.
41 */
42 class Sql_check_constraint_spec {
43  public:
44   /**
45     Validate check constraint name, perform per item-type to check if the
46     expression is allowed for the check constraint. Check expression is
47     pre-validated at this stage. Validation of specific functions in expression
48     is done later in the method open_table_from_share.
49 
50     @retval  false  Success.
51     @retval  true   Failure.
52   */
53   bool pre_validate();
54 
55   /**
56     Write check constraint expression into a String with proper syntax.
57 
58     @param[in]   thd   Thread handle.
59     @param[out]  out   Check constraint expression.
60   */
61   void print_expr(THD *thd, String &out);
62 
63   /**
64     Method to check if column "column_name" referred in the check constraint
65     expression.
66 
67     @param[in]  column_name   Column name.
68 
69     @retval     true       If column name is referenced in the check expression.
70     @retval     false      Otherwise.
71   */
72   bool expr_refers_column(const char *column_name);
73 
74  public:
75   /// Name of the check constraint.
76   LEX_STRING name{nullptr, 0};
77 
78   /// Check constraint expression.
79   Item *check_expr{nullptr};
80 
81   /// Name of the column if check clause is defined at the column level.
82   LEX_STRING column_name{nullptr, 0};
83 
84   /// Check constraint state (enforced/not enforced)
85   bool is_enforced{true};
86 
87   /**
88     During ALTER TABLE operation, the state of the Sql_check_constraint_spec
89     instance(s) is set to alter mode in new table definition. In this
90     mode, alias_name is stored to data-dictionary tables to avoid name
91     conflicts. The name of the check constraint is updated to actual name after
92     older table version is either dropped or when new version of table is
93     renamed to actual table name.
94   */
95   bool is_alter_mode{false};
96 
97   /// Alias name for check constraints.
98   LEX_STRING alias_name{nullptr, 0};
99 };
100 
101 /**
102   Class to represent check constraint in the TABLE_SHARE.
103 
104   The instance of Sql_check_constraint_share contains information as name,
105   state and expression in string form. These informations are filled from
106   the data-dictionary. The check expression is not in itemized (materialized)
107   form here.
108 */
109 class Sql_check_constraint_share {
110  public:
111   Sql_check_constraint_share() = default;
112 
Sql_check_constraint_share(const LEX_CSTRING & name,const LEX_CSTRING & expr_str,bool is_enforced)113   Sql_check_constraint_share(const LEX_CSTRING &name,
114                              const LEX_CSTRING &expr_str, bool is_enforced)
115       : m_name(name), m_expr_str(expr_str), m_is_enforced(is_enforced) {}
116 
117   /// Constraint name.
name()118   LEX_CSTRING &name() { return m_name; }
119   /// Check expression in string form.
expr_str()120   LEX_CSTRING &expr_str() { return m_expr_str; }
121   /// Check constraint state (enforced / not enforced)
is_enforced()122   bool is_enforced() { return m_is_enforced; }
123 
124  private:
125   /// Check constraint name.
126   LEX_CSTRING m_name{nullptr, 0};
127 
128   /// Check constraint expression.
129   LEX_CSTRING m_expr_str{nullptr, 0};
130 
131   /// Check constraint state.
132   bool m_is_enforced{true};
133 };
134 
135 /**
136   Class to represent check constraint in the TABLE instance.
137 
138   The Sql_table_check_constraint is a Sql_check_constraint_share with reference
139   to the parent TABLE instance and itemized (materialized) form of check
140   constraint expression.
141   Sql_table_check_constraint is prepared from the Sql_check_constraint_share of
142   TABLE_SHARE instance.
143 */
144 class Sql_table_check_constraint : public Sql_check_constraint_share {
145  public:
146   Sql_table_check_constraint() = default;
147 
Sql_table_check_constraint(const LEX_CSTRING & name,const LEX_CSTRING & expr_str,bool is_enforced,Value_generator * val_gen,TABLE * table)148   Sql_table_check_constraint(const LEX_CSTRING &name,
149                              const LEX_CSTRING &expr_str, bool is_enforced,
150                              Value_generator *val_gen, TABLE *table)
151       : Sql_check_constraint_share(name, expr_str, is_enforced),
152         m_val_gen(val_gen),
153         m_table(table) {}
154 
155   /// Value generator.
value_generator()156   Value_generator *value_generator() { return m_val_gen; }
set_value_generator(Value_generator * val_gen)157   void set_value_generator(Value_generator *val_gen) { m_val_gen = val_gen; }
158 
159   /// Reference to owner table.
table()160   TABLE *table() const { return m_table; }
161 
162  private:
163   /// Value generator for the check constraint expression.
164   Value_generator *m_val_gen{nullptr};
165 
166   /// Parent table reference.
167   TABLE *m_table{nullptr};
168 };
169 
170 /// Type for the list of Sql_check_constraint_spec elements.
171 using Sql_check_constraint_spec_list =
172     Mem_root_array<Sql_check_constraint_spec *>;
173 
174 /// Type for the list of Sql_check_constraint_share elements.
175 using Sql_check_constraint_share_list =
176     Mem_root_array<Sql_check_constraint_share>;
177 
178 /// Type for the list of Sql_table_check_constraint elements.
179 using Sql_table_check_constraint_list =
180     Mem_root_array<Sql_table_check_constraint>;
181 
182 /**
183   Method to check if server is a slave server and master server is on a
184   version not supporting check constraints feature. Check constraint support
185   is introduced in server version 80016.
186 
187   Method is used by methods prepare_check_constraints_for_create() and
188   prepare_check_constraints_for_alter(). Check constraints are not prepared
189   (and specification list is cleared) when this method returns to true.
190   In older versions, check constraint syntax was supported but check constraint
191   feature was not supported. So if master is on older version and slave gets
192   event with check constraint syntax then on slave supporting check constraint,
193   query is parsed but during prepare time the specifications are ignored
194   for the statement(event).
195 
196   @retval  true   if server is a slave server and master server is on a version
197                   not supporting check constraints feature.
198   @retval  false  Otherwise.
199 */
200 bool is_slave_with_master_without_check_constraints_support(THD *thd);
201 
202 /**
203   Check if constraint expression refers to only "column_name" column of the
204   table.
205 
206   @param[in]  check_expr    Check constraint expression.
207   @param[in]  column_name   Column name.
208 
209   @retval     true       If expression refers to only "column_name".
210   @retval     false      If expression refers to more than one column
211                          or if expression does not refers to "column_name".
212 */
213 bool check_constraint_expr_refers_to_only_column(Item *check_expr,
214                                                  const char *column_name);
215 
216 /**
217   Helper class to check if column being dropped or removed in ALTER statement
218   is in use by Check constraints.
219 */
220 class Check_constraint_column_dependency_checker {
221  public:
Check_constraint_column_dependency_checker(const Sql_check_constraint_spec_list & check_constraint_list)222   explicit Check_constraint_column_dependency_checker(
223       const Sql_check_constraint_spec_list &check_constraint_list)
224       : m_check_constraint_list(check_constraint_list) {}
225 
226   /**
227     Method to check if column being dropped is in use by check constraints.
228 
229     @param   drop    Instance of Alter_drop.
230 
231     @retval  true    If some check constraint uses the column being dropped.
232     @retval  false   Otherwise.
233   */
234   bool operator()(const Alter_drop *drop);
235 
236   /**
237     Method to check if column being renamed using RENAME COLUMN clause of the
238     ALTER TABLE statement is in use by check constraints.
239 
240     @param   alter_column   Instance of Alter_column.
241 
242     @retval  true    If some check constraint uses the column being renamed.
243     @retval  false   Otherwise.
244   */
245   bool operator()(const Alter_column *alter_column);
246 
247   /**
248     Method to check if column being renamed using CHANGE [COLUMN] clause of the
249     ALTER TABLE statement is in use by check constraints.
250 
251     @param   fld     Instance of Create_field.
252 
253     @retval  true    If some check constraint uses the column being renamed.
254     @retval  false   Otherwise.
255   */
256   bool operator()(const Create_field &fld);
257 
258  private:
259   /**
260     Check if any check constraint uses "column_name".
261 
262     @param   column_name  Column name.
263 
264     @retval  true         If column is used by the check constraint.
265     @retval  false        Otherwise.
266   */
267   bool any_check_constraint_uses_column(const char *column_name);
268 
269  private:
270   /// Check constraint specification list.
271   const Sql_check_constraint_spec_list &m_check_constraint_list;
272 };
273 #endif  // SQL_CHECK_CONSTRAINT_INCLUDED
274