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