1 /* Copyright (c) 2016, 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/info_schema/show_query_builder.h"  // Select_lex_builder
24 
25 #include "m_string.h"  // STRING_WITH_LEN
26 #include "my_dbug.h"
27 #include "sql/auth/sql_security_ctx.h"
28 #include "sql/item_cmpfunc.h"  // Item_func_like
29 #include "sql/item_func.h"
30 #include "sql/key.h"
31 #include "sql/key_spec.h"
32 #include "sql/parse_location.h"
33 #include "sql/parse_tree_helpers.h"
34 #include "sql/parse_tree_items.h"  // PTI_simple_ident_ident
35 #include "sql/parse_tree_node_base.h"
36 #include "sql/parse_tree_nodes.h"  // PT_select_item_list
37 #include "sql/query_options.h"     // OPTION_SELECT_FOR_SHOW
38 #include "sql/sql_class.h"
39 #include "sql/sql_lex.h"  // Query_options
40 #include "sql/strfunc.h"
41 #include "sql_string.h"
42 
43 class Item;
44 
45 namespace dd {
46 namespace info_schema {
47 
48 static const Query_options options = {
49     OPTION_SELECT_FOR_SHOW /* query_spec_options */
50 };
51 
Select_lex_builder(const POS * pc,THD * thd)52 Select_lex_builder::Select_lex_builder(const POS *pc, THD *thd)
53     : m_pos(pc),
54       m_thd(thd),
55       m_select_item_list(nullptr),
56       m_where_clause(nullptr),
57       m_order_by_list(nullptr) {
58   m_table_reference_list.init(m_thd->mem_root);
59 }
60 
add_to_select_item_list(Item * expr)61 bool Select_lex_builder::add_to_select_item_list(Item *expr) {
62   // Prepare list if not exist.
63   if (!m_select_item_list) {
64     m_select_item_list = new (m_thd->mem_root) PT_select_item_list();
65 
66     if (m_select_item_list == nullptr) return true;
67   }
68 
69   m_select_item_list->push_back(expr);
70 
71   return false;
72 }
73 
74 // Add item representing star in "SELECT '*' ...".
add_star_select_item()75 bool Select_lex_builder::add_star_select_item() {
76   Item_asterisk *ident_star =
77       new (m_thd->mem_root) Item_asterisk(*m_pos, nullptr, nullptr);
78   if (ident_star == nullptr) return true;
79 
80   return add_to_select_item_list(ident_star);
81 }
82 
83 /**
84   Add item representing a column as,
85   "SELECT <field_name> AS <alias>, ...".
86 */
add_select_item(const LEX_CSTRING & field_name,const LEX_CSTRING & alias)87 bool Select_lex_builder::add_select_item(const LEX_CSTRING &field_name,
88                                          const LEX_CSTRING &alias) {
89   /* ... FIELD_NAME ... */
90   PTI_simple_ident_ident *ident_field =
91       new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, field_name);
92   if (ident_field == nullptr) return true;
93 
94   /* ... FIELD_NAME as alias ... */
95   PTI_expr_with_alias *expr;
96   expr = new (m_thd->mem_root)
97       PTI_expr_with_alias(*m_pos, ident_field, m_pos->cpp, alias);
98   if (expr == nullptr) return true;
99 
100   return add_to_select_item_list(expr);
101 }
102 
103 /**
104   Add expression item representing a column as,
105   "SELECT <expr> AS <alias>, ...".
106 */
add_select_expr(Item * select_list_item,const LEX_CSTRING & alias)107 bool Select_lex_builder::add_select_expr(Item *select_list_item,
108                                          const LEX_CSTRING &alias) {
109   /* ... FIELD_NAME as alias ... */
110   PTI_expr_with_alias *expr = new (m_thd->mem_root)
111       PTI_expr_with_alias(*m_pos, select_list_item, m_pos->cpp, alias);
112   if (expr == nullptr) return true;
113 
114   return add_to_select_item_list(expr);
115 }
116 
117 /**
118   Add item representing a FROM clause table as,
119   @code
120   SELECT ... FROM <schema_name>.<table_name> ...
121   @endcode
122 */
add_from_item(const LEX_CSTRING & schema_name,const LEX_CSTRING & table_name)123 bool Select_lex_builder::add_from_item(const LEX_CSTRING &schema_name,
124                                        const LEX_CSTRING &table_name) {
125   /*
126     make_table_list() might alter the database and table name
127     strings. Create copies and leave the original values
128     unaltered.
129   */
130 
131   /* ... schame_name ... */
132   LEX_CSTRING tmp_db_name;
133   if (lex_string_strmake(m_thd->mem_root, &tmp_db_name, schema_name.str,
134                          schema_name.length))
135     return true;
136 
137   /* ... <table_name> ... */
138   LEX_CSTRING tmp_table_name;
139   if (lex_string_strmake(m_thd->mem_root, &tmp_table_name, table_name.str,
140                          table_name.length))
141     return true;
142 
143   /* ... schame_name.<table_name> ... */
144   Table_ident *table_ident =
145       new (m_thd->mem_root) Table_ident(tmp_db_name, tmp_table_name);
146   if (table_ident == nullptr) return true;
147 
148   /* ... FROM schame_name.<table_name> ... */
149   PT_table_factor_table_ident *table_factor = new (m_thd->mem_root)
150       PT_table_factor_table_ident(table_ident, nullptr, NULL_CSTR, nullptr);
151   if (table_factor == nullptr) return true;
152 
153   if (m_table_reference_list.push_back(table_factor)) return true;
154 
155   return false;
156 }
157 
158 /**
159   Add item representing a FROM clause table as,
160   @code
161   SELECT ... FROM <sub query or derived table> ...
162   @endcode
163  */
add_from_item(PT_derived_table * dt)164 bool Select_lex_builder::add_from_item(PT_derived_table *dt) {
165   if (m_table_reference_list.push_back(dt)) return true;
166 
167   return false;
168 }
169 
170 // Prepare item representing a LIKE condition.
prepare_like_item(const LEX_CSTRING & field_name,const String * wild)171 Item *Select_lex_builder::prepare_like_item(const LEX_CSTRING &field_name,
172                                             const String *wild) {
173   /* ... FIELD_NAME ... */
174   PTI_simple_ident_ident *ident_field =
175       new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, field_name);
176   if (ident_field == nullptr) return nullptr;
177 
178   /* ... <value> ... */
179   LEX_STRING *lex_string =
180       static_cast<LEX_STRING *>(m_thd->alloc(sizeof(LEX_STRING)));
181   if (lex_string == nullptr) return nullptr;
182   lex_string->length = wild->length();
183   lex_string->str = m_thd->strmake(wild->ptr(), wild->length());
184   if (lex_string->str == nullptr) return nullptr;
185 
186   PTI_text_literal_text_string *wild_string =
187       new (m_thd->mem_root) PTI_text_literal_text_string(
188           *m_pos, false, *lex_string);  // TODO WL#6629 check is_7bit
189   if (wild_string == nullptr) return nullptr;
190 
191   /* ... field_name LIKE <value> ... */
192   Item_func_like *func_like = new (m_thd->mem_root)
193       Item_func_like(*m_pos, ident_field, wild_string, nullptr);
194 
195   return func_like;
196 }
197 
198 // Prepare item representing a equal to comparision condition.
prepare_equal_item(const LEX_CSTRING & field_name,const LEX_CSTRING & value)199 Item *Select_lex_builder::prepare_equal_item(const LEX_CSTRING &field_name,
200                                              const LEX_CSTRING &value) {
201   /* ... FIELD_NAME ... */
202   PTI_simple_ident_ident *ident_field =
203       new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, field_name);
204   if (ident_field == nullptr) return nullptr;
205 
206   /* ... <value> ... */
207   LEX_STRING *lex_string =
208       static_cast<LEX_STRING *>(m_thd->alloc(sizeof(LEX_STRING)));
209   if (lex_string == nullptr) return nullptr;
210   lex_string->length = value.length;
211   lex_string->str = m_thd->strmake(value.str, value.length);
212   if (lex_string->str == nullptr) return nullptr;
213 
214   PTI_text_literal_underscore_charset *value_string =
215       new (m_thd->mem_root) PTI_text_literal_underscore_charset(
216           *m_pos, false, system_charset_info,
217           *lex_string);  // TODO WL#6629 check is_7bit
218   if (value_string == nullptr) return nullptr;
219 
220   /* ... FIELD_NAME = <value> ... */
221   Item_func_eq *func_eq =
222       new (m_thd->mem_root) Item_func_eq(*m_pos, ident_field, value_string);
223 
224   return func_eq;
225 }
226 
227 // Add a WHERE clause condition to Select_lex_builder.
add_condition(Item * a)228 bool Select_lex_builder::add_condition(Item *a) {
229   DBUG_ASSERT(a != nullptr);
230 
231   /* ... WHERE cond ... */
232   if (m_where_clause == nullptr) {
233     m_where_clause = a;
234   }
235   /* ... WHERE <cond> AND <cond> ... */
236   else {
237     m_where_clause =
238         flatten_associative_operator<Item_cond_and, Item_func::COND_AND_FUNC>(
239             m_thd->mem_root, *m_pos, m_where_clause, a);
240 
241     if (m_where_clause == nullptr) return true;
242   }
243 
244   return false;
245 }
246 
247 // Add a ORDER BY clause field to Select_lex_builder.
add_order_by(const LEX_CSTRING & field_name)248 bool Select_lex_builder::add_order_by(const LEX_CSTRING &field_name) {
249   /* ... ORDER BY <field_name> ASC... */
250   if (!m_order_by_list) {
251     m_order_by_list = new (m_thd->mem_root) PT_order_list();
252     if (m_order_by_list == nullptr) return true;
253   }
254 
255   /* ... FIELD_NAME ... */
256   PTI_simple_ident_ident *ident_field =
257       new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, field_name);
258   if (ident_field == nullptr) return true;
259 
260   PT_order_expr *expression =
261       new (m_thd->mem_root) PT_order_expr(ident_field, ORDER_ASC);
262   m_order_by_list->push_back(expression);
263 
264   return expression == nullptr;
265 }
266 
267 /**
268   This function build ParseTree node that represents this
269   Select_lex_builder as sub-query.
270 */
prepare_derived_table(const LEX_CSTRING & table_alias)271 PT_derived_table *Select_lex_builder::prepare_derived_table(
272     const LEX_CSTRING &table_alias) {
273   PT_query_primary *query_specification =
274       new (m_thd->mem_root) PT_query_specification(
275           options, m_select_item_list, m_table_reference_list, m_where_clause);
276 
277   if (query_specification == nullptr) return nullptr;
278 
279   PT_query_expression *query_expression =
280       new (m_thd->mem_root) PT_query_expression(query_specification);
281   if (query_expression == nullptr) return nullptr;
282 
283   PT_subquery *sub_query =
284       new (m_thd->mem_root) PT_subquery(*m_pos, query_expression);
285   if (sub_query == nullptr) return nullptr;
286 
287   Create_col_name_list column_names;
288   column_names.init(m_thd->mem_root);
289   PT_derived_table *derived_table = new (m_thd->mem_root)
290       PT_derived_table(false, sub_query, table_alias, &column_names);
291 
292   return derived_table;
293 }
294 
295 /**
296   Prepare a SELECT_LEX using all the information information
297   added to this Select_lex_builder.
298 */
prepare_select_lex()299 SELECT_LEX *Select_lex_builder::prepare_select_lex() {
300   PT_query_specification *query_specification =
301       new (m_thd->mem_root) PT_query_specification(
302           options, m_select_item_list, m_table_reference_list, m_where_clause);
303   if (query_specification == nullptr) return nullptr;
304 
305   PT_order *pt_order_by = nullptr;
306   if (m_order_by_list) {
307     pt_order_by = new (m_thd->mem_root) PT_order(m_order_by_list);
308     if (pt_order_by == nullptr) return nullptr;
309   }
310 
311   PT_query_expression *query_expression = new (m_thd->mem_root)
312       PT_query_expression(query_specification, pt_order_by, nullptr);
313   if (query_expression == nullptr) return nullptr;
314 
315   LEX *lex = m_thd->lex;
316   SELECT_LEX *current_select = lex->current_select();
317 
318   lex->sql_command = SQLCOM_SELECT;
319   Parse_context pc(m_thd, current_select);
320   if (m_thd->is_error()) return nullptr;
321 
322   if (query_expression->contextualize(&pc)) return nullptr;
323 
324   return current_select;
325 }
326 
327 }  // namespace info_schema
328 }  // namespace dd
329