1 /* Copyright (c) 2002, 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 Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 #include "my_global.h"
24 #include "mysql.h"
25 #include "sp.h" // sp_eval_expr
26 #include "sql_cursor.h"
27 #include "sp_rcontext.h"
28 #include "sp_pcontext.h"
29 #include "sql_tmp_table.h" // create_virtual_tmp_table
30 #include "sp_instr.h"
31 #include "template_utils.h"
32
33 extern "C" void sql_alloc_error_handler(void);
34
35 ///////////////////////////////////////////////////////////////////////////
36 // sp_rcontext implementation.
37 ///////////////////////////////////////////////////////////////////////////
38
39
sp_rcontext(const sp_pcontext * root_parsing_ctx,Field * return_value_fld,bool in_sub_stmt)40 sp_rcontext::sp_rcontext(const sp_pcontext *root_parsing_ctx,
41 Field *return_value_fld,
42 bool in_sub_stmt)
43 :end_partial_result_set(false),
44 m_root_parsing_ctx(root_parsing_ctx),
45 m_var_table(NULL),
46 m_return_value_fld(return_value_fld),
47 m_return_value_set(false),
48 m_in_sub_stmt(in_sub_stmt),
49 m_visible_handlers(PSI_INSTRUMENT_ME),
50 m_activated_handlers(PSI_INSTRUMENT_ME),
51 m_ccount(0)
52 {
53 }
54
55
~sp_rcontext()56 sp_rcontext::~sp_rcontext()
57 {
58 if (m_var_table)
59 free_blobs(m_var_table);
60
61 delete_container_pointers(m_activated_handlers);
62 delete_container_pointers(m_visible_handlers);
63 pop_all_cursors();
64
65 // Leave m_var_items and m_case_expr_holders untouched.
66 // They are allocated in mem roots and will be freed accordingly.
67 }
68
69
create(THD * thd,const sp_pcontext * root_parsing_ctx,Field * return_value_fld)70 sp_rcontext *sp_rcontext::create(THD *thd,
71 const sp_pcontext *root_parsing_ctx,
72 Field *return_value_fld)
73 {
74 sp_rcontext *ctx= new (thd->mem_root) sp_rcontext(root_parsing_ctx,
75 return_value_fld,
76 thd->in_sub_stmt);
77
78 if (!ctx)
79 return NULL;
80
81 if (ctx->alloc_arrays(thd) ||
82 ctx->init_var_table(thd) ||
83 ctx->init_var_items(thd))
84 {
85 delete ctx;
86 return NULL;
87 }
88
89 return ctx;
90 }
91
92
alloc_arrays(THD * thd)93 bool sp_rcontext::alloc_arrays(THD *thd)
94 {
95 {
96 size_t n= m_root_parsing_ctx->max_cursor_index();
97 m_cstack.reset(
98 static_cast<sp_cursor **> (
99 thd->alloc(n * sizeof (sp_cursor*))),
100 n);
101 }
102
103 {
104 size_t n= m_root_parsing_ctx->get_num_case_exprs();
105 m_case_expr_holders.reset(
106 static_cast<Item_cache **> (
107 thd->mem_calloc(n * sizeof (Item_cache*))),
108 n);
109 }
110
111 return !m_cstack.array() || !m_case_expr_holders.array();
112 }
113
114
init_var_table(THD * thd)115 bool sp_rcontext::init_var_table(THD *thd)
116 {
117 List<Create_field> field_def_lst;
118
119 if (!m_root_parsing_ctx->max_var_index())
120 return false;
121
122 m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
123
124 assert(field_def_lst.elements == m_root_parsing_ctx->max_var_index());
125
126 if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst)))
127 return true;
128
129 m_var_table->copy_blobs= true;
130 m_var_table->alias= "";
131
132 return false;
133 }
134
135
init_var_items(THD * thd)136 bool sp_rcontext::init_var_items(THD *thd)
137 {
138 uint num_vars= m_root_parsing_ctx->max_var_index();
139
140 m_var_items.reset(
141 static_cast<Item **> (
142 thd->alloc(num_vars * sizeof (Item *))),
143 num_vars);
144
145 if (!m_var_items.array())
146 return true;
147
148 for (uint idx = 0; idx < num_vars; ++idx)
149 {
150 if (!(m_var_items[idx]= new Item_field(m_var_table->field[idx])))
151 return true;
152 }
153
154 return false;
155 }
156
157
set_return_value(THD * thd,Item ** return_value_item)158 bool sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
159 {
160 assert(m_return_value_fld);
161
162 m_return_value_set = true;
163
164 return sp_eval_expr(thd, m_return_value_fld, return_value_item);
165 }
166
167
push_cursor(sp_instr_cpush * i)168 bool sp_rcontext::push_cursor(sp_instr_cpush *i)
169 {
170 /*
171 We should create cursors on the system heap because:
172 - they could be (and usually are) used in several instructions,
173 thus they can not be stored on an execution mem-root;
174 - a cursor can be pushed/popped many times in a loop, having these objects
175 on callers' mem-root would lead to a memory leak in every iteration.
176 */
177 sp_cursor *c= new (std::nothrow) sp_cursor(i);
178
179 if (!c)
180 {
181 sql_alloc_error_handler();
182 return true;
183 }
184
185 m_cstack[m_ccount++]= c;
186 return false;
187 }
188
189
pop_cursors(uint count)190 void sp_rcontext::pop_cursors(uint count)
191 {
192 assert(m_ccount >= count);
193
194 while (count--)
195 delete m_cstack[--m_ccount];
196 }
197
198
push_handler(sp_handler * handler,uint first_ip)199 bool sp_rcontext::push_handler(sp_handler *handler, uint first_ip)
200 {
201 /*
202 We should create handler entries on the system heap because:
203 - they could be (and usually are) used in several instructions,
204 thus they can not be stored on an execution mem-root;
205 - a handler can be pushed/popped many times in a loop, having these
206 objects on callers' mem-root would lead to a memory leak in every
207 iteration.
208 */
209 sp_handler_entry *he=
210 new (std::nothrow) sp_handler_entry(handler, first_ip);
211
212 if (!he)
213 {
214 sql_alloc_error_handler();
215 return true;
216 }
217
218 return m_visible_handlers.push_back(he);
219 }
220
221
pop_handlers(sp_pcontext * current_scope)222 void sp_rcontext::pop_handlers(sp_pcontext *current_scope)
223 {
224 for (int i= static_cast<int>(m_visible_handlers.size()) - 1; i >= 0; --i)
225 {
226 int handler_level= m_visible_handlers.at(i)->handler->scope->get_level();
227
228 if (handler_level >= current_scope->get_level())
229 {
230 delete m_visible_handlers.back();
231 m_visible_handlers.pop_back();
232 }
233 }
234 }
235
236
pop_handler_frame(THD * thd)237 void sp_rcontext::pop_handler_frame(THD *thd)
238 {
239 Handler_call_frame *frame= m_activated_handlers.back();
240 m_activated_handlers.pop_back();
241
242 // Also pop matching DA and copy new conditions.
243 assert(thd->get_stmt_da() == &frame->handler_da);
244 thd->pop_diagnostics_area();
245 // Out with the old, in with the new!
246 thd->get_stmt_da()->reset_condition_info(thd);
247 thd->get_stmt_da()->copy_new_sql_conditions(thd, &frame->handler_da);
248
249 delete frame;
250 }
251
252
exit_handler(THD * thd,sp_pcontext * target_scope)253 void sp_rcontext::exit_handler(THD *thd, sp_pcontext *target_scope)
254 {
255 /*
256 The handler has successfully completed. We should now pop the current
257 handler frame and pop the diagnostics area which was pushed when the
258 handler was activated.
259
260 The diagnostics area of the caller should then contain only any
261 conditions pushed during handler execution. The conditions present
262 when the handler was activated should be removed since they have
263 been successfully handled.
264 */
265 pop_handler_frame(thd);
266
267 // Pop frames below the target scope level.
268 for (int i= static_cast<int>(m_activated_handlers.size()) - 1; i >= 0; --i)
269 {
270 int handler_level= m_activated_handlers.at(i)->handler->scope->get_level();
271
272 if (handler_level <= target_scope->get_level())
273 break;
274
275 pop_handler_frame(thd);
276 }
277
278 /*
279 Condition was successfully handled, reset condition count
280 so we don't trigger the handler again for the same warning.
281 */
282 thd->get_stmt_da()->reset_statement_cond_count();
283 }
284
285
handle_sql_condition(THD * thd,uint * ip,const sp_instr * cur_spi)286 bool sp_rcontext::handle_sql_condition(THD *thd,
287 uint *ip,
288 const sp_instr *cur_spi)
289 {
290 DBUG_ENTER("sp_rcontext::handle_sql_condition");
291
292 /*
293 If this is a fatal sub-statement error, and this runtime
294 context corresponds to a sub-statement, no CONTINUE/EXIT
295 handlers from this context are applicable: try to locate one
296 in the outer scope.
297 */
298 if (thd->is_fatal_sub_stmt_error && m_in_sub_stmt)
299 DBUG_RETURN(false);
300
301 Diagnostics_area *da= thd->get_stmt_da();
302 const sp_handler *found_handler= NULL;
303 Sql_condition *found_condition= NULL;
304
305 if (thd->is_error())
306 {
307 sp_pcontext *cur_pctx= cur_spi->get_parsing_ctx();
308
309 found_handler= cur_pctx->find_handler(da->returned_sqlstate(),
310 da->mysql_errno(),
311 Sql_condition::SL_ERROR);
312
313 if (found_handler)
314 {
315 found_condition= da->error_condition();
316
317 /*
318 error_condition can be NULL if the Diagnostics Area was full
319 when the error was raised. It can also be NULL if
320 Diagnostics_area::set_error_status(uint sql_error) was used.
321 In these cases, make a temporary Sql_condition here so the
322 error can be handled.
323 */
324 if (!found_condition)
325 {
326 found_condition= new (callers_arena->mem_root)
327 Sql_condition(callers_arena->mem_root,
328 da->mysql_errno(),
329 da->returned_sqlstate(),
330 Sql_condition::SL_ERROR,
331 da->message_text());
332 }
333 }
334 }
335 else if (da->current_statement_cond_count())
336 {
337 Diagnostics_area::Sql_condition_iterator it= da->sql_conditions();
338 const Sql_condition *c;
339
340 /*
341 Here we need to find the last warning/note from the stack.
342 In MySQL most substantial warning is the last one.
343 (We could have used a reverse iterator here if one existed.)
344 We ignore preexisting conditions so we don't throw for them
345 again if the next statement isn't one that pre-clears the
346 DA. (Critically, that includes hpush_jump, i.e. any handlers
347 declared within the one we're calling. At that point, the
348 catcher for our throw would become very hard to predict!)
349 One benefit of not simply clearing the DA as we enter a handler
350 (instead of resetting the condition cound further down in this
351 exact function as we do now) and forcing the user to utilize
352 GET STACKED DIAGNOSTICS is that this way, we can make
353 SHOW WARNINGS|ERRORS work.
354 */
355
356 while ((c= it++))
357 {
358 if (c->severity() == Sql_condition::SL_WARNING ||
359 c->severity() == Sql_condition::SL_NOTE)
360 {
361 sp_pcontext *cur_pctx= cur_spi->get_parsing_ctx();
362
363 const sp_handler *handler=
364 cur_pctx->find_handler(c->returned_sqlstate(),
365 c->mysql_errno(),
366 c->severity());
367 if (handler)
368 {
369 found_handler= handler;
370 found_condition= const_cast<Sql_condition*>(c);
371 }
372 }
373 }
374 }
375
376 if (!found_handler)
377 DBUG_RETURN(false);
378
379 // At this point, we know that:
380 // - there is a pending SQL-condition (error or warning);
381 // - there is an SQL-handler for it.
382
383 assert(found_condition);
384
385 sp_handler_entry *handler_entry= NULL;
386 for (size_t i= 0; i < m_visible_handlers.size(); ++i)
387 {
388 sp_handler_entry *h= m_visible_handlers.at(i);
389
390 if (h->handler == found_handler)
391 {
392 handler_entry= h;
393 break;
394 }
395 }
396
397 /*
398 handler_entry usually should not be NULL here, as that indicates
399 that the parser context thinks a HANDLER should be activated,
400 but the runtime context cannot find it.
401
402 However, this can happen (and this is in line with the Standard)
403 if SQL-condition has been raised before DECLARE HANDLER instruction
404 is processed.
405
406 For example:
407 CREATE PROCEDURE p()
408 BEGIN
409 DECLARE v INT DEFAULT 'get'; -- raises SQL-warning here
410 DECLARE EXIT HANDLER ... -- this handler does not catch the warning
411 END
412 */
413 if (!handler_entry)
414 DBUG_RETURN(false);
415
416 uint continue_ip= handler_entry->handler->type == sp_handler::CONTINUE ?
417 cur_spi->get_cont_dest() : 0;
418
419 /* Add a frame to handler-call-stack. */
420 Handler_call_frame *frame=
421 new (std::nothrow) Handler_call_frame(found_handler,
422 found_condition,
423 continue_ip);
424 if (!frame)
425 {
426 sql_alloc_error_handler();
427 DBUG_RETURN(false);
428 }
429
430 m_activated_handlers.push_back(frame);
431
432 /* End aborted result set. */
433 if (end_partial_result_set)
434 thd->get_protocol()->end_partial_result_set();
435
436 /* Reset error state. */
437 thd->clear_error();
438 thd->killed= THD::NOT_KILLED; // Some errors set thd->killed
439 // (e.g. "bad data").
440
441 thd->push_diagnostics_area(&frame->handler_da);
442
443 /*
444 Mark current conditions so we later will know which conditions
445 were added during handler execution (if any).
446 */
447 frame->handler_da.mark_preexisting_sql_conditions();
448
449 frame->handler_da.reset_statement_cond_count();
450
451 *ip= handler_entry->first_ip;
452
453 DBUG_RETURN(true);
454 }
455
456
set_variable(THD * thd,Field * field,Item ** value)457 bool sp_rcontext::set_variable(THD *thd, Field *field, Item **value)
458 {
459 if (!value)
460 {
461 field->set_null();
462 return false;
463 }
464
465 return sp_eval_expr(thd, field, value);
466 }
467
468
create_case_expr_holder(THD * thd,const Item * item) const469 Item_cache *sp_rcontext::create_case_expr_holder(THD *thd,
470 const Item *item) const
471 {
472 Item_cache *holder;
473 Query_arena current_arena;
474
475 thd->set_n_backup_active_arena(thd->sp_runtime_ctx->callers_arena,
476 ¤t_arena);
477
478 holder= Item_cache::get_cache(item);
479
480 thd->restore_active_arena(thd->sp_runtime_ctx->callers_arena, ¤t_arena);
481
482 return holder;
483 }
484
485
set_case_expr(THD * thd,int case_expr_id,Item ** case_expr_item_ptr)486 bool sp_rcontext::set_case_expr(THD *thd, int case_expr_id,
487 Item **case_expr_item_ptr)
488 {
489 Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr);
490 if (!case_expr_item)
491 return true;
492
493 if (!m_case_expr_holders[case_expr_id] ||
494 m_case_expr_holders[case_expr_id]->result_type() !=
495 case_expr_item->result_type())
496 {
497 m_case_expr_holders[case_expr_id]=
498 create_case_expr_holder(thd, case_expr_item);
499 }
500
501 m_case_expr_holders[case_expr_id]->store(case_expr_item);
502 m_case_expr_holders[case_expr_id]->cache_value();
503 return false;
504 }
505
506
507 ///////////////////////////////////////////////////////////////////////////
508 // sp_cursor implementation.
509 ///////////////////////////////////////////////////////////////////////////
510
511
512 /**
513 Open an SP cursor
514
515 @param thd Thread context
516
517 @return Error status
518 */
519
open(THD * thd)520 bool sp_cursor::open(THD *thd)
521 {
522 if (m_server_side_cursor)
523 {
524 my_message(ER_SP_CURSOR_ALREADY_OPEN, ER(ER_SP_CURSOR_ALREADY_OPEN),
525 MYF(0));
526 return true;
527 }
528
529 return mysql_open_cursor(thd, &m_result, &m_server_side_cursor);
530 }
531
532
close(THD * thd)533 bool sp_cursor::close(THD *thd)
534 {
535 if (! m_server_side_cursor)
536 {
537 my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
538 return true;
539 }
540
541 destroy();
542 return false;
543 }
544
545
destroy()546 void sp_cursor::destroy()
547 {
548 delete m_server_side_cursor;
549 m_server_side_cursor= NULL;
550 }
551
552
fetch(THD * thd,List<sp_variable> * vars)553 bool sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
554 {
555 if (! m_server_side_cursor)
556 {
557 my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
558 return true;
559 }
560
561 if (vars->elements != m_result.get_field_count())
562 {
563 my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
564 ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
565 return true;
566 }
567
568 DBUG_EXECUTE_IF("bug23032_emit_warning",
569 push_warning(thd, Sql_condition::SL_WARNING,
570 ER_UNKNOWN_ERROR,
571 ER(ER_UNKNOWN_ERROR)););
572
573 m_result.set_spvar_list(vars);
574
575 /* Attempt to fetch one row */
576 if (m_server_side_cursor->is_open())
577 {
578 if (m_server_side_cursor->fetch(1))
579 return true;
580 }
581
582 /*
583 If the cursor was pointing after the last row, the fetch will
584 close it instead of sending any rows.
585 */
586 if (! m_server_side_cursor->is_open())
587 {
588 my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0));
589 return true;
590 }
591
592 return false;
593 }
594
595
596 ///////////////////////////////////////////////////////////////////////////
597 // sp_cursor::Query_fetch_into_spvars implementation.
598 ///////////////////////////////////////////////////////////////////////////
599
600
prepare(List<Item> & fields,SELECT_LEX_UNIT * u)601 int sp_cursor::Query_fetch_into_spvars::prepare(List<Item> &fields,
602 SELECT_LEX_UNIT *u)
603 {
604 /*
605 Cache the number of columns in the result set in order to easily
606 return an error if column count does not match value count.
607 */
608 field_count= fields.elements;
609 return Query_result_interceptor::prepare(fields, u);
610 }
611
612
send_data(List<Item> & items)613 bool sp_cursor::Query_fetch_into_spvars::send_data(List<Item> &items)
614 {
615 List_iterator_fast<sp_variable> spvar_iter(*spvar_list);
616 List_iterator_fast<Item> item_iter(items);
617 sp_variable *spvar;
618 Item *item;
619
620 /* Must be ensured by the caller */
621 assert(spvar_list->elements == items.elements);
622
623 /*
624 Assign the row fetched from a server side cursor to stored
625 procedure variables.
626 */
627 for (; spvar= spvar_iter++, item= item_iter++; )
628 {
629 if (thd->sp_runtime_ctx->set_variable(thd, spvar->offset, &item))
630 return true;
631 }
632 return false;
633 }
634