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