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