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