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-1301 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
31class sp_cursor;
32class sp_lex_keeper;
33class sp_instr_cpush;
34class Query_arena;
35class sp_head;
36class Item_cache;
37class Virtual_tmp_table;
38
39
40/*
41 This class is a runtime context of a Stored Routine. It is used in an
42 execution and is intended to contain all dynamic objects (i.e. objects, which
43 can be changed during execution), such as:
44 - stored routine variables;
45 - cursors;
46 - handlers;
47
48 Runtime context is used with sp_head class. sp_head class is intended to
49 contain all static things, related to the stored routines (code, for example).
50 sp_head instance creates runtime context for the execution of a stored
51 routine.
52
53 There is a parsing context (an instance of sp_pcontext class), which is used
54 on parsing stage. However, now it contains some necessary for an execution
55 things, such as definition of used stored routine variables. That's why
56 runtime context needs a reference to the parsing context.
57*/
58
59class sp_rcontext : public Sql_alloc
60{
61public:
62 /// Construct and properly initialize a new sp_rcontext instance. The static
63 /// create-function is needed because we need a way to return an error from
64 /// the constructor.
65 ///
66 /// @param thd Thread handle.
67 /// @param root_parsing_ctx Top-level parsing context for this stored program.
68 /// @param return_value_fld Field object to store the return value
69 /// (for stored functions only).
70 ///
71 /// @return valid sp_rcontext object or NULL in case of OOM-error.
72 static sp_rcontext *create(THD *thd,
73 const sp_head *owner,
74 const sp_pcontext *root_parsing_ctx,
75 Field *return_value_fld,
76 Row_definition_list &defs);
77
78 ~sp_rcontext();
79
80private:
81 sp_rcontext(const sp_head *owner,
82 const sp_pcontext *root_parsing_ctx,
83 Field *return_value_fld,
84 bool in_sub_stmt);
85
86 // Prevent use of copying constructor and operator.
87 sp_rcontext(const sp_rcontext &);
88 void operator=(sp_rcontext &);
89
90private:
91 /// This is an auxillary class to store entering instruction pointer for an
92 /// SQL-handler.
93 class sp_handler_entry : public Sql_alloc
94 {
95 public:
96 /// Handler definition (from parsing context).
97 const sp_handler *handler;
98
99 /// Instruction pointer to the first instruction.
100 uint first_ip;
101
102 /// The constructor.
103 ///
104 /// @param _handler sp_handler object.
105 /// @param _first_ip first instruction pointer.
106 sp_handler_entry(const sp_handler *_handler, uint _first_ip)
107 :handler(_handler), first_ip(_first_ip)
108 { }
109 };
110
111public:
112 /// This class stores basic information about SQL-condition, such as:
113 /// - SQL error code;
114 /// - error level;
115 /// - SQLSTATE;
116 /// - text message.
117 ///
118 /// It's used to organize runtime SQL-handler call stack.
119 ///
120 /// Standard Sql_condition class can not be used, because we don't always have
121 /// an Sql_condition object for an SQL-condition in Diagnostics_area.
122 ///
123 /// Eventually, this class should be moved to sql_error.h, and be a part of
124 /// standard SQL-condition processing (Diagnostics_area should contain an
125 /// object for active SQL-condition, not just information stored in DA's
126 /// fields).
127 class Sql_condition_info : public Sql_alloc,
128 public Sql_condition_identity
129 {
130 public:
131 /// Text message.
132 char *message;
133
134 /// The constructor.
135 ///
136 /// @param _sql_condition The SQL condition.
137 /// @param arena Query arena for SP
138 Sql_condition_info(const Sql_condition *_sql_condition,
139 Query_arena *arena)
140 :Sql_condition_identity(*_sql_condition)
141 {
142 message= strdup_root(arena->mem_root, _sql_condition->get_message_text());
143 }
144 };
145
146private:
147 /// This class represents a call frame of SQL-handler (one invocation of a
148 /// handler). Basically, it's needed to store continue instruction pointer for
149 /// CONTINUE SQL-handlers.
150 class Handler_call_frame : public Sql_alloc
151 {
152 public:
153 /// SQL-condition, triggered handler activation.
154 const Sql_condition_info *sql_condition;
155
156 /// Continue-instruction-pointer for CONTINUE-handlers.
157 /// The attribute contains 0 for EXIT-handlers.
158 uint continue_ip;
159
160 /// The constructor.
161 ///
162 /// @param _sql_condition SQL-condition, triggered handler activation.
163 /// @param _continue_ip Continue instruction pointer.
164 Handler_call_frame(const Sql_condition_info *_sql_condition,
165 uint _continue_ip)
166 :sql_condition(_sql_condition),
167 continue_ip(_continue_ip)
168 { }
169 };
170
171public:
172 /// Arena used to (re) allocate items on. E.g. reallocate INOUT/OUT
173 /// SP-variables when they don't fit into prealloced items. This is common
174 /// situation with String items. It is used mainly in sp_eval_func_item().
175 Query_arena *callers_arena;
176
177 /// Flag to end an open result set before start executing an SQL-handler
178 /// (if one is found). Otherwise the client will hang due to a violation
179 /// of the client/server protocol.
180 bool end_partial_result_set;
181 bool pause_state;
182 bool quit_func;
183 uint instr_ptr;
184
185 /// The stored program for which this runtime context is created. Used for
186 /// checking if correct runtime context is used for variable handling,
187 /// and to access the package run-time context.
188 /// Also used by slow log.
189 const sp_head *m_sp;
190
191 /////////////////////////////////////////////////////////////////////////
192 // SP-variables.
193 /////////////////////////////////////////////////////////////////////////
194
195 uint argument_count() const
196 {
197 return m_root_parsing_ctx->context_var_count();
198 }
199
200 int set_variable(THD *thd, uint var_idx, Item **value);
201 int set_variable_row_field(THD *thd, uint var_idx, uint field_idx,
202 Item **value);
203 int set_variable_row_field_by_name(THD *thd, uint var_idx,
204 const LEX_CSTRING &field_name,
205 Item **value);
206 int set_variable_row(THD *thd, uint var_idx, List<Item> &items);
207
208 int set_parameter(THD *thd, uint var_idx, Item **value)
209 {
210 DBUG_ASSERT(var_idx < argument_count());
211 return set_variable(thd, var_idx, value);
212 }
213
214 Item_field *get_variable(uint var_idx) const
215 { return m_var_items[var_idx]; }
216
217 Item **get_variable_addr(uint var_idx) const
218 { return ((Item **) m_var_items.array()) + var_idx; }
219
220 Item_field *get_parameter(uint var_idx) const
221 {
222 DBUG_ASSERT(var_idx < argument_count());
223 return get_variable(var_idx);
224 }
225
226 bool find_row_field_by_name_or_error(uint *field_idx, uint var_idx,
227 const LEX_CSTRING &field_name);
228
229 bool set_return_value(THD *thd, Item **return_value_item);
230
231 bool is_return_value_set() const
232 { return m_return_value_set; }
233
234 /////////////////////////////////////////////////////////////////////////
235 // SQL-handlers.
236 /////////////////////////////////////////////////////////////////////////
237
238 /// Create a new sp_handler_entry instance and push it to the handler call
239 /// stack.
240 ///
241 /// @param handler SQL-handler object.
242 /// @param first_ip First instruction pointer of the handler.
243 ///
244 /// @return error flag.
245 /// @retval false on success.
246 /// @retval true on error.
247 bool push_handler(sp_handler *handler, uint first_ip);
248
249 /// Pop and delete given number of sp_handler_entry instances from the handler
250 /// call stack.
251 ///
252 /// @param count Number of handler entries to pop & delete.
253 void pop_handlers(size_t count);
254
255 const Sql_condition_info *raised_condition() const
256 {
257 return m_handler_call_stack.elements() ?
258 (*m_handler_call_stack.back())->sql_condition : NULL;
259 }
260
261 /// Handle current SQL condition (if any).
262 ///
263 /// This is the public-interface function to handle SQL conditions in
264 /// stored routines.
265 ///
266 /// @param thd Thread handle.
267 /// @param ip[out] Instruction pointer to the first handler
268 /// instruction.
269 /// @param cur_spi Current SP instruction.
270 ///
271 /// @retval true if an SQL-handler has been activated. That means, all of
272 /// the following conditions are satisfied:
273 /// - the SP-instruction raised SQL-condition(s),
274 /// - and there is an SQL-handler to process at least one of those
275 /// SQL-conditions,
276 /// - and that SQL-handler has been activated.
277 /// Note, that the return value has nothing to do with "error flag"
278 /// semantics.
279 ///
280 /// @retval false otherwise.
281 bool handle_sql_condition(THD *thd,
282 uint *ip,
283 const sp_instr *cur_spi);
284
285 /// Remove latest call frame from the handler call stack.
286 ///
287 /// @param da Diagnostics area containing handled conditions.
288 ///
289 /// @return continue instruction pointer of the removed handler.
290 uint exit_handler(Diagnostics_area *da);
291
292 /////////////////////////////////////////////////////////////////////////
293 // Cursors.
294 /////////////////////////////////////////////////////////////////////////
295
296 /// Create a new sp_cursor instance and push it to the cursor stack.
297 ///
298 /// @param lex_keeper SP-instruction execution helper.
299 /// @param i Cursor-push instruction.
300 ///
301 /// @return error flag.
302 /// @retval false on success.
303 /// @retval true on error.
304 bool push_cursor(THD *thd, sp_lex_keeper *lex_keeper);
305
306 /// Pop and delete given number of sp_cursor instance from the cursor stack.
307 ///
308 /// @param count Number of cursors to pop & delete.
309 void pop_cursors(size_t count);
310
311 void pop_all_cursors()
312 { pop_cursors(m_ccount); }
313
314 sp_cursor *get_cursor(uint i) const
315 { return m_cstack[i]; }
316
317 /////////////////////////////////////////////////////////////////////////
318 // CASE expressions.
319 /////////////////////////////////////////////////////////////////////////
320
321 /// Set CASE expression to the specified value.
322 ///
323 /// @param thd Thread handler.
324 /// @param case_expr_id The CASE expression identifier.
325 /// @param case_expr_item The CASE expression value
326 ///
327 /// @return error flag.
328 /// @retval false on success.
329 /// @retval true on error.
330 ///
331 /// @note The idea is to reuse Item_cache for the expression of the one
332 /// CASE statement. This optimization takes place when there is CASE
333 /// statement inside of a loop. So, in other words, we will use the same
334 /// object on each iteration instead of creating a new one for each
335 /// iteration.
336 ///
337 /// TODO
338 /// Hypothetically, a type of CASE expression can be different for each
339 /// iteration. For instance, this can happen if the expression contains
340 /// a session variable (something like @@VAR) and its type is changed
341 /// from one iteration to another.
342 ///
343 /// In order to cope with this problem, we check type each time, when we
344 /// use already created object. If the type does not match, we re-create
345 /// Item. This also can (should?) be optimized.
346 bool set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr);
347
348 Item *get_case_expr(int case_expr_id) const
349 { return m_case_expr_holders[case_expr_id]; }
350
351 Item ** get_case_expr_addr(int case_expr_id) const
352 { return (Item**) m_case_expr_holders.array() + case_expr_id; }
353
354private:
355 /// Internal function to allocate memory for arrays.
356 ///
357 /// @param thd Thread handle.
358 ///
359 /// @return error flag: false on success, true in case of failure.
360 bool alloc_arrays(THD *thd);
361
362 /// Create and initialize a table to store SP-variables.
363 ///
364 /// param thd Thread handle.
365 ///
366 /// @return error flag.
367 /// @retval false on success.
368 /// @retval true on error.
369 bool init_var_table(THD *thd, List<Spvar_definition> &defs);
370
371 /// Create and initialize an Item-adapter (Item_field) for each SP-var field.
372 ///
373 /// param thd Thread handle.
374 ///
375 /// @return error flag.
376 /// @retval false on success.
377 /// @retval true on error.
378 bool init_var_items(THD *thd, List<Spvar_definition> &defs);
379
380 /// Create an instance of appropriate Item_cache class depending on the
381 /// specified type in the callers arena.
382 ///
383 /// @note We should create cache items in the callers arena, as they are
384 /// used between in several instructions.
385 ///
386 /// @param thd Thread handler.
387 /// @param item Item to get the expression type.
388 ///
389 /// @return Pointer to valid object on success, or NULL in case of error.
390 Item_cache *create_case_expr_holder(THD *thd, const Item *item) const;
391
392 Virtual_tmp_table *virtual_tmp_table_for_row(uint idx);
393
394private:
395 /// Top-level (root) parsing context for this runtime context.
396 const sp_pcontext *m_root_parsing_ctx;
397
398 /// Virtual table for storing SP-variables.
399 Virtual_tmp_table *m_var_table;
400
401 /// Collection of Item_field proxies, each of them points to the
402 /// corresponding field in m_var_table.
403 Bounds_checked_array<Item_field *> m_var_items;
404
405 /// This is a pointer to a field, which should contain return value for
406 /// stored functions (only). For stored procedures, this pointer is NULL.
407 Field *m_return_value_fld;
408
409 /// Indicates whether the return value (in m_return_value_fld) has been
410 /// set during execution.
411 bool m_return_value_set;
412
413 /// Flag to tell if the runtime context is created for a sub-statement.
414 bool m_in_sub_stmt;
415
416 /// Stack of visible handlers.
417 Dynamic_array<sp_handler_entry *> m_handlers;
418
419 /// Stack of caught SQL conditions.
420 Dynamic_array<Handler_call_frame *> m_handler_call_stack;
421
422 /// Stack of cursors.
423 Bounds_checked_array<sp_cursor *> m_cstack;
424
425 /// Current number of cursors in m_cstack.
426 uint m_ccount;
427
428 /// Array of CASE expression holders.
429 Bounds_checked_array<Item_cache *> m_case_expr_holders;
430}; // class sp_rcontext : public Sql_alloc
431
432///////////////////////////////////////////////////////////////////////////
433// sp_cursor declaration.
434///////////////////////////////////////////////////////////////////////////
435
436class Server_side_cursor;
437typedef class st_select_lex_unit SELECT_LEX_UNIT;
438
439/* A mediator between stored procedures and server side cursors */
440
441class sp_cursor : public Sql_alloc
442{
443private:
444 /// An interceptor of cursor result set used to implement
445 /// FETCH <cname> INTO <varlist>.
446 class Select_fetch_into_spvars: public select_result_interceptor
447 {
448 List<sp_variable> *spvar_list;
449 uint field_count;
450 bool send_data_to_variable_list(List<sp_variable> &vars, List<Item> &items);
451 public:
452 Select_fetch_into_spvars(THD *thd_arg): select_result_interceptor(thd_arg) {}
453 uint get_field_count() { return field_count; }
454 void set_spvar_list(List<sp_variable> *vars) { spvar_list= vars; }
455
456 virtual bool send_eof() { return FALSE; }
457 virtual int send_data(List<Item> &items);
458 virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
459};
460
461public:
462 sp_cursor(THD *thd_arg, sp_lex_keeper *lex_keeper);
463
464 virtual ~sp_cursor()
465 { destroy(); }
466
467 sp_lex_keeper *get_lex_keeper() { return m_lex_keeper; }
468
469 int open(THD *thd);
470
471 int open_view_structure_only(THD *thd);
472
473 int close(THD *thd);
474
475 my_bool is_open()
476 { return MY_TEST(server_side_cursor); }
477
478 bool found() const
479 { return m_found; }
480
481 ulonglong row_count() const
482 { return m_row_count; }
483
484 ulonglong fetch_count() const
485 { return m_fetch_count; }
486
487 int fetch(THD *, List<sp_variable> *vars, bool error_on_no_data);
488
489 bool export_structure(THD *thd, Row_definition_list *list);
490
491private:
492 Select_fetch_into_spvars result;
493 sp_lex_keeper *m_lex_keeper;
494 Server_side_cursor *server_side_cursor;
495 ulonglong m_fetch_count; // Number of FETCH commands since last OPEN
496 ulonglong m_row_count; // Number of successful FETCH since last OPEN
497 bool m_found; // If last FETCH fetched a row
498 void destroy();
499
500}; // class sp_cursor : public Sql_alloc
501
502#endif /* _SP_RCONTEXT_H_ */
503