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