1 /* -*- C++ -*- */ 2 /* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; version 2 of the License. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program; if not, write to the Free Software 15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ 16 17 #ifndef _SP_RCONTEXT_H_ 18 #define _SP_RCONTEXT_H_ 19 20 #ifdef USE_PRAGMA_INTERFACE 21 #pragma interface /* gcc class implementation */ 22 #endif 23 24 #include "sql_class.h" // select_result_interceptor 25 #include "sp_pcontext.h" // sp_condition_value 26 27 /////////////////////////////////////////////////////////////////////////// 28 // sp_rcontext declaration. 29 /////////////////////////////////////////////////////////////////////////// 30 31 class sp_cursor; 32 class sp_lex_keeper; 33 class sp_instr_cpush; 34 class sp_instr_hpush_jump; 35 class Query_arena; 36 class sp_head; 37 class Item_cache; 38 class Virtual_tmp_table; 39 40 41 /* 42 This class is a runtime context of a Stored Routine. It is used in an 43 execution and is intended to contain all dynamic objects (i.e. objects, which 44 can be changed during execution), such as: 45 - stored routine variables; 46 - cursors; 47 - handlers; 48 49 Runtime context is used with sp_head class. sp_head class is intended to 50 contain all static things, related to the stored routines (code, for example). 51 sp_head instance creates runtime context for the execution of a stored 52 routine. 53 54 There is a parsing context (an instance of sp_pcontext class), which is used 55 on parsing stage. However, now it contains some necessary for an execution 56 things, such as definition of used stored routine variables. That's why 57 runtime context needs a reference to the parsing context. 58 */ 59 60 class sp_rcontext : public Sql_alloc 61 { 62 public: 63 /// Construct and properly initialize a new sp_rcontext instance. The static 64 /// create-function is needed because we need a way to return an error from 65 /// the constructor. 66 /// 67 /// @param thd Thread handle. 68 /// @param root_parsing_ctx Top-level parsing context for this stored program. 69 /// @param return_value_fld Field object to store the return value 70 /// (for stored functions only). 71 /// 72 /// @return valid sp_rcontext object or NULL in case of OOM-error. 73 static sp_rcontext *create(THD *thd, 74 const sp_head *owner, 75 const sp_pcontext *root_parsing_ctx, 76 Field *return_value_fld, 77 Row_definition_list &defs); 78 79 ~sp_rcontext(); 80 81 private: 82 sp_rcontext(const sp_head *owner, 83 const sp_pcontext *root_parsing_ctx, 84 Field *return_value_fld, 85 bool in_sub_stmt); 86 87 // Prevent use of copying constructor and operator. 88 sp_rcontext(const sp_rcontext &); 89 void operator=(sp_rcontext &); 90 91 public: 92 /// This class stores basic information about SQL-condition, such as: 93 /// - SQL error code; 94 /// - error level; 95 /// - SQLSTATE; 96 /// - text message. 97 /// 98 /// It's used to organize runtime SQL-handler call stack. 99 /// 100 /// Standard Sql_condition class can not be used, because we don't always have 101 /// an Sql_condition object for an SQL-condition in Diagnostics_area. 102 /// 103 /// Eventually, this class should be moved to sql_error.h, and be a part of 104 /// standard SQL-condition processing (Diagnostics_area should contain an 105 /// object for active SQL-condition, not just information stored in DA's 106 /// fields). 107 class Sql_condition_info : public Sql_alloc, 108 public Sql_condition_identity 109 { 110 public: 111 /// Text message. 112 char *message; 113 114 /// The constructor. 115 /// 116 /// @param _sql_condition The SQL condition. 117 /// @param arena Query arena for SP Sql_condition_info(const Sql_condition * _sql_condition,Query_arena * arena)118 Sql_condition_info(const Sql_condition *_sql_condition, 119 Query_arena *arena) 120 :Sql_condition_identity(*_sql_condition) 121 { 122 message= strdup_root(arena->mem_root, _sql_condition->get_message_text()); 123 } 124 }; 125 126 private: 127 /// This class represents a call frame of SQL-handler (one invocation of a 128 /// handler). Basically, it's needed to store continue instruction pointer for 129 /// CONTINUE SQL-handlers. 130 class Handler_call_frame : public Sql_alloc 131 { 132 public: 133 /// SQL-condition, triggered handler activation. 134 const Sql_condition_info *sql_condition; 135 136 /// Continue-instruction-pointer for CONTINUE-handlers. 137 /// The attribute contains 0 for EXIT-handlers. 138 uint continue_ip; 139 140 /// The constructor. 141 /// 142 /// @param _sql_condition SQL-condition, triggered handler activation. 143 /// @param _continue_ip Continue instruction pointer. Handler_call_frame(const Sql_condition_info * _sql_condition,uint _continue_ip)144 Handler_call_frame(const Sql_condition_info *_sql_condition, 145 uint _continue_ip) 146 :sql_condition(_sql_condition), 147 continue_ip(_continue_ip) 148 { } 149 }; 150 151 public: 152 /// Arena used to (re) allocate items on. E.g. reallocate INOUT/OUT 153 /// SP-variables when they don't fit into prealloced items. This is common 154 /// situation with String items. It is used mainly in sp_eval_func_item(). 155 Query_arena *callers_arena; 156 157 /// Flag to end an open result set before start executing an SQL-handler 158 /// (if one is found). Otherwise the client will hang due to a violation 159 /// of the client/server protocol. 160 bool end_partial_result_set; 161 bool pause_state; 162 bool quit_func; 163 uint instr_ptr; 164 165 /// The stored program for which this runtime context is created. Used for 166 /// checking if correct runtime context is used for variable handling, 167 /// and to access the package run-time context. 168 /// Also used by slow log. 169 const sp_head *m_sp; 170 171 ///////////////////////////////////////////////////////////////////////// 172 // SP-variables. 173 ///////////////////////////////////////////////////////////////////////// 174 argument_count()175 uint argument_count() const 176 { 177 return m_root_parsing_ctx->context_var_count(); 178 } 179 180 int set_variable(THD *thd, uint var_idx, Item **value); 181 int set_variable_row_field(THD *thd, uint var_idx, uint field_idx, 182 Item **value); 183 int set_variable_row_field_by_name(THD *thd, uint var_idx, 184 const LEX_CSTRING &field_name, 185 Item **value); 186 int set_variable_row(THD *thd, uint var_idx, List<Item> &items); 187 set_parameter(THD * thd,uint var_idx,Item ** value)188 int set_parameter(THD *thd, uint var_idx, Item **value) 189 { 190 DBUG_ASSERT(var_idx < argument_count()); 191 return set_variable(thd, var_idx, value); 192 } 193 get_variable(uint var_idx)194 Item_field *get_variable(uint var_idx) const 195 { return m_var_items[var_idx]; } 196 get_variable_addr(uint var_idx)197 Item **get_variable_addr(uint var_idx) const 198 { return ((Item **) m_var_items.array()) + var_idx; } 199 get_parameter(uint var_idx)200 Item_field *get_parameter(uint var_idx) const 201 { 202 DBUG_ASSERT(var_idx < argument_count()); 203 return get_variable(var_idx); 204 } 205 206 bool find_row_field_by_name_or_error(uint *field_idx, uint var_idx, 207 const LEX_CSTRING &field_name); 208 209 bool set_return_value(THD *thd, Item **return_value_item); 210 is_return_value_set()211 bool is_return_value_set() const 212 { return m_return_value_set; } 213 214 ///////////////////////////////////////////////////////////////////////// 215 // SQL-handlers. 216 ///////////////////////////////////////////////////////////////////////// 217 218 /// Push an sp_instr_hpush_jump instance to the handler call stack. 219 /// 220 /// @param entry The condition handler entry 221 /// 222 /// @return error flag. 223 /// @retval false on success. 224 /// @retval true on error. 225 bool push_handler(sp_instr_hpush_jump *entry); 226 227 /// Pop and delete given number of instances from the handler 228 /// call stack. 229 /// 230 /// @param count Number of handler entries to pop & delete. 231 void pop_handlers(size_t count); 232 raised_condition()233 const Sql_condition_info *raised_condition() const 234 { 235 return m_handler_call_stack.elements() ? 236 (*m_handler_call_stack.back())->sql_condition : NULL; 237 } 238 239 /// Handle current SQL condition (if any). 240 /// 241 /// This is the public-interface function to handle SQL conditions in 242 /// stored routines. 243 /// 244 /// @param thd Thread handle. 245 /// @param ip[out] Instruction pointer to the first handler 246 /// instruction. 247 /// @param cur_spi Current SP instruction. 248 /// 249 /// @retval true if an SQL-handler has been activated. That means, all of 250 /// the following conditions are satisfied: 251 /// - the SP-instruction raised SQL-condition(s), 252 /// - and there is an SQL-handler to process at least one of those 253 /// SQL-conditions, 254 /// - and that SQL-handler has been activated. 255 /// Note, that the return value has nothing to do with "error flag" 256 /// semantics. 257 /// 258 /// @retval false otherwise. 259 bool handle_sql_condition(THD *thd, 260 uint *ip, 261 const sp_instr *cur_spi); 262 263 /// Remove latest call frame from the handler call stack. 264 /// 265 /// @param da Diagnostics area containing handled conditions. 266 /// 267 /// @return continue instruction pointer of the removed handler. 268 uint exit_handler(Diagnostics_area *da); 269 270 ///////////////////////////////////////////////////////////////////////// 271 // Cursors. 272 ///////////////////////////////////////////////////////////////////////// 273 274 /// Push a cursor to the cursor stack. 275 /// 276 /// @param cursor The cursor 277 /// 278 void push_cursor(sp_cursor *cur); 279 280 void pop_cursor(THD *thd); 281 /// Pop and delete given number of sp_cursor instance from the cursor stack. 282 /// 283 /// @param count Number of cursors to pop & delete. 284 void pop_cursors(THD *thd, size_t count); 285 pop_all_cursors(THD * thd)286 void pop_all_cursors(THD *thd) 287 { pop_cursors(thd, m_ccount); } 288 get_cursor(uint i)289 sp_cursor *get_cursor(uint i) const 290 { return m_cstack[i]; } 291 292 ///////////////////////////////////////////////////////////////////////// 293 // CASE expressions. 294 ///////////////////////////////////////////////////////////////////////// 295 296 /// Set CASE expression to the specified value. 297 /// 298 /// @param thd Thread handler. 299 /// @param case_expr_id The CASE expression identifier. 300 /// @param case_expr_item The CASE expression value 301 /// 302 /// @return error flag. 303 /// @retval false on success. 304 /// @retval true on error. 305 /// 306 /// @note The idea is to reuse Item_cache for the expression of the one 307 /// CASE statement. This optimization takes place when there is CASE 308 /// statement inside of a loop. So, in other words, we will use the same 309 /// object on each iteration instead of creating a new one for each 310 /// iteration. 311 /// 312 /// TODO 313 /// Hypothetically, a type of CASE expression can be different for each 314 /// iteration. For instance, this can happen if the expression contains 315 /// a session variable (something like @@VAR) and its type is changed 316 /// from one iteration to another. 317 /// 318 /// In order to cope with this problem, we check type each time, when we 319 /// use already created object. If the type does not match, we re-create 320 /// Item. This also can (should?) be optimized. 321 bool set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr); 322 get_case_expr(int case_expr_id)323 Item *get_case_expr(int case_expr_id) const 324 { return m_case_expr_holders[case_expr_id]; } 325 get_case_expr_addr(int case_expr_id)326 Item ** get_case_expr_addr(int case_expr_id) const 327 { return (Item**) m_case_expr_holders.array() + case_expr_id; } 328 329 private: 330 /// Internal function to allocate memory for arrays. 331 /// 332 /// @param thd Thread handle. 333 /// 334 /// @return error flag: false on success, true in case of failure. 335 bool alloc_arrays(THD *thd); 336 337 /// Create and initialize a table to store SP-variables. 338 /// 339 /// param thd Thread handle. 340 /// 341 /// @return error flag. 342 /// @retval false on success. 343 /// @retval true on error. 344 bool init_var_table(THD *thd, List<Spvar_definition> &defs); 345 346 /// Create and initialize an Item-adapter (Item_field) for each SP-var field. 347 /// 348 /// param thd Thread handle. 349 /// 350 /// @return error flag. 351 /// @retval false on success. 352 /// @retval true on error. 353 bool init_var_items(THD *thd, List<Spvar_definition> &defs); 354 355 /// Create an instance of appropriate Item_cache class depending on the 356 /// specified type in the callers arena. 357 /// 358 /// @note We should create cache items in the callers arena, as they are 359 /// used between in several instructions. 360 /// 361 /// @param thd Thread handler. 362 /// @param item Item to get the expression type. 363 /// 364 /// @return Pointer to valid object on success, or NULL in case of error. 365 Item_cache *create_case_expr_holder(THD *thd, const Item *item) const; 366 367 Virtual_tmp_table *virtual_tmp_table_for_row(uint idx); 368 369 private: 370 /// Top-level (root) parsing context for this runtime context. 371 const sp_pcontext *m_root_parsing_ctx; 372 373 /// Virtual table for storing SP-variables. 374 Virtual_tmp_table *m_var_table; 375 376 /// Collection of Item_field proxies, each of them points to the 377 /// corresponding field in m_var_table. 378 Bounds_checked_array<Item_field *> m_var_items; 379 380 /// This is a pointer to a field, which should contain return value for 381 /// stored functions (only). For stored procedures, this pointer is NULL. 382 Field *m_return_value_fld; 383 384 /// Indicates whether the return value (in m_return_value_fld) has been 385 /// set during execution. 386 bool m_return_value_set; 387 388 /// Flag to tell if the runtime context is created for a sub-statement. 389 bool m_in_sub_stmt; 390 391 /// Stack of visible handlers. 392 Dynamic_array<sp_instr_hpush_jump *> m_handlers; 393 394 /// Stack of caught SQL conditions. 395 Dynamic_array<Handler_call_frame *> m_handler_call_stack; 396 397 /// Stack of cursors. 398 Bounds_checked_array<sp_cursor *> m_cstack; 399 400 /// Current number of cursors in m_cstack. 401 uint m_ccount; 402 403 /// Array of CASE expression holders. 404 Bounds_checked_array<Item_cache *> m_case_expr_holders; 405 }; // class sp_rcontext : public Sql_alloc 406 407 #endif /* _SP_RCONTEXT_H_ */ 408