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