1 /* Copyright (c) 2013, 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/parse_tree_helpers.h"
24 
25 #include "m_string.h"
26 #include "my_dbug.h"
27 #include "my_inttypes.h"
28 #include "my_sqlcommand.h"
29 #include "my_sys.h"
30 #include "mysql/components/services/log_shared.h"
31 #include "mysql/mysql_lex_string.h"
32 #include "mysql_com.h"
33 #include "mysqld_error.h"
34 #include "sql/auth/auth_acls.h"
35 #include "sql/derror.h"
36 #include "sql/handler.h"
37 #include "sql/mysqld.h"
38 #include "sql/parse_tree_column_attrs.h"
39 #include "sql/parse_tree_nodes.h"
40 #include "sql/resourcegroups/platform/thread_attrs_api.h"
41 #include "sql/resourcegroups/resource_group_mgr.h"  // Resource_group_mgr
42 #include "sql/sp_head.h"
43 #include "sql/sp_instr.h"
44 #include "sql/sp_pcontext.h"
45 #include "sql/sql_class.h"
46 #include "sql/sql_error.h"
47 #include "sql/sql_lex.h"
48 #include "sql/sql_plugin_ref.h"
49 #include "sql/system_variables.h"
50 #include "sql/trigger_def.h"
51 #include "sql_string.h"
52 
53 /**
54   Create an object to represent a SP variable in the Item-hierarchy.
55 
56   @param thd              The current thread.
57   @param name             The SP variable name.
58   @param spv              The SP variable (optional).
59   @param query_start_ptr  Start of the SQL-statement query string (optional).
60   @param start            Start position of the SP variable name in the query.
61   @param end              End position of the SP variable name in the query.
62 
63   @remark If spv is not specified, the name is used to search for the
64           variable in the parse-time context. If the variable does not
65           exist, a error is set and NULL is returned to the caller.
66 
67   @return An Item_splocal object representing the SP variable, or NULL on error.
68 */
create_item_for_sp_var(THD * thd,LEX_CSTRING name,sp_variable * spv,const char * query_start_ptr,const char * start,const char * end)69 Item_splocal *create_item_for_sp_var(THD *thd, LEX_CSTRING name,
70                                      sp_variable *spv,
71                                      const char *query_start_ptr,
72                                      const char *start, const char *end) {
73   LEX *lex = thd->lex;
74   size_t spv_pos_in_query = 0;
75   size_t spv_len_in_query = 0;
76   sp_pcontext *pctx = lex->get_sp_current_parsing_ctx();
77 
78   /* If necessary, look for the variable. */
79   if (pctx && !spv) spv = pctx->find_variable(name.str, name.length, false);
80 
81   if (!spv) {
82     my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str);
83     return nullptr;
84   }
85 
86   DBUG_ASSERT(pctx && spv);
87 
88   if (lex->reparse_common_table_expr_at != 0) {
89     /*
90       This variable doesn't exist in the original query: shouldn't be
91       substituted for logging.
92     */
93     query_start_ptr = nullptr;
94   }
95 
96   if (query_start_ptr) {
97     /* Position and length of the SP variable name in the query. */
98     spv_pos_in_query = start - query_start_ptr;
99     spv_len_in_query = end - start;
100   }
101 
102   Item_splocal *item = new (thd->mem_root) Item_splocal(
103       name, spv->offset, spv->type, spv_pos_in_query, spv_len_in_query);
104 
105 #ifndef DBUG_OFF
106   if (item) item->m_sp = lex->sphead;
107 #endif
108 
109   return item;
110 }
111 
find_sys_var_null_base(THD * thd,struct sys_var_with_base * tmp)112 bool find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp) {
113   tmp->var = find_sys_var(thd, tmp->base_name.str, tmp->base_name.length);
114 
115   if (tmp->var == nullptr)
116     my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), tmp->base_name.str);
117   else
118     tmp->base_name = NULL_CSTR;
119 
120   return thd->is_error();
121 }
122 
123 /**
124   Helper action for a SET statement.
125   Used to push a system variable into the assignment list.
126 
127   @param thd      the current thread
128   @param var_with_base  the system variable with base name
129   @param var_type the scope of the variable
130   @param val      the value being assigned to the variable
131 
132   @return true if error, false otherwise.
133 */
134 
set_system_variable(THD * thd,struct sys_var_with_base * var_with_base,enum enum_var_type var_type,Item * val)135 bool set_system_variable(THD *thd, struct sys_var_with_base *var_with_base,
136                          enum enum_var_type var_type, Item *val) {
137   LEX *lex = thd->lex;
138   sp_head *sp = lex->sphead;
139   sp_pcontext *pctx = lex->get_sp_current_parsing_ctx();
140 
141   /* No AUTOCOMMIT from a stored function or trigger. */
142   if (pctx && var_with_base->var == Sys_autocommit_ptr)
143     sp->m_flags |= sp_head::HAS_SET_AUTOCOMMIT_STMT;
144 
145   if (lex->uses_stored_routines() &&
146       ((var_with_base->var == Sys_gtid_next_ptr
147 #ifdef HAVE_GTID_NEXT_LIST
148         || var_with_base->var == Sys_gtid_next_list_ptr
149 #endif
150         ) ||
151        Sys_gtid_purged_ptr == var_with_base->var)) {
152     my_error(ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION, MYF(0),
153              var_with_base->var->name.str);
154     return true;
155   }
156 
157   if (val && val->type() == Item::FIELD_ITEM &&
158       ((Item_field *)val)->table_name) {
159     my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var_with_base->var->name.str);
160     return true;
161   }
162 
163   set_var *var = new (thd->mem_root)
164       set_var(var_type, var_with_base->var, var_with_base->base_name, val);
165   if (var == nullptr) return true;
166 
167   return lex->var_list.push_back(var);
168 }
169 
170 /**
171   Make a new string allocated on THD's mem-root.
172 
173   @param thd        thread handler.
174   @param start_ptr  start of the new string.
175   @param end_ptr    end of the new string.
176 
177   @return LEX_CSTRING object, containing a pointer to a newly
178   constructed/allocated string, and its length. The pointer is NULL
179   in case of out-of-memory error.
180 */
make_string(THD * thd,const char * start_ptr,const char * end_ptr)181 LEX_CSTRING make_string(THD *thd, const char *start_ptr, const char *end_ptr) {
182   size_t length = end_ptr - start_ptr;
183   return {strmake_root(thd->mem_root, start_ptr, length), length};
184 }
185 
186 /**
187   Helper action for a SET statement.
188   Used to SET a field of NEW row.
189 
190   @param pc                 the parse context
191   @param trigger_field_name the NEW-row field name
192   @param expr_item          the value expression being assigned
193   @param expr_query         the value expression query
194 
195   @return error status (true if error, false otherwise).
196 */
197 
set_trigger_new_row(Parse_context * pc,LEX_CSTRING trigger_field_name,Item * expr_item,LEX_CSTRING expr_query)198 bool set_trigger_new_row(Parse_context *pc, LEX_CSTRING trigger_field_name,
199                          Item *expr_item, LEX_CSTRING expr_query) {
200   THD *thd = pc->thd;
201   LEX *lex = thd->lex;
202   sp_head *sp = lex->sphead;
203 
204   DBUG_ASSERT(expr_item);
205   DBUG_ASSERT(sp->m_trg_chistics.action_time == TRG_ACTION_BEFORE &&
206               (sp->m_trg_chistics.event == TRG_EVENT_INSERT ||
207                sp->m_trg_chistics.event == TRG_EVENT_UPDATE));
208 
209   Item_trigger_field *trg_fld = new (pc->mem_root) Item_trigger_field(
210       POS(), TRG_NEW_ROW, trigger_field_name.str, UPDATE_ACL, false);
211 
212   if (trg_fld == nullptr || trg_fld->itemize(pc, (Item **)&trg_fld))
213     return true;
214   DBUG_ASSERT(trg_fld->type() == Item::TRIGGER_FIELD_ITEM);
215 
216   sp_instr_set_trigger_field *i = new (pc->mem_root)
217       sp_instr_set_trigger_field(sp->instructions(), lex, trigger_field_name,
218                                  trg_fld, expr_item, expr_query);
219 
220   if (!i) return true;
221 
222   /*
223     Let us add this item to list of all Item_trigger_field
224     objects in trigger.
225   */
226   sp->m_cur_instr_trig_field_items.link_in_list(trg_fld,
227                                                 &trg_fld->next_trg_field);
228 
229   return sp->add_instr(thd, i);
230 }
231 
sp_create_assignment_lex(THD * thd,const char * option_ptr)232 void sp_create_assignment_lex(THD *thd, const char *option_ptr) {
233   sp_head *sp = thd->lex->sphead;
234 
235   /*
236     We can come here in the following cases:
237 
238       1. it's a regular SET statement outside stored programs
239         (thd->lex->sphead is NULL);
240 
241       2. we're parsing a stored program normally (loading from mysql.proc, ...);
242 
243       3. we're re-parsing SET-statement with a user variable after meta-data
244         change. It's guaranteed, that:
245         - this SET-statement deals with a user/system variable (otherwise, it
246           would be a different SP-instruction, and we would parse an
247     expression);
248         - this SET-statement has a single user/system variable assignment
249           (that's how we generate sp_instr_stmt-instructions for
250     SET-statements). So, in this case, even if thd->lex->sphead is set, we
251     should not process further.
252   */
253 
254   if (!sp ||             // case #1
255       sp->is_invoked())  // case #3
256   {
257     return;
258   }
259 
260   LEX *old_lex = thd->lex;
261   sp->reset_lex(thd);
262   LEX *const lex = thd->lex;
263 
264   /* Set new LEX as if we at start of set rule. */
265   lex->sql_command = SQLCOM_SET_OPTION;
266   lex->var_list.empty();
267   lex->autocommit = false;
268 
269   /*
270     It's a SET statement within SP. It will be either translated
271     into one or more sp_instr_stmt instructions, or it will be
272     sp_instr_set / sp_instr_set_trigger_field instructions.
273     In any case, position of SP-variable can not be determined
274     reliably. So, we set the start pointer of the current statement
275     to NULL.
276   */
277   sp->m_parser_data.set_current_stmt_start_ptr(nullptr);
278   sp->m_parser_data.set_option_start_ptr(option_ptr);
279 
280   /* Inherit from outer lex. */
281   lex->option_type = old_lex->option_type;
282 }
283 
284 /**
285   Create a SP instruction for a SET assignment.
286 
287   @see sp_create_assignment_lex
288 
289   @param thd           Thread context
290   @param expr_end_ptr  Option-value-expression end pointer
291 
292   @return false if success, true otherwise.
293 */
294 
sp_create_assignment_instr(THD * thd,const char * expr_end_ptr)295 bool sp_create_assignment_instr(THD *thd, const char *expr_end_ptr) {
296   LEX *lex = thd->lex;
297   sp_head *sp = lex->sphead;
298 
299   /*
300     We can come here in the following cases:
301 
302       1. it's a regular SET statement outside stored programs
303         (lex->sphead is NULL);
304 
305       2. we're parsing a stored program normally (loading from mysql.proc, ...);
306 
307       3. we're re-parsing SET-statement with a user variable after meta-data
308         change. It's guaranteed, that:
309         - this SET-statement deals with a user/system variable (otherwise, it
310           would be a different SP-instruction, and we would parse an
311     expression);
312         - this SET-statement has a single user/system variable assignment
313           (that's how we generate sp_instr_stmt-instructions for
314     SET-statements). So, in this case, even if lex->sphead is set, we should not
315     process further.
316   */
317 
318   if (!sp ||             // case #1
319       sp->is_invoked())  // case #3
320   {
321     return false;
322   }
323 
324   if (!lex->var_list.is_empty()) {
325     /* Extract expression string. */
326 
327     const char *expr_start_ptr = sp->m_parser_data.get_option_start_ptr();
328 
329     LEX_CSTRING expr{expr_start_ptr,
330                      static_cast<size_t>(expr_end_ptr - expr_start_ptr)};
331 
332     /* Construct SET-statement query. */
333 
334     LEX_CSTRING set_stmt_query;
335 
336     set_stmt_query.length = expr.length + 3;
337     char *c = static_cast<char *>(thd->alloc(set_stmt_query.length + 1));
338 
339     if (!c) return true;
340 
341     strmake(strmake(c, "SET", 3), expr.str, expr.length);
342     set_stmt_query.str = c;
343 
344     /*
345       We have assignment to user or system variable or option setting, so we
346       should construct sp_instr_stmt for it.
347     */
348 
349     sp_instr_stmt *i = new (thd->mem_root)
350         sp_instr_stmt(sp->instructions(), lex, set_stmt_query);
351 
352     if (!i || sp->add_instr(thd, i)) return true;
353   }
354 
355   /* Remember option_type of the currently parsed LEX. */
356   enum_var_type inner_option_type = lex->option_type;
357 
358   if (sp->restore_lex(thd)) return true;
359 
360   /* Copy option_type to outer lex in case it has changed. */
361   thd->lex->option_type = inner_option_type;
362 
363   return false;
364 }
365 
366 /**
367   Resolve engine by its name
368 
369   @param        thd            Thread handler.
370   @param        name           Engine's name.
371   @param        is_temp_table  True if temporary table.
372   @param        strict         Force error if engine is unknown(*).
373   @param[out]   ret            Engine object or NULL(**).
374 
375   @returns true if error is reported(**), otherwise false.
376 
377   @note *) NO_ENGINE_SUBSTITUTION sql_mode overrides the @c strict parameter.
378   @note **) If @c strict if false and engine is unknown, the function outputs
379             a warning, sets @c ret to NULL and returns false (success).
380 */
resolve_engine(THD * thd,const LEX_CSTRING & name,bool is_temp_table,bool strict,handlerton ** ret)381 bool resolve_engine(THD *thd, const LEX_CSTRING &name, bool is_temp_table,
382                     bool strict, handlerton **ret) {
383   plugin_ref plugin = ha_resolve_by_name(thd, &name, is_temp_table);
384   if (plugin) {
385     *ret = plugin_data<handlerton *>(plugin);
386     return false;
387   }
388 
389   if (strict || !is_engine_substitution_allowed(thd)) {
390     my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), name.str);
391     return true;
392   }
393   push_warning_printf(thd, Sql_condition::SL_WARNING, ER_UNKNOWN_STORAGE_ENGINE,
394                       ER_THD(thd, ER_UNKNOWN_STORAGE_ENGINE), name.str);
395   *ret = nullptr;
396   return false;
397 }
398 
399 /**
400   This helper function is responsible for aggregating grants from parser tokens
401   to containers and masks which can be used during semantic analysis.
402 
403   @param thd The thread handler
404   @param privs A list of parser tokens representing roles or privileges.
405   @return Error state
406     @retval true An error occurred
407     @retval false Success
408 */
409 
apply_privileges(THD * thd,const Mem_root_array<class PT_role_or_privilege * > & privs)410 bool apply_privileges(
411     THD *thd, const Mem_root_array<class PT_role_or_privilege *> &privs) {
412   LEX *const lex = thd->lex;
413 
414   for (PT_role_or_privilege *p : privs) {
415     Privilege *privilege = p->get_privilege(thd);
416     if (privilege == nullptr) return true;
417 
418     if (privilege->type == Privilege::DYNAMIC) {
419       // We can push a reference to the PT object since it will have the same
420       // life time as our dynamic_privileges list.
421       LEX_CSTRING *grant =
422           static_cast<LEX_CSTRING *>(thd->alloc(sizeof(LEX_CSTRING)));
423       grant->str = static_cast<Dynamic_privilege *>(privilege)->ident.str;
424       grant->length = static_cast<Dynamic_privilege *>(privilege)->ident.length;
425       char *s = static_cast<Dynamic_privilege *>(privilege)->ident.str;
426       char *s_end =
427           s + static_cast<Dynamic_privilege *>(privilege)->ident.length;
428       while (s != s_end) {
429         *s = my_toupper(system_charset_info, *s);
430         ++s;
431       }
432       lex->dynamic_privileges.push_back(grant);
433     } else {
434       auto grant = static_cast<Static_privilege *>(privilege)->grant;
435       auto columns = static_cast<Static_privilege *>(privilege)->columns;
436 
437       if (columns == nullptr)
438         lex->grant |= grant;
439       else {
440         for (auto &c : *columns) {
441           auto new_str =
442               new (thd->mem_root) String(c.str, c.length, system_charset_info);
443           if (new_str == nullptr) return true;
444           List_iterator<LEX_COLUMN> iter(lex->columns);
445           class LEX_COLUMN *point;
446           while ((point = iter++)) {
447             if (!my_strcasecmp(system_charset_info, point->column.ptr(),
448                                new_str->ptr()))
449               break;
450           }
451           lex->grant_tot_col |= grant;
452           if (point)
453             point->rights |= grant;
454           else {
455             LEX_COLUMN *col = new (thd->mem_root) LEX_COLUMN(*new_str, grant);
456             if (col == nullptr) return true;
457             lex->columns.push_back(col);
458           }
459         }
460       }
461     }
462   }  // end for
463   return false;
464 }
465 
validate_vcpu_range(const resourcegroups::Range & range)466 bool validate_vcpu_range(const resourcegroups::Range &range) {
467   auto vcpus = resourcegroups::Resource_group_mgr::instance()->num_vcpus();
468   for (resourcegroups::platform::cpu_id_t cpu : {range.m_start, range.m_end}) {
469     if (cpu >= vcpus) {
470       my_error(ER_INVALID_VCPU_ID, MYF(0), cpu);
471       return true;
472     }
473   }
474   return false;
475 }
476 
validate_resource_group_priority(THD * thd,int * priority,const LEX_CSTRING & name,const resourcegroups::Type & type)477 bool validate_resource_group_priority(THD *thd, int *priority,
478                                       const LEX_CSTRING &name,
479                                       const resourcegroups::Type &type) {
480   auto mgr_ptr = resourcegroups::Resource_group_mgr::instance();
481   if (mgr_ptr->thread_priority_available()) {
482     int min = resourcegroups::platform::min_thread_priority_value();
483     int max = resourcegroups::platform::max_thread_priority_value();
484 
485     if (type == resourcegroups::Type::USER_RESOURCE_GROUP)
486       min = 0;
487     else
488       max = 0;
489 
490     if (*priority < min || *priority > max) {
491       my_error(ER_INVALID_THREAD_PRIORITY, MYF(0), *priority,
492                mgr_ptr->resource_group_type_str(type), name.str, min, max);
493       return true;
494     }
495   } else if (*priority != 0) {
496     push_warning_printf(thd, Sql_condition::SL_WARNING, ER_ATTRIBUTE_IGNORED,
497                         ER_THD(thd, ER_ATTRIBUTE_IGNORED), "thread_priority",
498                         "using default value");
499     *priority = 0;
500   }
501   return false;
502 }
503 
check_resource_group_support()504 bool check_resource_group_support() {
505   auto res_grp_mgr = resourcegroups::Resource_group_mgr::instance();
506   if (!res_grp_mgr->resource_group_support()) {
507     my_error(ER_FEATURE_UNSUPPORTED, MYF(0), "Resource Groups",
508              res_grp_mgr->unsupport_reason());
509     return true;
510   }
511   return false;
512 }
513 
check_resource_group_name_len(const LEX_CSTRING & name,Sql_condition::enum_severity_level severity)514 bool check_resource_group_name_len(
515     const LEX_CSTRING &name, Sql_condition::enum_severity_level severity) {
516   if (name.length <= NAME_CHAR_LEN) {
517     return false;
518   }
519   if (severity == Sql_condition::SL_ERROR) {
520     my_error(ER_TOO_LONG_IDENT, MYF(0), name.str);
521   } else {
522     push_warning_printf(current_thd, Sql_condition::SL_WARNING,
523                         ER_TOO_LONG_IDENT,
524                         ER_THD(current_thd, ER_TOO_LONG_IDENT), name.str);
525   }
526   return true;
527 }
528 
move_cf_appliers(Parse_context * tddlpc,Column_parse_context * cpc)529 void move_cf_appliers(Parse_context *tddlpc, Column_parse_context *cpc) {
530   Table_ddl_parse_context *tpc = static_cast<Table_ddl_parse_context *>(tddlpc);
531   tpc->alter_info->cf_appliers = std::move(cpc->cf_appliers);
532 }
533