1 /* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
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 
24 #include "sql_show_status.h"
25 #include "sql_parse.h"
26 #include "sql_yacc.h"
27 #include "parse_tree_items.h"
28 #include "parse_tree_nodes.h"
29 #include "item_cmpfunc.h"
30 
31 /**
32   Build a replacement query for SHOW STATUS.
33   When the parser accepts the following syntax:
34     SHOW GLOBAL STATUS
35   the parsed tree built for this query is in fact:
36   SELECT * FROM
37            (SELECT VARIABLE_NAME as Variable_name, VARIABLE_VALUE as Value
38             FROM performance_schema.global_status) global_status
39 
40   Likewise, the query:
41     SHOW GLOBAL STATUS LIKE "<value>"
42   is built as:
43   SELECT * FROM
44            (SELECT VARIABLE_NAME as Variable_name, VARIABLE_VALUE as Value
45             FROM performance_schema.global_status) global_status
46             WHERE Variable_name LIKE "<value>"
47 
48   Likewise, the query:
49     SHOW GLOBAL STATUS where <where_clause>
50   is built as:
51     SELECT * FROM
52              (SELECT VARIABLE_NAME as Variable_name, VARIABLE_VALUE as Value
53               FROM performance_schema.global_status) global_status
54               WHERE <where_clause>
55 */
56 SELECT_LEX*
build_query(const POS & pos,THD * thd,enum_sql_command command,const LEX_STRING & table_name,const String * wild,Item * where_cond)57 build_query(const POS &pos,
58             THD *thd,
59             enum_sql_command command,
60             const LEX_STRING& table_name,
61             const String *wild,
62             Item *where_cond)
63 {
64   /*
65     MAINTAINER:
66     This code builds a parsed tree for a query.
67     Write the query to build in SQL first,
68     then see turn_parser_debug_on() in sql_yacc.yy
69     to understand which grammar actions are needed to
70     build a parsed tree for this SQL query.
71   */
72   static const LEX_STRING col_name= { C_STRING_WITH_LEN("VARIABLE_NAME")};
73   static const LEX_STRING as_name= { C_STRING_WITH_LEN("Variable_name")};
74   static const LEX_STRING col_value= { C_STRING_WITH_LEN("VARIABLE_VALUE")};
75   static const LEX_STRING as_value= { C_STRING_WITH_LEN("Value")};
76   static const LEX_STRING pfs= { C_STRING_WITH_LEN("performance_schema")};
77 
78   static const Query_options options=
79   {
80     0, /* query_spec_options */
81     SELECT_LEX::SQL_CACHE_UNSPECIFIED /* sql_cache */
82   };
83 
84   static const Select_lock_type lock_type=
85   {
86     false, /* is_set */
87     TL_READ, /* lock_type */
88     false /* is_safe_to_cache_query */
89   };
90 
91 
92   /* * */
93   Item *star= new (thd->mem_root) Item_asterisk(pos, NULL, NULL);
94 
95   PT_select_item_list *item_list2;
96   item_list2= new (thd->mem_root) PT_select_item_list();
97   if (item_list2 == NULL)
98     return NULL;
99   item_list2->push_back(star);
100 
101   /* SELECT * ... */
102   PT_select_options_and_item_list *options_and_item_list2;
103   options_and_item_list2= new (thd->mem_root) PT_select_options_and_item_list(options, item_list2);
104   if (options_and_item_list2 == NULL)
105     return NULL;
106 
107 
108  /*
109     ... (SELECT VARIABLE_NAME as Variable_name, VARIABLE_VALUE as Value
110            FROM performance_schema.<table_name>) ...
111   */
112 
113   /* ... VARIABLE_NAME ... */
114   PTI_simple_ident_ident *ident_name;
115   ident_name= new (thd->mem_root) PTI_simple_ident_ident(pos, col_name);
116   if (ident_name == NULL)
117     return NULL;
118 
119   /* ... VARIABLE_NAME as Variable_name ... */
120   PTI_expr_with_alias *expr_name;
121   expr_name= new (thd->mem_root) PTI_expr_with_alias(pos, ident_name, pos.cpp, as_name);
122   if (expr_name == NULL)
123     return NULL;
124 
125   /* ... VARIABLE_VALUE ... */
126   PTI_simple_ident_ident *ident_value;
127   ident_value= new (thd->mem_root) PTI_simple_ident_ident(pos, col_value);
128   if (ident_value == NULL)
129     return NULL;
130 
131   /* ... VARIABLE_VALUE as Value ... */
132   PTI_expr_with_alias *expr_value;
133   expr_value= new (thd->mem_root) PTI_expr_with_alias(pos, ident_value, pos.cpp, as_value);
134   if (expr_value == NULL)
135     return NULL;
136 
137   /* ... VARIABLE_NAME as Variable_name, VARIABLE_VALUE as Value ... */
138   PT_select_item_list *item_list;
139   item_list= new (thd->mem_root) PT_select_item_list();
140   if (item_list == NULL)
141     return NULL;
142   item_list->push_back(expr_name);
143   item_list->push_back(expr_value);
144 
145   /* SELECT VARIABLE_NAME as Variable_name, VARIABLE_VALUE as Value ... */
146   PT_select_options_and_item_list *options_and_item_list;
147   options_and_item_list= new (thd->mem_root) PT_select_options_and_item_list(options, item_list);
148   if (options_and_item_list == NULL)
149     return NULL;
150 
151   /*
152     make_table_list() might alter the database and table name strings. Create
153     copies and leave the original values unaltered.
154   */
155 
156   /* ... performance_schema ... */
157   LEX_CSTRING tmp_db_name;
158   if (!thd->make_lex_string(&tmp_db_name, pfs.str, pfs.length, false))
159     return NULL;
160 
161   /* ... <table_name> ... */
162   LEX_CSTRING tmp_table_name;
163   if (!thd->make_lex_string(&tmp_table_name, table_name.str, table_name.length, false))
164     return NULL;
165 
166   /* ... performance_schema.<table_name> ... */
167   Table_ident *table_ident;
168   table_ident= new (thd->mem_root) Table_ident(tmp_db_name, tmp_table_name);
169   if (table_ident == NULL)
170     return NULL;
171 
172   /* ... FROM performance_schema.<table_name> ... */
173   PT_table_factor_table_ident *table_factor;
174   table_factor= new (thd->mem_root) PT_table_factor_table_ident(table_ident, NULL, NULL, NULL);
175   if (table_factor == NULL)
176     return NULL;
177 
178   PT_join_table_list *join_table_list;
179   join_table_list= new (thd->mem_root) PT_join_table_list(pos, table_factor);
180   if (join_table_list == NULL)
181     return NULL;
182 
183   PT_table_reference_list *table_reference_list;
184   table_reference_list= new (thd->mem_root) PT_table_reference_list(join_table_list);
185   if (table_reference_list == NULL)
186     return NULL;
187 
188   PT_table_expression *table_expression;
189   table_expression= new (thd->mem_root)PT_table_expression(table_reference_list,
190                                                            NULL,
191                                                            NULL,
192                                                            NULL,
193                                                            NULL,
194                                                            NULL,
195                                                            NULL,
196                                                            lock_type);
197 
198   /* ... FROM (SELECT ...) ... */
199   PT_table_factor_select_sym *table_factor_select_sym;
200   table_factor_select_sym= new (thd->mem_root) PT_table_factor_select_sym(pos, NULL, options, item_list, table_expression);
201   if (table_factor_select_sym == NULL)
202     return NULL;
203 
204   PT_select_derived *select_derived;
205   select_derived= new (thd->mem_root) PT_select_derived(pos, table_factor_select_sym);
206   if (select_derived == NULL)
207     return NULL;
208 
209   PT_select_derived_union_select *select_derived_union_select;
210   select_derived_union_select= new (thd->mem_root) PT_select_derived_union_select(select_derived, NULL, pos);
211   if (select_derived_union_select == NULL)
212     return NULL;
213 
214   /* ... derived_table ... */
215   LEX_STRING derived_table_name;
216   if (!thd->make_lex_string(&derived_table_name, table_name.str, table_name.length, false))
217     return NULL;
218 
219   PT_table_factor_parenthesis *table_factor_parenthesis;
220   table_factor_parenthesis= new (thd->mem_root) PT_table_factor_parenthesis(select_derived_union_select, &derived_table_name, pos);
221   if (table_factor_parenthesis == NULL)
222     return NULL;
223 
224   PT_join_table_list *join_table_list2;
225   join_table_list2= new (thd->mem_root) PT_join_table_list(pos, table_factor_parenthesis);
226   if (join_table_list2 == NULL)
227     return NULL;
228 
229   PT_table_reference_list *table_reference_list2;
230   table_reference_list2= new (thd->mem_root) PT_table_reference_list(join_table_list2);
231   if (table_reference_list2 == NULL)
232     return NULL;
233 
234   /* where clause */
235   Item *where_clause= NULL;
236 
237   if (wild != NULL)
238   {
239     /* ... Variable_name ... */
240     PTI_simple_ident_ident *ident_name_where;
241     ident_name_where= new (thd->mem_root) PTI_simple_ident_ident(pos, as_name);
242     if (ident_name_where == NULL)
243       return NULL;
244 
245     /* ... <value> ... */
246     LEX_STRING *lex_string;
247     lex_string= static_cast<LEX_STRING*> (thd->alloc(sizeof(LEX_STRING)));
248     if (lex_string == NULL)
249       return NULL;
250     lex_string->length= wild->length();
251     lex_string->str= thd->strmake(wild->ptr(), wild->length());
252     if (lex_string->str == NULL)
253       return NULL;
254 
255     PTI_text_literal_text_string *wild_string;
256     wild_string= new (thd->mem_root) PTI_text_literal_text_string(pos, false, *lex_string); // TODO WL#6629 check is_7bit
257     if (wild_string == NULL)
258       return NULL;
259 
260     /* ... Variable_name LIKE <value> ... */
261     Item_func_like *func_like;
262     func_like= new (thd->mem_root) Item_func_like(pos, ident_name_where, wild_string, NULL);
263     if (func_like == NULL)
264       return NULL;
265 
266     /* ... WHERE Variable_name LIKE <value> ... */
267     where_clause= new (thd->mem_root) PTI_context<CTX_WHERE>(pos, func_like);
268     if (where_clause == NULL)
269       return NULL;
270   }
271   else
272   {
273     where_clause= where_cond;
274   }
275 
276 
277   /* SELECT * FROM (SELECT ...) derived_table [ WHERE Variable_name LIKE <value> ] */
278   /* SELECT * FROM (SELECT ...) derived_table [ WHERE <cond> ] */
279   PT_select_part2 *select_part2;
280   select_part2= new (thd->mem_root) PT_select_part2(options_and_item_list2,
281                                                     NULL, /* opt_into */
282                                                     table_reference_list2, /* from_clause */
283                                                     where_clause, /* opt_where_clause */
284                                                     NULL, /* opt_group_clause */
285                                                     NULL, /* opt_having_clause */
286                                                     NULL, /* opt_order_clause */
287                                                     NULL, /* opt_limit_clause */
288                                                     NULL, /* opt_procedure_analyse_clause */
289                                                     NULL, /* opt_into */
290                                                     lock_type /* opt_select_lock_type */);
291   if (select_part2 == NULL)
292     return NULL;
293 
294   PT_select_init2 *select_init2;
295   select_init2= new (thd->mem_root) PT_select_init2(NULL, select_part2, NULL);
296   if (select_init2 == NULL)
297     return NULL;
298 
299   PT_select *select;
300   select= new (thd->mem_root) PT_select(select_init2, SQLCOM_SELECT);
301   if (select == NULL)
302     return NULL;
303 
304   LEX *lex= thd->lex;
305   SELECT_LEX *current_select= lex->current_select();
306   Parse_context pc(thd, current_select);
307   if (thd->is_error())
308     return NULL;
309 
310   if (select->contextualize(&pc))
311     return NULL;
312 
313   /* contextualize sets to COM_SELECT */
314   lex->sql_command= command;
315 
316   return current_select;
317 }
318 
319 SELECT_LEX*
build_show_session_status(const POS & pos,THD * thd,const String * wild,Item * where_cond)320 build_show_session_status(const POS &pos, THD *thd, const String *wild, Item *where_cond)
321 {
322   static const LEX_STRING table_name= { C_STRING_WITH_LEN("session_status")};
323 
324   return build_query(pos, thd, SQLCOM_SHOW_STATUS, table_name, wild, where_cond);
325 }
326 
327 SELECT_LEX*
build_show_global_status(const POS & pos,THD * thd,const String * wild,Item * where_cond)328 build_show_global_status(const POS &pos, THD *thd, const String *wild, Item *where_cond)
329 {
330   static const LEX_STRING table_name= { C_STRING_WITH_LEN("global_status")};
331 
332   return build_query(pos, thd, SQLCOM_SHOW_STATUS, table_name, wild, where_cond);
333 }
334 
335 SELECT_LEX*
build_show_session_variables(const POS & pos,THD * thd,const String * wild,Item * where_cond)336 build_show_session_variables(const POS &pos, THD *thd, const String *wild, Item *where_cond)
337 {
338   static const LEX_STRING table_name= { C_STRING_WITH_LEN("session_variables")};
339 
340   return build_query(pos, thd, SQLCOM_SHOW_VARIABLES, table_name, wild, where_cond);
341 }
342 
343 SELECT_LEX*
build_show_global_variables(const POS & pos,THD * thd,const String * wild,Item * where_cond)344 build_show_global_variables(const POS &pos, THD *thd, const String *wild, Item *where_cond)
345 {
346   static const LEX_STRING table_name= { C_STRING_WITH_LEN("global_variables")};
347 
348   return build_query(pos, thd, SQLCOM_SHOW_VARIABLES, table_name, wild, where_cond);
349 }
350 
351