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