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