1 /* Copyright (c) 2012, 2015, 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 #ifndef _SP_INSTR_H_ 24 #define _SP_INSTR_H_ 25 26 #include "my_global.h" // NO_EMBEDDED_ACCESS_CHECKS 27 #include "sp_pcontext.h" // sp_pcontext 28 #include "sql_class.h" // THD 29 #include "sp_head.h" // sp_printable 30 31 /////////////////////////////////////////////////////////////////////////// 32 // This file contains SP-instruction classes. 33 /////////////////////////////////////////////////////////////////////////// 34 35 /** 36 An interface for all SP-instructions with destinations that 37 need to be updated by the SP-optimizer. 38 */ 39 class sp_branch_instr 40 { 41 public: 42 /** 43 Update the destination; used by the SP-instruction-optimizer. 44 45 @param old_dest current (old) destination (instruction pointer). 46 @param new_dest new destination (instruction pointer). 47 */ 48 virtual void set_destination(uint old_dest, uint new_dest) = 0; 49 50 /** 51 Update all instruction with the given label in the backpatch list to 52 the specified instruction pointer. 53 54 @param dest destination instruction pointer. 55 */ 56 virtual void backpatch(uint dest) = 0; 57 ~sp_branch_instr()58 virtual ~sp_branch_instr() 59 { } 60 }; 61 62 /////////////////////////////////////////////////////////////////////////// 63 64 /** 65 Base class for every SP-instruction. sp_instr defines interface and provides 66 base implementation. 67 */ 68 class sp_instr : public Query_arena, 69 public Sql_alloc, 70 public sp_printable 71 { 72 public: sp_instr(uint ip,sp_pcontext * ctx)73 sp_instr(uint ip, sp_pcontext *ctx) 74 :Query_arena(0, STMT_INITIALIZED_FOR_SP), 75 m_marked(false), 76 m_ip(ip), 77 m_parsing_ctx(ctx) 78 { } 79 ~sp_instr()80 virtual ~sp_instr() 81 { free_items(); } 82 83 /** 84 Execute this instruction 85 86 @param thd Thread context 87 @param[out] nextp index of the next instruction to execute. (For most 88 instructions this will be the instruction following this 89 one). Note that this parameter is undefined in case of 90 errors, use get_cont_dest() to find the continuation 91 instruction for CONTINUE error handlers. 92 93 @return Error status. 94 */ 95 virtual bool execute(THD *thd, uint *nextp) = 0; 96 get_ip()97 uint get_ip() const 98 { return m_ip; } 99 100 /** 101 Get the continuation destination (instruction pointer for the CONTINUE 102 HANDLER) of this instruction. 103 @return the continuation destination 104 */ get_cont_dest()105 virtual uint get_cont_dest() const 106 { return get_ip() + 1; } 107 get_parsing_ctx()108 sp_pcontext *get_parsing_ctx() const 109 { return m_parsing_ctx; } 110 111 /////////////////////////////////////////////////////////////////////////// 112 // The following operations are used solely for SP-code-optimizer. 113 /////////////////////////////////////////////////////////////////////////// 114 115 /** 116 Mark this instruction as reachable during optimization and return the 117 index to the next instruction. Jump instruction will add their 118 destination to the leads list. 119 */ opt_mark(sp_head * sp,List<sp_instr> * leads)120 virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads) 121 { 122 m_marked= true; 123 return get_ip() + 1; 124 } 125 126 /** 127 Short-cut jumps to jumps during optimization. This is used by the 128 jump instructions' opt_mark() methods. 'start' is the starting point, 129 used to prevent the mark sweep from looping for ever. Return the 130 end destination. 131 */ opt_shortcut_jump(sp_head * sp,sp_instr * start)132 virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) 133 { return get_ip(); } 134 135 /** 136 Inform the instruction that it has been moved during optimization. 137 Most instructions will simply update its index, but jump instructions 138 must also take care of their destination pointers. Forward jumps get 139 pushed to the backpatch list 'ibp'. 140 */ opt_move(uint dst,List<sp_branch_instr> * ibp)141 virtual void opt_move(uint dst, List<sp_branch_instr> *ibp) 142 { m_ip= dst; } 143 opt_is_marked()144 bool opt_is_marked() const 145 { return m_marked; } 146 get_instr_trig_field_list()147 virtual SQL_I_List<Item_trigger_field>* get_instr_trig_field_list() 148 { return NULL; } 149 150 protected: 151 /// Show if this instruction is reachable within the SP 152 /// (used by SP-optimizer). 153 bool m_marked; 154 155 /// Instruction pointer. 156 uint m_ip; 157 158 /// Instruction parsing context. 159 sp_pcontext *m_parsing_ctx; 160 161 private: 162 // Prevent use of copy constructor and assignment operator. 163 sp_instr(const sp_instr &); 164 void operator= (sp_instr &); 165 }; 166 167 /////////////////////////////////////////////////////////////////////////// 168 169 /** 170 sp_lex_instr is a class providing the interface and base implementation 171 for SP-instructions, whose execution is based on expression evaluation. 172 173 sp_lex_instr keeps LEX-object to be able to evaluate the expression. 174 175 sp_lex_instr also provides possibility to re-parse the original query 176 string if for some reason the LEX-object is not valid any longer. 177 */ 178 class sp_lex_instr : public sp_instr 179 { 180 public: sp_lex_instr(uint ip,sp_pcontext * ctx,LEX * lex,bool is_lex_owner)181 sp_lex_instr(uint ip, sp_pcontext *ctx, LEX *lex, bool is_lex_owner) 182 :sp_instr(ip, ctx), 183 m_lex(NULL), 184 m_is_lex_owner(false), 185 m_first_execution(true), 186 m_prelocking_tables(NULL), 187 m_lex_query_tables_own_last(NULL) 188 { 189 set_lex(lex, is_lex_owner); 190 memset(&m_lex_mem_root, 0, sizeof (MEM_ROOT)); 191 } 192 ~sp_lex_instr()193 virtual ~sp_lex_instr() 194 { 195 free_lex(); 196 /* 197 If the instruction is reparsed, m_lex_mem_root was used to allocate 198 the items, then freeing the memroot, frees the items. Also free the 199 items allocated on heap as well. 200 */ 201 if (alloc_root_inited(&m_lex_mem_root)) 202 free_items(); 203 free_root(&m_lex_mem_root, MYF(0)); 204 } 205 206 /** 207 Make a few attempts to execute the instruction. 208 209 Basically, this operation does the following things: 210 - install Reprepare_observer to catch metadata changes (if any); 211 - calls reset_lex_and_exec_core() to execute the instruction; 212 - if the execution fails due to a change in metadata, re-parse the 213 instruction's SQL-statement and repeat execution. 214 215 @param thd Thread context. 216 @param[out] nextp Next instruction pointer 217 @param open_tables Flag to specify if the function should check read 218 access to tables in LEX's table list and open and 219 lock them (used in instructions which need to 220 calculate some expression and don't execute 221 complete statement). 222 223 @return Error status. 224 */ 225 bool validate_lex_and_execute_core(THD *thd, uint *nextp, bool open_tables); 226 get_instr_trig_field_list()227 virtual SQL_I_List<Item_trigger_field>* get_instr_trig_field_list() 228 { return &m_trig_field_list; } 229 230 private: 231 /** 232 Prepare LEX and thread for execution of instruction, if requested open 233 and lock LEX's tables, execute instruction's core function, perform 234 cleanup afterwards. 235 236 @param thd thread context 237 @param nextp[out] next instruction pointer 238 @param open_tables if TRUE then check read access to tables in LEX's table 239 list and open and lock them (used in instructions which 240 need to calculate some expression and don't execute 241 complete statement). 242 243 @note 244 We are not saving/restoring some parts of THD which may need this because 245 we do this once for whole routine execution in sp_head::execute(). 246 247 @return Error status. 248 */ 249 bool reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables); 250 251 /** 252 (Re-)parse the query corresponding to this instruction and return a new 253 LEX-object. 254 255 @param thd Thread context. 256 @param sp The stored program. 257 258 @return new LEX-object or NULL in case of failure. 259 */ 260 LEX *parse_expr(THD *thd, sp_head *sp); 261 262 /** 263 Set LEX-object. 264 265 Previously assigned LEX-object (if any) will be properly cleaned up 266 and destroyed. 267 268 @param lex LEX-object to be used by this instance of sp_lex_instr. 269 @param is_lex_owner the flag specifying if this instance sp_lex_instr 270 owns (and thus deletes when needed) passed LEX-object. 271 */ 272 void set_lex(LEX *lex, bool is_lex_owner); 273 274 /** 275 Cleanup and destroy assigned LEX-object if needed. 276 */ 277 void free_lex(); 278 279 public: 280 ///////////////////////////////////////////////////////////////////////// 281 // sp_instr implementation. 282 ///////////////////////////////////////////////////////////////////////// 283 execute(THD * thd,uint * nextp)284 virtual bool execute(THD *thd, uint *nextp) 285 { return validate_lex_and_execute_core(thd, nextp, true); } 286 287 protected: 288 ///////////////////////////////////////////////////////////////////////// 289 // Interface (virtual) methods. 290 ///////////////////////////////////////////////////////////////////////// 291 292 /** 293 Execute core function of instruction after all preparations 294 (e.g. setting of proper LEX, saving part of the thread context). 295 296 @param thd Thread context. 297 @param nextp[out] next instruction pointer 298 299 @return Error flag. 300 */ 301 virtual bool exec_core(THD *thd, uint *nextp) = 0; 302 303 /** 304 @retval false if the object (i.e. LEX-object) is valid and exec_core() can be 305 just called. 306 307 @retval true if the object is not valid any longer, exec_core() can not be 308 called. The original query string should be re-parsed and a new LEX-object 309 should be used. 310 */ 311 virtual bool is_invalid() const = 0; 312 313 /** 314 Invalidate the object. 315 */ 316 virtual void invalidate() = 0; 317 318 /** 319 Return the query string, which can be passed to the parser. I.e. the 320 operation should return a valid SQL-statement query string. 321 322 @param[out] sql_query SQL-statement query string. 323 */ 324 virtual void get_query(String *sql_query) const; 325 326 /** 327 @return the expression query string. This string can not be passed directly 328 to the parser as it is most likely not a valid SQL-statement. 329 330 @note as it can be seen in the get_query() implementation, get_expr_query() 331 might return EMPTY_STR. EMPTY_STR means that no query-expression is 332 available. That happens when class provides different implementation of 333 get_query(). Strictly speaking, this is a drawback of the current class 334 hierarchy. 335 */ get_expr_query()336 virtual LEX_STRING get_expr_query() const 337 { return EMPTY_STR; } 338 339 /** 340 Callback function which is called after the statement query string is 341 successfully parsed, and the thread context has not been switched to the 342 outer context. The thread context contains new LEX-object corresponding to 343 the parsed query string. 344 345 @param thd Thread context. 346 347 @return Error flag. 348 */ on_after_expr_parsing(THD * thd)349 virtual bool on_after_expr_parsing(THD *thd) 350 { return false; } 351 352 /** 353 Destroy items in the free list before re-parsing the statement query 354 string (and thus, creating new items). 355 356 @param thd Thread context. 357 */ 358 virtual void cleanup_before_parsing(THD *thd); 359 360 /// LEX-object. 361 LEX *m_lex; 362 private: 363 /** 364 Mem-root for storing the LEX-tree during reparse. This 365 mem-root is freed when a reparse is triggered or the stored 366 routine is dropped. 367 */ 368 MEM_ROOT m_lex_mem_root; 369 370 371 /** 372 Indicates whether this sp_lex_instr instance is responsible for 373 LEX-object deletion. 374 */ 375 bool m_is_lex_owner; 376 377 /** 378 Indicates whether exec_core() has not been already called on the current 379 LEX-object. 380 */ 381 bool m_first_execution; 382 383 /***************************************************************************** 384 Support for being able to execute this statement in two modes: 385 a) inside prelocked mode set by the calling procedure or its ancestor. 386 b) outside of prelocked mode, when this statement enters/leaves 387 prelocked mode itself. 388 *****************************************************************************/ 389 390 /** 391 List of additional tables this statement needs to lock when it 392 enters/leaves prelocked mode on its own. 393 */ 394 TABLE_LIST *m_prelocking_tables; 395 396 /** 397 The value m_lex->query_tables_own_last should be set to this when the 398 statement enters/leaves prelocked mode on its own. 399 */ 400 TABLE_LIST **m_lex_query_tables_own_last; 401 402 /** 403 List of all the Item_trigger_field's of instruction. 404 */ 405 SQL_I_List<Item_trigger_field> m_trig_field_list; 406 }; 407 408 /////////////////////////////////////////////////////////////////////////// 409 410 /** 411 sp_instr_stmt represents almost all conventional SQL-statements, which are 412 supported outside stored programs. 413 414 SET-statements, which deal with SP-variable or NEW/OLD trigger pseudo-rows are 415 not represented by this instruction. 416 */ 417 class sp_instr_stmt : public sp_lex_instr 418 { 419 public: sp_instr_stmt(uint ip,LEX * lex,LEX_STRING query)420 sp_instr_stmt(uint ip, 421 LEX *lex, 422 LEX_STRING query) 423 :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true), 424 m_query(query), 425 m_valid(true) 426 { } 427 428 ///////////////////////////////////////////////////////////////////////// 429 // sp_instr implementation. 430 ///////////////////////////////////////////////////////////////////////// 431 432 virtual bool execute(THD *thd, uint *nextp); 433 434 ///////////////////////////////////////////////////////////////////////// 435 // sp_printable implementation. 436 ///////////////////////////////////////////////////////////////////////// 437 438 virtual void print(String *str); 439 440 ///////////////////////////////////////////////////////////////////////// 441 // sp_lex_instr implementation. 442 ///////////////////////////////////////////////////////////////////////// 443 444 virtual bool exec_core(THD *thd, uint *nextp); 445 is_invalid()446 virtual bool is_invalid() const 447 { return !m_valid; } 448 invalidate()449 virtual void invalidate() 450 { m_valid= false; } 451 get_query(String * sql_query)452 virtual void get_query(String *sql_query) const 453 { sql_query->append(m_query.str, m_query.length); } 454 on_after_expr_parsing(THD * thd)455 virtual bool on_after_expr_parsing(THD *thd) 456 { 457 m_valid= true; 458 return false; 459 } 460 461 private: 462 /// Complete query of the SQL-statement. 463 LEX_STRING m_query; 464 465 /// Specify if the stored LEX-object is up-to-date. 466 bool m_valid; 467 }; 468 469 /////////////////////////////////////////////////////////////////////////// 470 471 /** 472 sp_instr_set represents SET-statememnts, which deal with SP-variables. 473 */ 474 class sp_instr_set : public sp_lex_instr 475 { 476 public: sp_instr_set(uint ip,LEX * lex,uint offset,Item * value_item,LEX_STRING value_query,bool is_lex_owner)477 sp_instr_set(uint ip, 478 LEX *lex, 479 uint offset, 480 Item *value_item, 481 LEX_STRING value_query, 482 bool is_lex_owner) 483 :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, is_lex_owner), 484 m_offset(offset), 485 m_value_item(value_item), 486 m_value_query(value_query) 487 { } 488 489 ///////////////////////////////////////////////////////////////////////// 490 // sp_printable implementation. 491 ///////////////////////////////////////////////////////////////////////// 492 493 virtual void print(String *str); 494 495 ///////////////////////////////////////////////////////////////////////// 496 // sp_lex_instr implementation. 497 ///////////////////////////////////////////////////////////////////////// 498 499 virtual bool exec_core(THD *thd, uint *nextp); 500 is_invalid()501 virtual bool is_invalid() const 502 { return m_value_item == NULL; } 503 invalidate()504 virtual void invalidate() 505 { m_value_item= NULL; } 506 on_after_expr_parsing(THD * thd)507 virtual bool on_after_expr_parsing(THD *thd) 508 { 509 DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1); 510 511 m_value_item= thd->lex->select_lex.item_list.head(); 512 513 return false; 514 } 515 get_expr_query()516 virtual LEX_STRING get_expr_query() const 517 { return m_value_query; } 518 519 private: 520 /// Frame offset. 521 uint m_offset; 522 523 /// Value expression item of the SET-statement. 524 Item *m_value_item; 525 526 /// SQL-query corresponding to the value expression. 527 LEX_STRING m_value_query; 528 }; 529 530 /////////////////////////////////////////////////////////////////////////// 531 532 /** 533 sp_instr_set_trigger_field represents SET-statements, which deal with NEW/OLD 534 trigger pseudo-rows. 535 */ 536 class sp_instr_set_trigger_field : public sp_lex_instr 537 { 538 public: sp_instr_set_trigger_field(uint ip,LEX * lex,LEX_STRING trigger_field_name,Item_trigger_field * trigger_field,Item * value_item,LEX_STRING value_query)539 sp_instr_set_trigger_field(uint ip, 540 LEX *lex, 541 LEX_STRING trigger_field_name, 542 Item_trigger_field *trigger_field, 543 Item *value_item, 544 LEX_STRING value_query) 545 :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true), 546 m_trigger_field_name(trigger_field_name), 547 m_trigger_field(trigger_field), 548 m_value_item(value_item), 549 m_value_query(value_query) 550 { } 551 552 ///////////////////////////////////////////////////////////////////////// 553 // sp_printable implementation. 554 ///////////////////////////////////////////////////////////////////////// 555 556 virtual void print(String *str); 557 558 ///////////////////////////////////////////////////////////////////////// 559 // sp_lex_instr implementation. 560 ///////////////////////////////////////////////////////////////////////// 561 562 virtual bool exec_core(THD *thd, uint *nextp); 563 is_invalid()564 virtual bool is_invalid() const 565 { return m_value_item == NULL; } 566 invalidate()567 virtual void invalidate() 568 { m_value_item= NULL; } 569 570 virtual bool on_after_expr_parsing(THD *thd); 571 572 virtual void cleanup_before_parsing(THD *thd); 573 get_expr_query()574 virtual LEX_STRING get_expr_query() const 575 { return m_value_query; } 576 577 private: 578 /// Trigger field name ("field_name" of the "NEW.field_name"). 579 LEX_STRING m_trigger_field_name; 580 581 /// Item corresponding to the NEW/OLD trigger field. 582 Item_trigger_field *m_trigger_field; 583 584 /// Value expression item of the SET-statement. 585 Item *m_value_item; 586 587 /// SQL-query corresponding to the value expression. 588 LEX_STRING m_value_query; 589 }; 590 591 /////////////////////////////////////////////////////////////////////////// 592 593 /** 594 sp_instr_freturn represents RETURN statement in stored functions. 595 */ 596 class sp_instr_freturn : public sp_lex_instr 597 { 598 public: sp_instr_freturn(uint ip,LEX * lex,Item * expr_item,LEX_STRING expr_query,enum enum_field_types return_field_type)599 sp_instr_freturn(uint ip, 600 LEX *lex, 601 Item *expr_item, 602 LEX_STRING expr_query, 603 enum enum_field_types return_field_type) 604 :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true), 605 m_expr_item(expr_item), 606 m_expr_query(expr_query), 607 m_return_field_type(return_field_type) 608 { } 609 610 ///////////////////////////////////////////////////////////////////////// 611 // sp_printable implementation. 612 ///////////////////////////////////////////////////////////////////////// 613 614 virtual void print(String *str); 615 616 ///////////////////////////////////////////////////////////////////////// 617 // sp_instr implementation. 618 ///////////////////////////////////////////////////////////////////////// 619 opt_mark(sp_head * sp,List<sp_instr> * leads)620 virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads) 621 { 622 m_marked= true; 623 return UINT_MAX; 624 } 625 626 ///////////////////////////////////////////////////////////////////////// 627 // sp_lex_instr implementation. 628 ///////////////////////////////////////////////////////////////////////// 629 630 virtual bool exec_core(THD *thd, uint *nextp); 631 is_invalid()632 virtual bool is_invalid() const 633 { return m_expr_item == NULL; } 634 invalidate()635 virtual void invalidate() 636 { 637 // it's already deleted. 638 m_expr_item= NULL; 639 } 640 on_after_expr_parsing(THD * thd)641 virtual bool on_after_expr_parsing(THD *thd) 642 { 643 DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1); 644 645 m_expr_item= thd->lex->select_lex.item_list.head(); 646 647 return false; 648 } 649 get_expr_query()650 virtual LEX_STRING get_expr_query() const 651 { return m_expr_query; } 652 653 private: 654 /// RETURN-expression item. 655 Item *m_expr_item; 656 657 /// SQL-query corresponding to the RETURN-expression. 658 LEX_STRING m_expr_query; 659 660 /// RETURN-field type code. 661 enum enum_field_types m_return_field_type; 662 }; 663 664 /////////////////////////////////////////////////////////////////////////// 665 666 /** 667 This is base class for all kinds of jump instructions. 668 669 @note this is the only class, we directly construct instances of, that has 670 subclasses. We also redefine sp_instr_jump behavior in those subclasses. 671 672 @todo later we will consider introducing a new class, which will be the base 673 for sp_instr_jump, sp_instr_set_case_expr and sp_instr_jump_case_when. 674 Something like sp_regular_branch_instr (similar to sp_lex_branch_instr). 675 */ 676 class sp_instr_jump : public sp_instr, 677 public sp_branch_instr 678 { 679 public: sp_instr_jump(uint ip,sp_pcontext * ctx)680 sp_instr_jump(uint ip, sp_pcontext *ctx) 681 :sp_instr(ip, ctx), 682 m_dest(0), 683 m_optdest(NULL) 684 { } 685 sp_instr_jump(uint ip,sp_pcontext * ctx,uint dest)686 sp_instr_jump(uint ip, sp_pcontext *ctx, uint dest) 687 :sp_instr(ip, ctx), 688 m_dest(dest), 689 m_optdest(NULL) 690 { } 691 692 ///////////////////////////////////////////////////////////////////////// 693 // sp_printable implementation. 694 ///////////////////////////////////////////////////////////////////////// 695 696 virtual void print(String *str); 697 698 ///////////////////////////////////////////////////////////////////////// 699 // sp_instr implementation. 700 ///////////////////////////////////////////////////////////////////////// 701 execute(THD * thd,uint * nextp)702 virtual bool execute(THD *thd, uint *nextp) 703 { 704 *nextp= m_dest; 705 return false; 706 } 707 708 virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); 709 710 virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start); 711 712 virtual void opt_move(uint dst, List<sp_branch_instr> *ibp); 713 714 ///////////////////////////////////////////////////////////////////////// 715 // sp_branch_instr implementation. 716 ///////////////////////////////////////////////////////////////////////// 717 set_destination(uint old_dest,uint new_dest)718 virtual void set_destination(uint old_dest, uint new_dest) 719 { 720 if (m_dest == old_dest) 721 m_dest= new_dest; 722 } 723 backpatch(uint dest)724 virtual void backpatch(uint dest) 725 { 726 /* Calling backpatch twice is a logic flaw in jump resolution. */ 727 DBUG_ASSERT(m_dest == 0); 728 m_dest= dest; 729 } 730 731 protected: 732 /// Where we will go. 733 uint m_dest; 734 735 // The following attribute is used by SP-optimizer. 736 sp_instr *m_optdest; 737 }; 738 739 /////////////////////////////////////////////////////////////////////////// 740 741 /** 742 sp_lex_branch_instr is a base class for SP-instructions, which might perform 743 conditional jump depending on the value of an SQL-expression. 744 */ 745 class sp_lex_branch_instr : public sp_lex_instr, 746 public sp_branch_instr 747 { 748 protected: sp_lex_branch_instr(uint ip,sp_pcontext * ctx,LEX * lex,Item * expr_item,LEX_STRING expr_query)749 sp_lex_branch_instr(uint ip, sp_pcontext *ctx, LEX *lex, 750 Item *expr_item, LEX_STRING expr_query) 751 :sp_lex_instr(ip, ctx, lex, true), 752 m_dest(0), 753 m_cont_dest(0), 754 m_optdest(NULL), 755 m_cont_optdest(NULL), 756 m_expr_item(expr_item), 757 m_expr_query(expr_query) 758 { } 759 sp_lex_branch_instr(uint ip,sp_pcontext * ctx,LEX * lex,Item * expr_item,LEX_STRING expr_query,uint dest)760 sp_lex_branch_instr(uint ip, sp_pcontext *ctx, LEX *lex, 761 Item *expr_item, LEX_STRING expr_query, 762 uint dest) 763 :sp_lex_instr(ip, ctx, lex, true), 764 m_dest(dest), 765 m_cont_dest(0), 766 m_optdest(NULL), 767 m_cont_optdest(NULL), 768 m_expr_item(expr_item), 769 m_expr_query(expr_query) 770 { } 771 772 public: set_cont_dest(uint cont_dest)773 void set_cont_dest(uint cont_dest) 774 { m_cont_dest= cont_dest; } 775 776 ///////////////////////////////////////////////////////////////////////// 777 // sp_instr implementation. 778 ///////////////////////////////////////////////////////////////////////// 779 780 virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); 781 782 virtual void opt_move(uint dst, List<sp_branch_instr> *ibp); 783 get_cont_dest()784 virtual uint get_cont_dest() const 785 { return m_cont_dest; } 786 787 ///////////////////////////////////////////////////////////////////////// 788 // sp_lex_instr implementation. 789 ///////////////////////////////////////////////////////////////////////// 790 is_invalid()791 virtual bool is_invalid() const 792 { return m_expr_item == NULL; } 793 invalidate()794 virtual void invalidate() 795 { m_expr_item= NULL; /* it's already deleted. */ } 796 get_expr_query()797 virtual LEX_STRING get_expr_query() const 798 { return m_expr_query; } 799 800 ///////////////////////////////////////////////////////////////////////// 801 // sp_branch_instr implementation. 802 ///////////////////////////////////////////////////////////////////////// 803 set_destination(uint old_dest,uint new_dest)804 virtual void set_destination(uint old_dest, uint new_dest) 805 { 806 if (m_dest == old_dest) 807 m_dest= new_dest; 808 809 if (m_cont_dest == old_dest) 810 m_cont_dest= new_dest; 811 } 812 backpatch(uint dest)813 virtual void backpatch(uint dest) 814 { 815 /* Calling backpatch twice is a logic flaw in jump resolution. */ 816 DBUG_ASSERT(m_dest == 0); 817 m_dest= dest; 818 } 819 820 protected: 821 /// Where we will go. 822 uint m_dest; 823 824 /// Where continue handlers will go. 825 uint m_cont_dest; 826 827 // The following attributes are used by SP-optimizer. 828 sp_instr *m_optdest; 829 sp_instr *m_cont_optdest; 830 831 /// Expression item. 832 Item *m_expr_item; 833 834 /// SQL-query corresponding to the expression. 835 LEX_STRING m_expr_query; 836 }; 837 838 /////////////////////////////////////////////////////////////////////////// 839 840 /** 841 sp_instr_jump_if_not implements SP-instruction, which does the jump if its 842 SQL-expression is false. 843 */ 844 class sp_instr_jump_if_not : public sp_lex_branch_instr 845 { 846 public: sp_instr_jump_if_not(uint ip,LEX * lex,Item * expr_item,LEX_STRING expr_query)847 sp_instr_jump_if_not(uint ip, 848 LEX *lex, 849 Item *expr_item, 850 LEX_STRING expr_query) 851 :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex, 852 expr_item, expr_query) 853 { } 854 sp_instr_jump_if_not(uint ip,LEX * lex,Item * expr_item,LEX_STRING expr_query,uint dest)855 sp_instr_jump_if_not(uint ip, 856 LEX *lex, 857 Item *expr_item, 858 LEX_STRING expr_query, 859 uint dest) 860 :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex, 861 expr_item, expr_query, dest) 862 { } 863 864 ///////////////////////////////////////////////////////////////////////// 865 // sp_printable implementation. 866 ///////////////////////////////////////////////////////////////////////// 867 868 virtual void print(String *str); 869 870 ///////////////////////////////////////////////////////////////////////// 871 // sp_lex_instr implementation. 872 ///////////////////////////////////////////////////////////////////////// 873 874 virtual bool exec_core(THD *thd, uint *nextp); 875 on_after_expr_parsing(THD * thd)876 virtual bool on_after_expr_parsing(THD *thd) 877 { 878 DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1); 879 880 m_expr_item= thd->lex->select_lex.item_list.head(); 881 882 return false; 883 } 884 }; 885 886 /////////////////////////////////////////////////////////////////////////// 887 // Instructions used for the "simple CASE" implementation. 888 /////////////////////////////////////////////////////////////////////////// 889 890 /** 891 sp_instr_set_case_expr is used in the "simple CASE" implementation to evaluate 892 and store the CASE-expression in the runtime context. 893 */ 894 class sp_instr_set_case_expr : public sp_lex_branch_instr 895 { 896 public: sp_instr_set_case_expr(uint ip,LEX * lex,uint case_expr_id,Item * case_expr_item,LEX_STRING case_expr_query)897 sp_instr_set_case_expr(uint ip, 898 LEX *lex, 899 uint case_expr_id, 900 Item *case_expr_item, 901 LEX_STRING case_expr_query) 902 :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex, 903 case_expr_item, case_expr_query), 904 m_case_expr_id(case_expr_id) 905 { } 906 907 ///////////////////////////////////////////////////////////////////////// 908 // sp_printable implementation. 909 ///////////////////////////////////////////////////////////////////////// 910 911 virtual void print(String *str); 912 913 ///////////////////////////////////////////////////////////////////////// 914 // sp_instr implementation. 915 ///////////////////////////////////////////////////////////////////////// 916 917 virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); 918 919 virtual void opt_move(uint dst, List<sp_branch_instr> *ibp); 920 921 ///////////////////////////////////////////////////////////////////////// 922 // sp_branch_instr implementation. 923 ///////////////////////////////////////////////////////////////////////// 924 925 /* 926 NOTE: set_destination() and backpatch() are overriden here just because the 927 m_dest attribute is not used by this class, so there is no need to do 928 anything about it. 929 930 @todo These operations probably should be left as they are (i.e. do not 931 override them here). The m_dest attribute would be set and not used, but 932 that should not be a big deal. 933 934 @todo This also indicates deficiency of the current SP-istruction class 935 hierarchy. 936 */ 937 set_destination(uint old_dest,uint new_dest)938 virtual void set_destination(uint old_dest, uint new_dest) 939 { 940 if (m_cont_dest == old_dest) 941 m_cont_dest= new_dest; 942 } 943 backpatch(uint dest)944 virtual void backpatch(uint dest) 945 { } 946 947 ///////////////////////////////////////////////////////////////////////// 948 // sp_lex_instr implementation. 949 ///////////////////////////////////////////////////////////////////////// 950 951 virtual bool exec_core(THD *thd, uint *nextp); 952 on_after_expr_parsing(THD * thd)953 virtual bool on_after_expr_parsing(THD *thd) 954 { 955 DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1); 956 957 m_expr_item= thd->lex->select_lex.item_list.head(); 958 959 return false; 960 } 961 962 private: 963 /// Identifier (index) of the CASE-expression in the runtime context. 964 uint m_case_expr_id; 965 }; 966 967 /////////////////////////////////////////////////////////////////////////// 968 969 /** 970 sp_instr_jump_case_when instruction is used in the "simple CASE" 971 implementation. It's a jump instruction with the following condition: 972 (CASE-expression = WHEN-expression) 973 CASE-expression is retrieved from sp_rcontext; 974 WHEN-expression is kept by this instruction. 975 */ 976 class sp_instr_jump_case_when : public sp_lex_branch_instr 977 { 978 public: sp_instr_jump_case_when(uint ip,LEX * lex,int case_expr_id,Item * when_expr_item,LEX_STRING when_expr_query)979 sp_instr_jump_case_when(uint ip, 980 LEX *lex, 981 int case_expr_id, 982 Item *when_expr_item, 983 LEX_STRING when_expr_query) 984 :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex, 985 when_expr_item, when_expr_query), 986 m_case_expr_id(case_expr_id) 987 { } 988 989 ///////////////////////////////////////////////////////////////////////// 990 // sp_printable implementation. 991 ///////////////////////////////////////////////////////////////////////// 992 993 virtual void print(String *str); 994 995 ///////////////////////////////////////////////////////////////////////// 996 // sp_lex_instr implementation. 997 ///////////////////////////////////////////////////////////////////////// 998 999 virtual bool exec_core(THD *thd, uint *nextp); 1000 invalidate()1001 virtual void invalidate() 1002 { 1003 // Items should be already deleted in lex-keeper. 1004 m_case_expr_item= NULL; 1005 m_eq_item= NULL; 1006 m_expr_item= NULL; // it's a WHEN-expression. 1007 } 1008 on_after_expr_parsing(THD * thd)1009 virtual bool on_after_expr_parsing(THD *thd) 1010 { return build_expr_items(thd); } 1011 1012 private: 1013 /** 1014 Build CASE-expression item tree: 1015 Item_func_eq(case-expression, when-i-expression) 1016 1017 This function is used for the following form of CASE statement: 1018 CASE case-expression 1019 WHEN when-1-expression THEN ... 1020 WHEN when-2-expression THEN ... 1021 ... 1022 WHEN when-n-expression THEN ... 1023 END CASE 1024 1025 The thing is that after the parsing we have an item (item tree) for the 1026 case-expression and for each when-expression. Here we build jump 1027 conditions: expressions like (case-expression = when-i-expression). 1028 1029 @param thd Thread context. 1030 1031 @return Error flag. 1032 */ 1033 bool build_expr_items(THD *thd); 1034 1035 private: 1036 /// Identifier (index) of the CASE-expression in the runtime context. 1037 int m_case_expr_id; 1038 1039 /// Item representing the CASE-expression. 1040 Item_case_expr *m_case_expr_item; 1041 1042 /** 1043 Item corresponding to the main item of the jump-condition-expression: 1044 it's the equal function (=) in the (case-expression = when-i-expression) 1045 expression. 1046 */ 1047 Item *m_eq_item; 1048 }; 1049 1050 /////////////////////////////////////////////////////////////////////////// 1051 // SQL-condition handler instructions. 1052 /////////////////////////////////////////////////////////////////////////// 1053 1054 class sp_instr_hpush_jump : public sp_instr_jump 1055 { 1056 public: sp_instr_hpush_jump(uint ip,sp_pcontext * ctx,sp_handler * handler)1057 sp_instr_hpush_jump(uint ip, 1058 sp_pcontext *ctx, 1059 sp_handler *handler) 1060 :sp_instr_jump(ip, ctx), 1061 m_handler(handler), 1062 m_opt_hpop(0), 1063 m_frame(ctx->current_var_count()) 1064 { 1065 DBUG_ASSERT(m_handler->condition_values.elements == 0); 1066 } 1067 ~sp_instr_hpush_jump()1068 virtual ~sp_instr_hpush_jump() 1069 { 1070 m_handler->condition_values.empty(); 1071 m_handler= NULL; 1072 } 1073 add_condition(sp_condition_value * condition_value)1074 void add_condition(sp_condition_value *condition_value) 1075 { m_handler->condition_values.push_back(condition_value); } 1076 get_handler()1077 sp_handler *get_handler() 1078 { return m_handler; } 1079 1080 ///////////////////////////////////////////////////////////////////////// 1081 // sp_printable implementation. 1082 ///////////////////////////////////////////////////////////////////////// 1083 1084 virtual void print(String *str); 1085 1086 ///////////////////////////////////////////////////////////////////////// 1087 // sp_instr implementation. 1088 ///////////////////////////////////////////////////////////////////////// 1089 1090 virtual bool execute(THD *thd, uint *nextp); 1091 1092 virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); 1093 1094 /** Override sp_instr_jump's shortcut; we stop here. */ opt_shortcut_jump(sp_head * sp,sp_instr * start)1095 virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) 1096 { return get_ip(); } 1097 1098 ///////////////////////////////////////////////////////////////////////// 1099 // sp_branch_instr implementation. 1100 ///////////////////////////////////////////////////////////////////////// 1101 backpatch(uint dest)1102 virtual void backpatch(uint dest) 1103 { 1104 DBUG_ASSERT(!m_dest || !m_opt_hpop); 1105 if (!m_dest) 1106 m_dest= dest; 1107 else 1108 m_opt_hpop= dest; 1109 } 1110 1111 private: 1112 /// Handler. 1113 sp_handler *m_handler; 1114 1115 /// hpop marking end of handler scope. 1116 uint m_opt_hpop; 1117 1118 // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in 1119 // debug version only). It's used in print(). 1120 uint m_frame; 1121 }; 1122 1123 /////////////////////////////////////////////////////////////////////////// 1124 1125 class sp_instr_hpop : public sp_instr 1126 { 1127 public: sp_instr_hpop(uint ip,sp_pcontext * ctx)1128 sp_instr_hpop(uint ip, sp_pcontext *ctx) 1129 : sp_instr(ip, ctx) 1130 { } 1131 1132 ///////////////////////////////////////////////////////////////////////// 1133 // sp_printable implementation. 1134 ///////////////////////////////////////////////////////////////////////// 1135 print(String * str)1136 virtual void print(String *str) 1137 { str->append(STRING_WITH_LEN("hpop")); } 1138 1139 ///////////////////////////////////////////////////////////////////////// 1140 // sp_instr implementation. 1141 ///////////////////////////////////////////////////////////////////////// 1142 1143 virtual bool execute(THD *thd, uint *nextp); 1144 }; 1145 1146 /////////////////////////////////////////////////////////////////////////// 1147 1148 class sp_instr_hreturn : public sp_instr_jump 1149 { 1150 public: sp_instr_hreturn(uint ip,sp_pcontext * ctx)1151 sp_instr_hreturn(uint ip, sp_pcontext *ctx) 1152 :sp_instr_jump(ip, ctx), 1153 m_frame(ctx->current_var_count()) 1154 { } 1155 1156 ///////////////////////////////////////////////////////////////////////// 1157 // sp_printable implementation. 1158 ///////////////////////////////////////////////////////////////////////// 1159 1160 virtual void print(String *str); 1161 1162 ///////////////////////////////////////////////////////////////////////// 1163 // sp_instr implementation. 1164 ///////////////////////////////////////////////////////////////////////// 1165 1166 virtual bool execute(THD *thd, uint *nextp); 1167 1168 /** Override sp_instr_jump's shortcut; we stop here. */ opt_shortcut_jump(sp_head * sp,sp_instr * start)1169 virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) 1170 { return get_ip(); } 1171 1172 virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); 1173 1174 private: 1175 // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in 1176 // debug version only). It's used in print(). 1177 uint m_frame; 1178 }; 1179 1180 /////////////////////////////////////////////////////////////////////////// 1181 // Cursor implementation. 1182 /////////////////////////////////////////////////////////////////////////// 1183 1184 /** 1185 sp_instr_cpush corresponds to DECLARE CURSOR, implements DECLARE CURSOR and 1186 OPEN. 1187 1188 This is the most important instruction in cursor implementation. It is created 1189 and added to sp_head when DECLARE CURSOR is being parsed. The arena of this 1190 instruction contains LEX-object for the cursor's SELECT-statement. 1191 1192 This instruction is actually used to open the cursor. 1193 1194 execute() operation "implements" DECLARE CURSOR statement -- it merely pushes 1195 a new cursor object into the stack in sp_rcontext object. 1196 1197 exec_core() operation implements OPEN statement. It is important to implement 1198 OPEN statement in this instruction, because OPEN may lead to re-parsing of the 1199 SELECT-statement. So, the original Arena and parsing context must be used. 1200 */ 1201 class sp_instr_cpush : public sp_lex_instr 1202 { 1203 public: sp_instr_cpush(uint ip,sp_pcontext * ctx,LEX * cursor_lex,LEX_STRING cursor_query,int cursor_idx)1204 sp_instr_cpush(uint ip, 1205 sp_pcontext *ctx, 1206 LEX *cursor_lex, 1207 LEX_STRING cursor_query, 1208 int cursor_idx) 1209 :sp_lex_instr(ip, ctx, cursor_lex, true), 1210 m_cursor_query(cursor_query), 1211 m_valid(true), 1212 m_cursor_idx(cursor_idx) 1213 { 1214 // Cursor can't be stored in Query Cache, so we should prevent opening QC 1215 // for try to write results which are absent. 1216 1217 cursor_lex->safe_to_cache_query= false; 1218 } 1219 1220 ///////////////////////////////////////////////////////////////////////// 1221 // sp_printable implementation. 1222 ///////////////////////////////////////////////////////////////////////// 1223 1224 virtual void print(String *str); 1225 1226 ///////////////////////////////////////////////////////////////////////// 1227 // Query_arena implementation. 1228 ///////////////////////////////////////////////////////////////////////// 1229 1230 /** 1231 This call is used to cleanup the instruction when a sensitive 1232 cursor is closed. For now stored procedures always use materialized 1233 cursors and the call is not used. 1234 */ cleanup_stmt()1235 virtual void cleanup_stmt() 1236 { /* no op */ } 1237 1238 ///////////////////////////////////////////////////////////////////////// 1239 // sp_instr implementation. 1240 ///////////////////////////////////////////////////////////////////////// 1241 1242 virtual bool execute(THD *thd, uint *nextp); 1243 1244 ///////////////////////////////////////////////////////////////////////// 1245 // sp_lex_instr implementation. 1246 ///////////////////////////////////////////////////////////////////////// 1247 1248 virtual bool exec_core(THD *thd, uint *nextp); 1249 is_invalid()1250 virtual bool is_invalid() const 1251 { return !m_valid; } 1252 invalidate()1253 virtual void invalidate() 1254 { m_valid= false; } 1255 get_query(String * sql_query)1256 virtual void get_query(String *sql_query) const 1257 { sql_query->append(m_cursor_query.str, m_cursor_query.length); } 1258 on_after_expr_parsing(THD * thd)1259 virtual bool on_after_expr_parsing(THD *thd) 1260 { 1261 m_valid= true; 1262 return false; 1263 } 1264 1265 private: 1266 /// This attribute keeps the cursor SELECT statement. 1267 LEX_STRING m_cursor_query; 1268 1269 /// Flag if the LEX-object of this instruction is valid or not. 1270 /// The LEX-object is not valid when metadata have changed. 1271 bool m_valid; 1272 1273 /// Used to identify the cursor in the sp_rcontext. 1274 int m_cursor_idx; 1275 }; 1276 1277 /////////////////////////////////////////////////////////////////////////// 1278 1279 /** 1280 sp_instr_cpop instruction is added at the end of BEGIN..END block. 1281 It's used to remove declared cursors so that they are not visible any longer. 1282 */ 1283 class sp_instr_cpop : public sp_instr 1284 { 1285 public: sp_instr_cpop(uint ip,sp_pcontext * ctx,uint count)1286 sp_instr_cpop(uint ip, sp_pcontext *ctx, uint count) 1287 :sp_instr(ip, ctx), 1288 m_count(count) 1289 { } 1290 1291 ///////////////////////////////////////////////////////////////////////// 1292 // sp_printable implementation. 1293 ///////////////////////////////////////////////////////////////////////// 1294 1295 virtual void print(String *str); 1296 1297 ///////////////////////////////////////////////////////////////////////// 1298 // sp_instr implementation. 1299 ///////////////////////////////////////////////////////////////////////// 1300 1301 virtual bool execute(THD *thd, uint *nextp); 1302 1303 private: 1304 uint m_count; 1305 }; 1306 1307 /////////////////////////////////////////////////////////////////////////// 1308 1309 /** 1310 sp_instr_copen represents OPEN statement (opens the cursor). 1311 However, the actual implementation is in sp_instr_cpush::exec_core(). 1312 */ 1313 class sp_instr_copen : public sp_instr 1314 { 1315 public: sp_instr_copen(uint ip,sp_pcontext * ctx,int cursor_idx)1316 sp_instr_copen(uint ip, sp_pcontext *ctx, int cursor_idx) 1317 :sp_instr(ip, ctx), 1318 m_cursor_idx(cursor_idx) 1319 { } 1320 1321 ///////////////////////////////////////////////////////////////////////// 1322 // sp_printable implementation. 1323 ///////////////////////////////////////////////////////////////////////// 1324 1325 virtual void print(String *str); 1326 1327 ///////////////////////////////////////////////////////////////////////// 1328 // sp_instr implementation. 1329 ///////////////////////////////////////////////////////////////////////// 1330 1331 virtual bool execute(THD *thd, uint *nextp); 1332 1333 private: 1334 /// Used to identify the cursor in the sp_rcontext. 1335 int m_cursor_idx; 1336 }; 1337 1338 /////////////////////////////////////////////////////////////////////////// 1339 1340 /** 1341 The instruction corresponds to the CLOSE statement. 1342 It just forwards the close-call to the appropriate sp_cursor object in the 1343 sp_rcontext. 1344 */ 1345 class sp_instr_cclose : public sp_instr 1346 { 1347 public: sp_instr_cclose(uint ip,sp_pcontext * ctx,int cursor_idx)1348 sp_instr_cclose(uint ip, sp_pcontext *ctx, int cursor_idx) 1349 :sp_instr(ip, ctx), 1350 m_cursor_idx(cursor_idx) 1351 { } 1352 1353 ///////////////////////////////////////////////////////////////////////// 1354 // sp_printable implementation. 1355 ///////////////////////////////////////////////////////////////////////// 1356 1357 virtual void print(String *str); 1358 1359 ///////////////////////////////////////////////////////////////////////// 1360 // sp_instr implementation. 1361 ///////////////////////////////////////////////////////////////////////// 1362 1363 virtual bool execute(THD *thd, uint *nextp); 1364 1365 private: 1366 /// Used to identify the cursor in the sp_rcontext. 1367 int m_cursor_idx; 1368 }; 1369 1370 /////////////////////////////////////////////////////////////////////////// 1371 1372 /** 1373 The instruction corresponds to the FETCH statement. 1374 It just forwards the close-call to the appropriate sp_cursor object in the 1375 sp_rcontext. 1376 */ 1377 class sp_instr_cfetch : public sp_instr 1378 { 1379 public: sp_instr_cfetch(uint ip,sp_pcontext * ctx,int cursor_idx)1380 sp_instr_cfetch(uint ip, sp_pcontext *ctx, int cursor_idx) 1381 :sp_instr(ip, ctx), 1382 m_cursor_idx(cursor_idx) 1383 { } 1384 1385 ///////////////////////////////////////////////////////////////////////// 1386 // sp_printable implementation. 1387 ///////////////////////////////////////////////////////////////////////// 1388 1389 virtual void print(String *str); 1390 1391 ///////////////////////////////////////////////////////////////////////// 1392 // sp_instr implementation. 1393 ///////////////////////////////////////////////////////////////////////// 1394 1395 virtual bool execute(THD *thd, uint *nextp); 1396 add_to_varlist(sp_variable * var)1397 void add_to_varlist(sp_variable *var) 1398 { m_varlist.push_back(var); } 1399 1400 private: 1401 /// List of SP-variables to store fetched values. 1402 List<sp_variable> m_varlist; 1403 1404 /// Used to identify the cursor in the sp_rcontext. 1405 int m_cursor_idx; 1406 }; 1407 1408 /////////////////////////////////////////////////////////////////////////// 1409 /////////////////////////////////////////////////////////////////////////// 1410 1411 /** 1412 sp_instr_error just throws an SQL-condition if the execution flow comes to it. 1413 It's used in the CASE implementation to perform runtime-check that the 1414 CASE-expression is handled by some WHEN/ELSE clause. 1415 */ 1416 class sp_instr_error : public sp_instr 1417 { 1418 public: sp_instr_error(uint ip,sp_pcontext * ctx,int errcode)1419 sp_instr_error(uint ip, sp_pcontext *ctx, int errcode) 1420 :sp_instr(ip, ctx), 1421 m_errcode(errcode) 1422 { } 1423 1424 ///////////////////////////////////////////////////////////////////////// 1425 // sp_printable implementation. 1426 ///////////////////////////////////////////////////////////////////////// 1427 1428 virtual void print(String *str); 1429 1430 ///////////////////////////////////////////////////////////////////////// 1431 // sp_instr implementation. 1432 ///////////////////////////////////////////////////////////////////////// 1433 execute(THD * thd,uint * nextp)1434 virtual bool execute(THD *thd, uint *nextp) 1435 { 1436 my_message(m_errcode, ER(m_errcode), MYF(0)); 1437 *nextp= get_ip() + 1; 1438 return true; 1439 } 1440 opt_mark(sp_head * sp,List<sp_instr> * leads)1441 virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads) 1442 { 1443 m_marked= true; 1444 return UINT_MAX; 1445 } 1446 1447 private: 1448 /// The error code, which should be raised by this instruction. 1449 int m_errcode; 1450 }; 1451 1452 /////////////////////////////////////////////////////////////////////////// 1453 1454 #endif // _SP_INSTR_H_ 1455