1 /*****************************************************************************
2
3 Copyright (c) 1998, 2011, Oracle and/or its affiliates. All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25 *****************************************************************************/
26
27 /**************************************************//**
28 @file eval/eval0proc.cc
29 Executes SQL stored procedures and their control structures
30
31 Created 1/20/1998 Heikki Tuuri
32 *******************************************************/
33
34 #include "eval0proc.h"
35
36 #ifdef UNIV_NONINL
37 #include "eval0proc.ic"
38 #endif
39
40 /**********************************************************************//**
41 Performs an execution step of an if-statement node.
42 @return query thread to run next or NULL */
43 UNIV_INTERN
44 que_thr_t*
if_step(que_thr_t * thr)45 if_step(
46 /*====*/
47 que_thr_t* thr) /*!< in: query thread */
48 {
49 if_node_t* node;
50 elsif_node_t* elsif_node;
51
52 ut_ad(thr);
53
54 node = static_cast<if_node_t*>(thr->run_node);
55 ut_ad(que_node_get_type(node) == QUE_NODE_IF);
56
57 if (thr->prev_node == que_node_get_parent(node)) {
58
59 /* Evaluate the condition */
60
61 eval_exp(node->cond);
62
63 if (eval_node_get_ibool_val(node->cond)) {
64
65 /* The condition evaluated to TRUE: start execution
66 from the first statement in the statement list */
67
68 thr->run_node = node->stat_list;
69
70 } else if (node->else_part) {
71 thr->run_node = node->else_part;
72
73 } else if (node->elsif_list) {
74 elsif_node = node->elsif_list;
75
76 for (;;) {
77 eval_exp(elsif_node->cond);
78
79 if (eval_node_get_ibool_val(
80 elsif_node->cond)) {
81
82 /* The condition evaluated to TRUE:
83 start execution from the first
84 statement in the statement list */
85
86 thr->run_node = elsif_node->stat_list;
87
88 break;
89 }
90
91 elsif_node = static_cast<elsif_node_t*>(
92 que_node_get_next(elsif_node));
93
94 if (elsif_node == NULL) {
95 thr->run_node = NULL;
96
97 break;
98 }
99 }
100 } else {
101 thr->run_node = NULL;
102 }
103 } else {
104 /* Move to the next statement */
105 ut_ad(que_node_get_next(thr->prev_node) == NULL);
106
107 thr->run_node = NULL;
108 }
109
110 if (thr->run_node == NULL) {
111 thr->run_node = que_node_get_parent(node);
112 }
113
114 return(thr);
115 }
116
117 /**********************************************************************//**
118 Performs an execution step of a while-statement node.
119 @return query thread to run next or NULL */
120 UNIV_INTERN
121 que_thr_t*
while_step(que_thr_t * thr)122 while_step(
123 /*=======*/
124 que_thr_t* thr) /*!< in: query thread */
125 {
126 while_node_t* node;
127
128 ut_ad(thr);
129
130 node = static_cast<while_node_t*>(thr->run_node);
131 ut_ad(que_node_get_type(node) == QUE_NODE_WHILE);
132
133 ut_ad((thr->prev_node == que_node_get_parent(node))
134 || (que_node_get_next(thr->prev_node) == NULL));
135
136 /* Evaluate the condition */
137
138 eval_exp(node->cond);
139
140 if (eval_node_get_ibool_val(node->cond)) {
141
142 /* The condition evaluated to TRUE: start execution
143 from the first statement in the statement list */
144
145 thr->run_node = node->stat_list;
146 } else {
147 thr->run_node = que_node_get_parent(node);
148 }
149
150 return(thr);
151 }
152
153 /**********************************************************************//**
154 Performs an execution step of an assignment statement node.
155 @return query thread to run next or NULL */
156 UNIV_INTERN
157 que_thr_t*
assign_step(que_thr_t * thr)158 assign_step(
159 /*========*/
160 que_thr_t* thr) /*!< in: query thread */
161 {
162 assign_node_t* node;
163
164 ut_ad(thr);
165
166 node = static_cast<assign_node_t*>(thr->run_node);
167 ut_ad(que_node_get_type(node) == QUE_NODE_ASSIGNMENT);
168
169 /* Evaluate the value to assign */
170
171 eval_exp(node->val);
172
173 eval_node_copy_val(node->var->alias, node->val);
174
175 thr->run_node = que_node_get_parent(node);
176
177 return(thr);
178 }
179
180 /**********************************************************************//**
181 Performs an execution step of a for-loop node.
182 @return query thread to run next or NULL */
183 UNIV_INTERN
184 que_thr_t*
for_step(que_thr_t * thr)185 for_step(
186 /*=====*/
187 que_thr_t* thr) /*!< in: query thread */
188 {
189 for_node_t* node;
190 que_node_t* parent;
191 lint loop_var_value;
192
193 ut_ad(thr);
194
195 node = static_cast<for_node_t*>(thr->run_node);
196
197 ut_ad(que_node_get_type(node) == QUE_NODE_FOR);
198
199 parent = que_node_get_parent(node);
200
201 if (thr->prev_node != parent) {
202
203 /* Move to the next statement */
204 thr->run_node = que_node_get_next(thr->prev_node);
205
206 if (thr->run_node != NULL) {
207
208 return(thr);
209 }
210
211 /* Increment the value of loop_var */
212
213 loop_var_value = 1 + eval_node_get_int_val(node->loop_var);
214 } else {
215 /* Initialize the loop */
216
217 eval_exp(node->loop_start_limit);
218 eval_exp(node->loop_end_limit);
219
220 loop_var_value = eval_node_get_int_val(node->loop_start_limit);
221
222 node->loop_end_value
223 = (int) eval_node_get_int_val(node->loop_end_limit);
224 }
225
226 /* Check if we should do another loop */
227
228 if (loop_var_value > node->loop_end_value) {
229
230 /* Enough loops done */
231
232 thr->run_node = parent;
233 } else {
234 eval_node_set_int_val(node->loop_var, loop_var_value);
235
236 thr->run_node = node->stat_list;
237 }
238
239 return(thr);
240 }
241
242 /**********************************************************************//**
243 Performs an execution step of an exit statement node.
244 @return query thread to run next or NULL */
245 UNIV_INTERN
246 que_thr_t*
exit_step(que_thr_t * thr)247 exit_step(
248 /*======*/
249 que_thr_t* thr) /*!< in: query thread */
250 {
251 exit_node_t* node;
252 que_node_t* loop_node;
253
254 ut_ad(thr);
255
256 node = static_cast<exit_node_t*>(thr->run_node);
257
258 ut_ad(que_node_get_type(node) == QUE_NODE_EXIT);
259
260 /* Loops exit by setting thr->run_node as the loop node's parent, so
261 find our containing loop node and get its parent. */
262
263 loop_node = que_node_get_containing_loop_node(node);
264
265 /* If someone uses an EXIT statement outside of a loop, this will
266 trigger. */
267 ut_a(loop_node);
268
269 thr->run_node = que_node_get_parent(loop_node);
270
271 return(thr);
272 }
273
274 /**********************************************************************//**
275 Performs an execution step of a return-statement node.
276 @return query thread to run next or NULL */
277 UNIV_INTERN
278 que_thr_t*
return_step(que_thr_t * thr)279 return_step(
280 /*========*/
281 que_thr_t* thr) /*!< in: query thread */
282 {
283 return_node_t* node;
284 que_node_t* parent;
285
286 ut_ad(thr);
287
288 node = static_cast<return_node_t*>(thr->run_node);
289
290 ut_ad(que_node_get_type(node) == QUE_NODE_RETURN);
291
292 parent = node;
293
294 while (que_node_get_type(parent) != QUE_NODE_PROC) {
295
296 parent = que_node_get_parent(parent);
297 }
298
299 ut_a(parent);
300
301 thr->run_node = que_node_get_parent(parent);
302
303 return(thr);
304 }
305