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