1 /* Copyright (c) 2013, 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 #include "my_config.h"
24 #include "parse_tree_helpers.h"
25
26 #include "sql_class.h"
27 #include "sp_head.h"
28 #include "sp_instr.h"
29 #include "auth/auth_common.h"
30
31
32 /**
33 Create an object to represent a SP variable in the Item-hierarchy.
34
35 @param thd The current thread.
36 @param name The SP variable name.
37 @param spv The SP variable (optional).
38 @param query_start_ptr Start of the SQL-statement query string (optional).
39 @param start Start position of the SP variable name in the query.
40 @param end End position of the SP variable name in the query.
41
42 @remark If spv is not specified, the name is used to search for the
43 variable in the parse-time context. If the variable does not
44 exist, a error is set and NULL is returned to the caller.
45
46 @return An Item_splocal object representing the SP variable, or NULL on error.
47 */
create_item_for_sp_var(THD * thd,LEX_STRING name,sp_variable * spv,const char * query_start_ptr,const char * start,const char * end)48 Item_splocal* create_item_for_sp_var(THD *thd,
49 LEX_STRING name,
50 sp_variable *spv,
51 const char *query_start_ptr,
52 const char *start,
53 const char *end)
54 {
55 LEX *lex= thd->lex;
56 size_t spv_pos_in_query= 0;
57 size_t spv_len_in_query= 0;
58 sp_pcontext *pctx= lex->get_sp_current_parsing_ctx();
59
60 /* If necessary, look for the variable. */
61 if (pctx && !spv)
62 spv= pctx->find_variable(name, false);
63
64 if (!spv)
65 {
66 my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str);
67 return NULL;
68 }
69
70 assert(pctx && spv);
71
72 if (query_start_ptr)
73 {
74 /* Position and length of the SP variable name in the query. */
75 spv_pos_in_query= start - query_start_ptr;
76 spv_len_in_query= end - start;
77 }
78
79 Item_splocal *item=
80 new (thd->mem_root) Item_splocal(
81 name, spv->offset, spv->type, spv_pos_in_query, spv_len_in_query);
82
83 #ifndef NDEBUG
84 if (item)
85 item->m_sp= lex->sphead;
86 #endif
87
88 return item;
89 }
90
91
92 /**
93 Report syntax error if the sel query block can't be parenthesized
94
95 @return false if successful, true if an error was reported. In the latter
96 case parsing should stop.
97 */
setup_select_in_parentheses(SELECT_LEX * sel)98 bool setup_select_in_parentheses(SELECT_LEX *sel)
99 {
100 assert(sel->braces);
101 if (sel->linkage == UNION_TYPE &&
102 !sel->master_unit()->first_select()->braces &&
103 sel->master_unit()->first_select()->linkage ==
104 UNION_TYPE)
105 {
106 my_syntax_error(ER(ER_SYNTAX_ERROR));
107 return true;
108 }
109 if (sel->linkage == UNION_TYPE &&
110 sel->olap != UNSPECIFIED_OLAP_TYPE &&
111 sel->master_unit()->fake_select_lex)
112 {
113 my_error(ER_WRONG_USAGE, MYF(0), "CUBE/ROLLUP", "ORDER BY");
114 return true;
115 }
116 return false;
117 }
118
119
120 /**
121 @brief Push an error message into MySQL diagnostic area with line
122 and position information.
123
124 This function provides semantic action implementers with a way
125 to push the famous "You have a syntax error near..." error
126 message into the diagnostic area, which is normally produced only if
127 a parse error is discovered internally by the Bison generated
128 parser.
129 */
130
my_syntax_error(const char * s)131 void my_syntax_error(const char *s)
132 {
133 THD *thd= current_thd;
134 Lex_input_stream *lip= & thd->m_parser_state->m_lip;
135
136 const char *yytext= lip->get_tok_start();
137 if (!yytext)
138 yytext= "";
139
140 /* Push an error into the diagnostic area */
141 ErrConvString err(yytext, thd->variables.character_set_client);
142 my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s,
143 err.ptr(), lip->yylineno);
144 }
145
146
find_sys_var_null_base(THD * thd,struct sys_var_with_base * tmp)147 bool find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp)
148 {
149 tmp->var= find_sys_var(thd, tmp->base_name.str, tmp->base_name.length);
150
151 if (tmp->var == NULL)
152 my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), tmp->base_name.str);
153 else
154 tmp->base_name= null_lex_str;
155
156 return thd->is_error();
157 }
158
159
160 /**
161 Helper action for a SET statement.
162 Used to push a system variable into the assignment list.
163
164 @param thd the current thread
165 @param var_with_base the system variable with base name
166 @param var_type the scope of the variable
167 @param val the value being assigned to the variable
168
169 @return TRUE if error, FALSE otherwise.
170 */
171
172 bool
set_system_variable(THD * thd,struct sys_var_with_base * var_with_base,enum enum_var_type var_type,Item * val)173 set_system_variable(THD *thd, struct sys_var_with_base *var_with_base,
174 enum enum_var_type var_type, Item *val)
175 {
176 set_var *var;
177 LEX *lex= thd->lex;
178 sp_head *sp= lex->sphead;
179 sp_pcontext *pctx= lex->get_sp_current_parsing_ctx();
180
181 /* No AUTOCOMMIT from a stored function or trigger. */
182 if (pctx && var_with_base->var == Sys_autocommit_ptr)
183 sp->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
184
185 #ifdef HAVE_REPLICATION
186 if (lex->uses_stored_routines() &&
187 ((var_with_base->var == Sys_gtid_next_ptr
188 #ifdef HAVE_GTID_NEXT_LIST
189 || var_with_base->var == Sys_gtid_next_list_ptr
190 #endif
191 ) ||
192 Sys_gtid_purged_ptr == var_with_base->var))
193 {
194 my_error(ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION, MYF(0),
195 var_with_base->var->name.str);
196 return TRUE;
197 }
198 #endif
199
200 if (val && val->type() == Item::FIELD_ITEM &&
201 ((Item_field*)val)->table_name)
202 {
203 my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var_with_base->var->name.str);
204 return TRUE;
205 }
206
207 if (! (var= new set_var(var_type, var_with_base->var,
208 &var_with_base->base_name, val)))
209 return TRUE;
210
211 return lex->var_list.push_back(var);
212 }
213
214
215 /**
216 Make a new string allocated on THD's mem-root.
217
218 @param thd thread handler.
219 @param start_ptr start of the new string.
220 @param end_ptr end of the new string.
221
222 @return LEX_STRING object, containing a pointer to a newly
223 constructed/allocated string, and its length. The pointer is NULL
224 in case of out-of-memory error.
225 */
make_string(THD * thd,const char * start_ptr,const char * end_ptr)226 LEX_STRING make_string(THD *thd, const char *start_ptr, const char *end_ptr)
227 {
228 LEX_STRING s;
229
230 s.length= end_ptr - start_ptr;
231 s.str= (char *) thd->alloc(s.length + 1);
232
233 if (s.str)
234 strmake(s.str, start_ptr, s.length);
235
236 return s;
237 }
238
239
240 /**
241 Helper action for a SET statement.
242 Used to SET a field of NEW row.
243
244 @param pc the parse context
245 @param trigger_field_name the NEW-row field name
246 @param expr_item the value expression being assigned
247 @param expr_query the value expression query
248
249 @return error status (true if error, false otherwise).
250 */
251
set_trigger_new_row(Parse_context * pc,LEX_STRING trigger_field_name,Item * expr_item,LEX_STRING expr_query)252 bool set_trigger_new_row(Parse_context *pc,
253 LEX_STRING trigger_field_name,
254 Item *expr_item,
255 LEX_STRING expr_query)
256 {
257 THD *thd= pc->thd;
258 LEX *lex= thd->lex;
259 sp_head *sp= lex->sphead;
260
261 assert(expr_item);
262 assert(sp->m_trg_chistics.action_time == TRG_ACTION_BEFORE &&
263 (sp->m_trg_chistics.event == TRG_EVENT_INSERT ||
264 sp->m_trg_chistics.event == TRG_EVENT_UPDATE));
265
266 Item_trigger_field *trg_fld=
267 new (pc->mem_root) Item_trigger_field(POS(),
268 TRG_NEW_ROW,
269 trigger_field_name.str,
270 UPDATE_ACL, false);
271
272 if (trg_fld == NULL || trg_fld->itemize(pc, (Item **) &trg_fld))
273 return true;
274 assert(trg_fld->type() == Item::TRIGGER_FIELD_ITEM);
275
276 sp_instr_set_trigger_field *i=
277 new (pc->mem_root)
278 sp_instr_set_trigger_field(sp->instructions(),
279 lex,
280 trigger_field_name,
281 trg_fld, expr_item,
282 expr_query);
283
284 if (!i)
285 return true;
286
287 /*
288 Let us add this item to list of all Item_trigger_field
289 objects in trigger.
290 */
291 sp->m_cur_instr_trig_field_items.link_in_list(trg_fld,
292 &trg_fld->next_trg_field);
293
294 return sp->add_instr(thd, i);
295 }
296
297
sp_create_assignment_lex(THD * thd,const char * option_ptr)298 void sp_create_assignment_lex(THD *thd, const char *option_ptr)
299 {
300 sp_head *sp= thd->lex->sphead;
301
302 /*
303 We can come here in the following cases:
304
305 1. it's a regular SET statement outside stored programs
306 (thd->lex->sphead is NULL);
307
308 2. we're parsing a stored program normally (loading from mysql.proc, ...);
309
310 3. we're re-parsing SET-statement with a user variable after meta-data
311 change. It's guaranteed, that:
312 - this SET-statement deals with a user/system variable (otherwise, it
313 would be a different SP-instruction, and we would parse an expression);
314 - this SET-statement has a single user/system variable assignment
315 (that's how we generate sp_instr_stmt-instructions for SET-statements).
316 So, in this case, even if thd->lex->sphead is set, we should not process
317 further.
318
319 4. We are parsing SET STATEMENT FOR ... inside of SP.
320 */
321
322 if (!sp || // case #1
323 sp->is_invoked() || // case #3
324 thd->lex->set_statement) // case #4
325 {
326 return;
327 }
328
329 LEX *old_lex= thd->lex;
330 sp->reset_lex(thd);
331 LEX * const lex= thd->lex;
332
333 /* Set new LEX as if we at start of set rule. */
334 lex->sql_command= SQLCOM_SET_OPTION;
335 lex->var_list.empty();
336 lex->autocommit= false;
337
338 /*
339 It's a SET statement within SP. It will be either translated
340 into one or more sp_instr_stmt instructions, or it will be
341 sp_instr_set / sp_instr_set_trigger_field instructions.
342 In any case, position of SP-variable can not be determined
343 reliably. So, we set the start pointer of the current statement
344 to NULL.
345 */
346 sp->m_parser_data.set_current_stmt_start_ptr(NULL);
347 sp->m_parser_data.set_option_start_ptr(option_ptr);
348
349 /* Inherit from outer lex. */
350 lex->option_type= old_lex->option_type;
351 }
352
353
354 /**
355 Create a SP instruction for a SET assignment.
356
357 @see sp_create_assignment_lex
358
359 @param thd Thread context
360 @param expr_end_ptr Option-value-expression end pointer
361
362 @return false if success, true otherwise.
363 */
364
sp_create_assignment_instr(THD * thd,const char * expr_end_ptr)365 bool sp_create_assignment_instr(THD *thd, const char *expr_end_ptr)
366 {
367 LEX *lex= thd->lex;
368 sp_head *sp= lex->sphead;
369
370 /*
371 We can come here in the following cases:
372
373 1. it's a regular SET statement outside stored programs
374 (lex->sphead is NULL);
375
376 2. we're parsing a stored program normally (loading from mysql.proc, ...);
377
378 3. we're re-parsing SET-statement with a user variable after meta-data
379 change. It's guaranteed, that:
380 - this SET-statement deals with a user/system variable (otherwise, it
381 would be a different SP-instruction, and we would parse an expression);
382 - this SET-statement has a single user/system variable assignment
383 (that's how we generate sp_instr_stmt-instructions for SET-statements).
384 So, in this case, even if lex->sphead is set, we should not process
385 further.
386
387 4. It's a SET STATEMENT ... FOR CREATE PROCEDURE and should be treated as
388 case 1 even though lex->sphead != NULL.
389 */
390
391 if (!sp || // case #1
392 sp->is_invoked() || // case #3
393 lex->set_statement) // case #4
394 {
395 return false;
396 }
397
398 if (!lex->var_list.is_empty())
399 {
400 /* Extract expression string. */
401
402 const char *expr_start_ptr= sp->m_parser_data.get_option_start_ptr();
403
404 LEX_STRING expr;
405 expr.str= (char *) expr_start_ptr;
406 expr.length= expr_end_ptr - expr_start_ptr;
407
408 /* Construct SET-statement query. */
409
410 LEX_STRING set_stmt_query;
411
412 set_stmt_query.length= expr.length + 3;
413 set_stmt_query.str= (char *) thd->alloc(set_stmt_query.length + 1);
414
415 if (!set_stmt_query.str)
416 return true;
417
418 strmake(strmake(set_stmt_query.str, "SET", 3),
419 expr.str, expr.length);
420
421 /*
422 We have assignment to user or system variable or option setting, so we
423 should construct sp_instr_stmt for it.
424 */
425
426 sp_instr_stmt *i=
427 new (thd->mem_root)
428 sp_instr_stmt(sp->instructions(), lex, set_stmt_query);
429
430 if (!i || sp->add_instr(thd, i))
431 return true;
432 }
433
434 /* Remember option_type of the currently parsed LEX. */
435 enum_var_type inner_option_type= lex->option_type;
436
437 if (sp->restore_lex(thd))
438 return true;
439
440 /* Copy option_type to outer lex in case it has changed. */
441 thd->lex->option_type= inner_option_type;
442
443 return false;
444 }
445
446
447