1 /* Copyright (c) 2017, 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 DD_SYSTEM_VIEWS__SYSTEM_VIEW_DEFINITION_IMPL_INCLUDED 24 #define DD_SYSTEM_VIEWS__SYSTEM_VIEW_DEFINITION_IMPL_INCLUDED 25 26 #include <map> 27 #include <memory> 28 #include <vector> 29 30 #include "sql/dd/string_type.h" // dd::String_type 31 #include "sql/dd/types/system_view_definition.h" // dd::System_view_definition 32 #include "sql/mysqld.h" // lower_case_table_names 33 34 namespace dd { 35 namespace system_views { 36 37 class System_view_definition_impl : public System_view_definition { 38 public: 39 /** 40 Get view name. 41 42 @return name of the view. 43 */ view_name()44 virtual const String_type &view_name() const { return m_view_name; } 45 46 /** 47 Set view name. 48 */ set_view_name(const String_type & name)49 virtual void set_view_name(const String_type &name) { m_view_name = name; } 50 51 /** 52 Get collation clause to append to view definition for some 53 view columns based on lower_case_table_names. 54 55 @return Empty string if lctn=0, other wise " COLLATE utf8_tolower_ci". 56 */ fs_name_collation()57 static const String_type fs_name_collation() { 58 if (lower_case_table_names != 0) return " COLLATE utf8_tolower_ci"; 59 return ""; 60 } 61 62 virtual String_type build_ddl_create_view() const = 0; 63 64 private: 65 // Name of I_S system view; 66 String_type m_view_name; 67 }; 68 69 class System_view_select_definition_impl : public System_view_definition_impl { 70 public: 71 /** 72 Add a field definition for the SELECT projection. 73 This function can be called more than once. The call will add a new 74 projection to the SELECT command. 75 76 @param field_number Ordinal position of field in the projection list. 77 @param field_name Field name used for the SELECT's projection. 78 @param field_definition Expression representing the projection. 79 @param add_quotes If true, output single quotes around the 80 field_definition. 81 */ 82 virtual void add_field(int field_number, const String_type &field_name, 83 const String_type &field_definition, 84 bool add_quotes = false) { 85 // Make sure the field_number and field_name are not added twise. 86 DBUG_ASSERT(m_field_numbers.find(field_name) == m_field_numbers.end() && 87 m_field_definitions.find(field_number) == 88 m_field_definitions.end()); 89 90 // Store the field number. 91 m_field_numbers[field_name] = field_number; 92 93 // Store the field definition expression. 94 Stringstream_type ss; 95 if (field_name == "*") { 96 ss << " * "; 97 } else { 98 if (add_quotes) { 99 DBUG_ASSERT(field_definition.find('\'') == String_type::npos); 100 ss << '\'' << field_definition << '\''; 101 } else 102 ss << field_definition; 103 104 ss << " AS " << field_name; 105 } 106 107 m_field_definitions[field_number] = ss.str(); 108 } 109 110 /** 111 Add FROM clause for the SELECT. 112 This function can be called more than once. The clause will be appended to 113 the previous FROM clause string. 114 115 @param from String representing the FROM clause. 116 */ add_from(const String_type & from)117 virtual void add_from(const String_type &from) { 118 m_from_clauses.push_back(from); 119 } 120 121 /** 122 Add WHERE clause for the SELECT. 123 This function can be called more than once. The clause will be appended to 124 the previous WHERE clause string. 125 126 @param where String representing the WHERE clause. 127 */ add_where(const String_type & where)128 virtual void add_where(const String_type &where) { 129 m_where_clauses.push_back(where); 130 } 131 132 /** 133 Add CTE expression before SELECT. 134 135 @param cte String representing the CTE expression. 136 */ add_cte_expression(const String_type & cte)137 virtual void add_cte_expression(const String_type &cte) { 138 m_cte_expression = cte; 139 } 140 141 /** 142 Indicates that we should add DISTINCT clause to SELECT. 143 */ add_distinct()144 virtual void add_distinct() { m_is_distinct = true; } 145 146 /** 147 Indicates selection of all field (SELECT '*'). 148 */ add_star()149 virtual void add_star() { m_add_star = true; } 150 /** 151 Get the field ordinal position number for the given field name. 152 153 @param field_name Column name for which the field number is returned. 154 155 @return Integer representing position of column in projection list. 156 */ field_number(const String_type & field_name)157 virtual int field_number(const String_type &field_name) const { 158 DBUG_ASSERT(m_field_numbers.find(field_name) != m_field_numbers.end()); 159 return m_field_numbers.find(field_name)->second; 160 } 161 162 /** 163 Build the SELECT query that is used in the CREATE VIEW command. 164 165 @return The SELECT query string. 166 */ build_select_query()167 String_type build_select_query() const { 168 Stringstream_type ss; 169 170 if (!m_cte_expression.empty()) ss << m_cte_expression << "\n "; 171 172 // Make SELECT [DISTINCT] 173 ss << "SELECT " << (m_is_distinct ? "DISTINCT \n" : "\n"); 174 175 if (!m_add_star) { 176 // Output view column definitions 177 for (Field_definitions::const_iterator field = 178 m_field_definitions.begin(); 179 field != m_field_definitions.end(); ++field) { 180 if (field != m_field_definitions.begin()) ss << ",\n"; 181 ss << " " << field->second; 182 } 183 } else 184 ss << "*"; 185 186 // Output FROM clauses 187 for (From_clauses::const_iterator from = m_from_clauses.begin(); 188 from != m_from_clauses.end(); ++from) { 189 if (from == m_from_clauses.begin()) ss << " FROM "; 190 191 ss << "\n " << *from; 192 } 193 194 // Output WHERE clauses 195 for (Where_clauses::const_iterator where = m_where_clauses.begin(); 196 where != m_where_clauses.end(); ++where) { 197 if (where == m_where_clauses.begin()) ss << " WHERE "; 198 199 ss << "\n " << *where; 200 } 201 202 ss << "\n"; 203 204 return ss.str(); 205 } 206 build_ddl_create_view()207 virtual String_type build_ddl_create_view() const { 208 Stringstream_type ss; 209 ss << "CREATE OR REPLACE DEFINER=`mysql.infoschema`@`localhost` VIEW " 210 << "information_schema." << view_name() << " AS " + build_select_query(); 211 212 return ss.str(); 213 } 214 215 private: 216 // Map of field_names and the ordinal position in SELECT projection. 217 typedef std::map<String_type, int> Field_numbers; 218 219 // Map of field ordinal position and their view column definition. 220 typedef std::map<int, String_type> Field_definitions; 221 222 // List of FROM clause definintion in the SELECT 223 typedef std::vector<String_type> From_clauses; 224 225 // List of WHERE clause definition in the SELECT 226 typedef std::vector<String_type> Where_clauses; 227 228 Field_numbers m_field_numbers; 229 Field_definitions m_field_definitions; 230 From_clauses m_from_clauses; 231 Where_clauses m_where_clauses; 232 dd::String_type m_cte_expression; 233 bool m_is_distinct{false}; 234 bool m_add_star{false}; 235 }; 236 237 // This class is unused and kept here for future use. 238 class System_view_union_definition_impl : public System_view_definition_impl { 239 public: 240 /** 241 Get the object for a SELECT definition to be used in the UNION. 242 243 @return The System_view_select_definition_impl&. 244 */ get_select()245 System_view_select_definition_impl &get_select() { 246 m_selects.push_back( 247 Select_definition(new System_view_select_definition_impl)); 248 return *(m_selects.back().get()); 249 } 250 build_ddl_create_view()251 virtual String_type build_ddl_create_view() const { 252 Stringstream_type ss; 253 bool first_select = true; 254 // Union definition must have minimum two SELECTs. 255 DBUG_ASSERT(m_selects.size() >= 2); 256 257 for (auto &select : m_selects) { 258 if (first_select) { 259 ss << "CREATE OR REPLACE DEFINER=`mysql.infoschema`@`localhost` VIEW " 260 << "information_schema." << view_name() << " AS " 261 << "(" << select->build_select_query() << ")"; 262 first_select = false; 263 } else { 264 ss << " UNION " 265 << "(" << select->build_select_query() << ")"; 266 } 267 } 268 269 return ss.str(); 270 } 271 272 private: 273 using Select_definition = std::unique_ptr<System_view_select_definition_impl>; 274 275 // Member holds SELECT's used for the UNION 276 std::vector<Select_definition> m_selects; 277 }; 278 279 } // namespace system_views 280 } // namespace dd 281 282 #endif // DD_SYSTEM_VIEWS__SYSTEM_VIEW_DEFINITION_IMPL_INCLUDED 283