summaryrefslogtreecommitdiff
path: root/innobase/eval
diff options
context:
space:
mode:
authorunknown <monty@donna.mysql.com>2001-02-17 14:19:19 +0200
committerunknown <monty@donna.mysql.com>2001-02-17 14:19:19 +0200
commit2662b59306ef0cd495fa6e2edf7129e58a11393a (patch)
treebfe39951a73e906579ab819bf5198ad8f3a64a36 /innobase/eval
parent66de55a56bdcf2f7a9c0c4f8e19b3e761475e202 (diff)
downloadmariadb-git-2662b59306ef0cd495fa6e2edf7129e58a11393a.tar.gz
Added Innobase to source distribution
Docs/manual.texi: Added Innobase documentation configure.in: Incremented version include/my_base.h: Added option for Innobase myisam/mi_check.c: cleanup mysql-test/t/bdb.test: cleanup mysql-test/t/innobase.test: Extended with new tests from bdb.test mysql-test/t/merge.test: Added test of SHOW create mysys/my_init.c: Fix for UNIXWARE 7 scripts/mysql_install_db.sh: Always write how to start mysqld scripts/safe_mysqld.sh: Fixed type sql/ha_innobase.cc: Update to new version sql/ha_innobase.h: Update to new version sql/handler.h: Added 'update_table_comment()' and 'append_create_info()' sql/sql_delete.cc: Fixes for Innobase sql/sql_select.cc: Fixes for Innobase sql/sql_show.cc: Append create information (for MERGE tables) sql/sql_update.cc: Fixes for Innobase
Diffstat (limited to 'innobase/eval')
-rw-r--r--innobase/eval/Makefile.am25
-rw-r--r--innobase/eval/eval0eval.c777
-rw-r--r--innobase/eval/eval0proc.c245
-rw-r--r--innobase/eval/makefilewin10
4 files changed, 1057 insertions, 0 deletions
diff --git a/innobase/eval/Makefile.am b/innobase/eval/Makefile.am
new file mode 100644
index 00000000000..748980b6192
--- /dev/null
+++ b/innobase/eval/Makefile.am
@@ -0,0 +1,25 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+# & Innobase Oy
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+include ../include/Makefile.i
+
+libs_LIBRARIES = libeval.a
+
+libeval_a_SOURCES = eval0eval.c eval0proc.c
+
+EXTRA_PROGRAMS =
+
diff --git a/innobase/eval/eval0eval.c b/innobase/eval/eval0eval.c
new file mode 100644
index 00000000000..110387d8373
--- /dev/null
+++ b/innobase/eval/eval0eval.c
@@ -0,0 +1,777 @@
+/******************************************************
+SQL evaluator: evaluates simple data structures, like expressions, in
+a query graph
+
+(c) 1997 Innobase Oy
+
+Created 12/29/1997 Heikki Tuuri
+*******************************************************/
+
+#include "eval0eval.h"
+
+#ifdef UNIV_NONINL
+#include "eval0eval.ic"
+#endif
+
+#include "data0data.h"
+#include "row0sel.h"
+
+/* The RND function seed */
+ulint eval_rnd = 128367121;
+
+/* Dummy adress used when we should allocate a buffer of size 0 in
+the function below */
+
+byte eval_dummy;
+
+/*********************************************************************
+Allocate a buffer from global dynamic memory for a value of a que_node.
+NOTE that this memory must be explicitly freed when the query graph is
+freed. If the node already has an allocated buffer, that buffer is freed
+here. NOTE that this is the only function where dynamic memory should be
+allocated for a query node val field. */
+
+byte*
+eval_node_alloc_val_buf(
+/*====================*/
+ /* out: pointer to allocated buffer */
+ que_node_t* node, /* in: query graph node; sets the val field
+ data field to point to the new buffer, and
+ len field equal to size */
+ ulint size) /* in: buffer size */
+{
+ dfield_t* dfield;
+ byte* data;
+
+ ut_ad(que_node_get_type(node) == QUE_NODE_SYMBOL
+ || que_node_get_type(node) == QUE_NODE_FUNC);
+
+ dfield = que_node_get_val(node);
+
+ data = dfield_get_data(dfield);
+
+ if (data && data != &eval_dummy) {
+ mem_free(data);
+ }
+
+ if (size == 0) {
+ data = &eval_dummy;
+ } else {
+ data = mem_alloc(size);
+ }
+
+ que_node_set_val_buf_size(node, size);
+
+ dfield_set_data(dfield, data, size);
+
+ return(data);
+}
+
+/*********************************************************************
+Free the buffer from global dynamic memory for a value of a que_node,
+if it has been allocated in the above function. The freeing for pushed
+column values is done in sel_col_prefetch_buf_free. */
+
+void
+eval_node_free_val_buf(
+/*===================*/
+ que_node_t* node) /* in: query graph node */
+{
+ dfield_t* dfield;
+ byte* data;
+
+ ut_ad(que_node_get_type(node) == QUE_NODE_SYMBOL
+ || que_node_get_type(node) == QUE_NODE_FUNC);
+
+ dfield = que_node_get_val(node);
+
+ data = dfield_get_data(dfield);
+
+ if (que_node_get_val_buf_size(node) > 0) {
+ ut_a(data);
+
+ mem_free(data);
+ }
+}
+
+/*********************************************************************
+Evaluates a comparison node. */
+
+ibool
+eval_cmp(
+/*=====*/
+ /* out: the result of the comparison */
+ func_node_t* cmp_node) /* in: comparison node */
+{
+ que_node_t* arg1;
+ que_node_t* arg2;
+ int res;
+ ibool val;
+ int func;
+
+ ut_ad(que_node_get_type(cmp_node) == QUE_NODE_FUNC);
+
+ arg1 = cmp_node->args;
+ arg2 = que_node_get_next(arg1);
+
+ res = cmp_dfield_dfield(que_node_get_val(arg1),
+ que_node_get_val(arg2));
+ val = TRUE;
+
+ func = cmp_node->func;
+
+ if (func == '=') {
+ if (res != 0) {
+ val = FALSE;
+ }
+ } else if (func == '<') {
+ if (res != -1) {
+ val = FALSE;
+ }
+ } else if (func == PARS_LE_TOKEN) {
+ if (res == 1) {
+ val = FALSE;
+ }
+ } else if (func == PARS_NE_TOKEN) {
+ if (res == 0) {
+ val = FALSE;
+ }
+ } else if (func == PARS_GE_TOKEN) {
+ if (res == -1) {
+ val = FALSE;
+ }
+ } else {
+ ut_ad(func == '>');
+
+ if (res != 1) {
+ val = FALSE;
+ }
+ }
+
+ eval_node_set_ibool_val(cmp_node, val);
+
+ return(val);
+}
+
+/*********************************************************************
+Evaluates a logical operation node. */
+UNIV_INLINE
+void
+eval_logical(
+/*=========*/
+ func_node_t* logical_node) /* in: logical operation node */
+{
+ que_node_t* arg1;
+ que_node_t* arg2;
+ ibool val1;
+ ibool val2;
+ ibool val;
+ int func;
+
+ ut_ad(que_node_get_type(logical_node) == QUE_NODE_FUNC);
+
+ arg1 = logical_node->args;
+ arg2 = que_node_get_next(arg1); /* arg2 is NULL if func is 'NOT' */
+
+ val1 = eval_node_get_ibool_val(arg1);
+
+ if (arg2) {
+ val2 = eval_node_get_ibool_val(arg2);
+ }
+
+ func = logical_node->func;
+
+ if (func == PARS_AND_TOKEN) {
+ val = val1 & val2;
+ } else if (func == PARS_OR_TOKEN) {
+ val = val1 | val2;
+ } else if (func == PARS_NOT_TOKEN) {
+ val = TRUE - val1;
+ } else {
+ ut_error;
+ }
+
+ eval_node_set_ibool_val(logical_node, val);
+}
+
+/*********************************************************************
+Evaluates an arithmetic operation node. */
+UNIV_INLINE
+void
+eval_arith(
+/*=======*/
+ func_node_t* arith_node) /* in: arithmetic operation node */
+{
+ que_node_t* arg1;
+ que_node_t* arg2;
+ lint val1;
+ lint val2;
+ lint val;
+ int func;
+
+ ut_ad(que_node_get_type(arith_node) == QUE_NODE_FUNC);
+
+ arg1 = arith_node->args;
+ arg2 = que_node_get_next(arg1); /* arg2 is NULL if func is unary '-' */
+
+ val1 = eval_node_get_int_val(arg1);
+
+ if (arg2) {
+ val2 = eval_node_get_int_val(arg2);
+ }
+
+ func = arith_node->func;
+
+ if (func == '+') {
+ val = val1 + val2;
+ } else if ((func == '-') && arg2) {
+ val = val1 - val2;
+ } else if (func == '-') {
+ val = -val1;
+ } else if (func == '*') {
+ val = val1 * val2;
+ } else {
+ ut_ad(func == '/');
+ val = val1 / val2;
+ }
+
+ eval_node_set_int_val(arith_node, val);
+}
+
+/*********************************************************************
+Evaluates an aggregate operation node. */
+UNIV_INLINE
+void
+eval_aggregate(
+/*===========*/
+ func_node_t* node) /* in: aggregate operation node */
+{
+ que_node_t* arg;
+ lint val;
+ lint arg_val;
+ int func;
+
+ ut_ad(que_node_get_type(node) == QUE_NODE_FUNC);
+
+ val = eval_node_get_int_val(node);
+
+ func = node->func;
+
+ if (func == PARS_COUNT_TOKEN) {
+
+ val = val + 1;
+ } else {
+ ut_ad(func == PARS_SUM_TOKEN);
+
+ arg = node->args;
+ arg_val = eval_node_get_int_val(arg);
+
+ val = val + arg_val;
+ }
+
+ eval_node_set_int_val(node, val);
+}
+
+/*********************************************************************
+Evaluates a predefined function node where the function is not relevant
+in benchmarks. */
+static
+void
+eval_predefined_2(
+/*==============*/
+ func_node_t* func_node) /* in: predefined function node */
+{
+ que_node_t* arg;
+ que_node_t* arg1;
+ que_node_t* arg2;
+ lint int_val;
+ byte* data;
+ ulint len1;
+ ulint len2;
+ int func;
+ ulint i;
+
+ ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
+
+ arg1 = func_node->args;
+
+ if (arg1) {
+ arg2 = que_node_get_next(arg1);
+ }
+
+ func = func_node->func;
+
+ if (func == PARS_PRINTF_TOKEN) {
+
+ arg = arg1;
+
+ while (arg) {
+ dfield_print(que_node_get_val(arg));
+
+ arg = que_node_get_next(arg);
+ }
+
+ printf("\n");
+
+ } else if (func == PARS_ASSERT_TOKEN) {
+
+ if (!eval_node_get_ibool_val(arg1)) {
+ printf("SQL assertion fails in a stored procedure!\n");
+ }
+
+ ut_a(eval_node_get_ibool_val(arg1));
+
+ /* This function, or more precisely, a debug procedure,
+ returns no value */
+
+ } else if (func == PARS_RND_TOKEN) {
+
+ len1 = (ulint)eval_node_get_int_val(arg1);
+ len2 = (ulint)eval_node_get_int_val(arg2);
+
+ ut_ad(len2 >= len1);
+
+ if (len2 > len1) {
+ int_val = (lint)(len1 +
+ (eval_rnd % (len2 - len1 + 1)));
+ } else {
+ int_val = (lint)len1;
+ }
+
+ eval_rnd = ut_rnd_gen_next_ulint(eval_rnd);
+
+ eval_node_set_int_val(func_node, int_val);
+
+ } else if (func == PARS_RND_STR_TOKEN) {
+
+ len1 = (ulint)eval_node_get_int_val(arg1);
+
+ data = eval_node_ensure_val_buf(func_node, len1);
+
+ for (i = 0; i < len1; i++) {
+ data[i] = (byte)(97 + (eval_rnd % 3));
+
+ eval_rnd = ut_rnd_gen_next_ulint(eval_rnd);
+ }
+ } else {
+ ut_error;
+ }
+}
+
+/*********************************************************************
+Evaluates a notfound-function node. */
+UNIV_INLINE
+void
+eval_notfound(
+/*==========*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg1;
+ que_node_t* arg2;
+ sym_node_t* cursor;
+ sel_node_t* sel_node;
+ ibool ibool_val;
+
+ arg1 = func_node->args;
+ arg2 = que_node_get_next(arg1);
+
+ ut_ad(func_node->func == PARS_NOTFOUND_TOKEN);
+
+ cursor = arg1;
+
+ ut_ad(que_node_get_type(cursor) == QUE_NODE_SYMBOL);
+
+ if (cursor->token_type == SYM_LIT) {
+
+ ut_ad(ut_memcmp(dfield_get_data(que_node_get_val(cursor)),
+ "SQL", 3) == 0);
+
+ sel_node = cursor->sym_table->query_graph->last_sel_node;
+ } else {
+ sel_node = cursor->alias->cursor_def;
+ }
+
+ if (sel_node->state == SEL_NODE_NO_MORE_ROWS) {
+ ibool_val = TRUE;
+ } else {
+ ibool_val = FALSE;
+ }
+
+ eval_node_set_ibool_val(func_node, ibool_val);
+}
+
+/*********************************************************************
+Evaluates a substr-function node. */
+UNIV_INLINE
+void
+eval_substr(
+/*========*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg1;
+ que_node_t* arg2;
+ que_node_t* arg3;
+ dfield_t* dfield;
+ byte* str1;
+ ulint len1;
+ ulint len2;
+
+ arg1 = func_node->args;
+ arg2 = que_node_get_next(arg1);
+
+ ut_ad(func_node->func == PARS_SUBSTR_TOKEN);
+
+ arg3 = que_node_get_next(arg2);
+
+ str1 = dfield_get_data(que_node_get_val(arg1));
+
+ len1 = (ulint)eval_node_get_int_val(arg2);
+ len2 = (ulint)eval_node_get_int_val(arg3);
+
+ dfield = que_node_get_val(func_node);
+
+ dfield_set_data(dfield, str1 + len1, len2);
+}
+
+/*********************************************************************
+Evaluates a replstr-procedure node. */
+static
+void
+eval_replstr(
+/*=========*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg1;
+ que_node_t* arg2;
+ que_node_t* arg3;
+ que_node_t* arg4;
+ byte* str1;
+ byte* str2;
+ ulint len1;
+ ulint len2;
+
+ arg1 = func_node->args;
+ arg2 = que_node_get_next(arg1);
+
+ ut_ad(que_node_get_type(arg1) == QUE_NODE_SYMBOL);
+
+ arg3 = que_node_get_next(arg2);
+ arg4 = que_node_get_next(arg3);
+
+ str1 = dfield_get_data(que_node_get_val(arg1));
+ str2 = dfield_get_data(que_node_get_val(arg2));
+
+ len1 = (ulint)eval_node_get_int_val(arg3);
+ len2 = (ulint)eval_node_get_int_val(arg4);
+
+ if ((dfield_get_len(que_node_get_val(arg1)) < len1 + len2)
+ || (dfield_get_len(que_node_get_val(arg2)) < len2)) {
+
+ ut_error;
+ }
+
+ ut_memcpy(str1 + len1, str2, len2);
+}
+
+/*********************************************************************
+Evaluates an instr-function node. */
+static
+void
+eval_instr(
+/*=======*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg1;
+ que_node_t* arg2;
+ dfield_t* dfield1;
+ dfield_t* dfield2;
+ lint int_val;
+ byte* str1;
+ byte* str2;
+ byte match_char;
+ ulint len1;
+ ulint len2;
+ ulint i;
+ ulint j;
+
+ arg1 = func_node->args;
+ arg2 = que_node_get_next(arg1);
+
+ dfield1 = que_node_get_val(arg1);
+ dfield2 = que_node_get_val(arg2);
+
+ str1 = dfield_get_data(dfield1);
+ str2 = dfield_get_data(dfield2);
+
+ len1 = dfield_get_len(dfield1);
+ len2 = dfield_get_len(dfield2);
+
+ if (len2 == 0) {
+ ut_error;
+ }
+
+ match_char = str2[0];
+
+ for (i = 0; i < len1; i++) {
+ /* In this outer loop, the number of matched characters is 0 */
+
+ if (str1[i] == match_char) {
+
+ if (i + len2 > len1) {
+
+ break;
+ }
+
+ for (j = 1;; j++) {
+ /* We have already matched j characters */
+
+ if (j == len2) {
+ int_val = i + 1;
+
+ goto match_found;
+ }
+
+ if (str1[i + j] != str2[j]) {
+
+ break;
+ }
+ }
+ }
+ }
+
+ int_val = 0;
+
+match_found:
+ eval_node_set_int_val(func_node, int_val);
+}
+
+/*********************************************************************
+Evaluates a predefined function node. */
+UNIV_INLINE
+void
+eval_binary_to_number(
+/*==================*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg1;
+ dfield_t* dfield;
+ byte* str1;
+ byte* str2;
+ ulint len1;
+ ulint int_val;
+
+ arg1 = func_node->args;
+
+ dfield = que_node_get_val(arg1);
+
+ str1 = dfield_get_data(dfield);
+ len1 = dfield_get_len(dfield);
+
+ if (len1 > 4) {
+ ut_error;
+ }
+
+ if (len1 == 4) {
+ str2 = str1;
+ } else {
+ int_val = 0;
+ str2 = (byte*)&int_val;
+
+ ut_memcpy(str2 + (4 - len1), str1, len1);
+ }
+
+ eval_node_copy_and_alloc_val(func_node, str2, 4);
+}
+
+/*********************************************************************
+Evaluates a predefined function node. */
+static
+void
+eval_concat(
+/*========*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg;
+ dfield_t* dfield;
+ byte* data;
+ ulint len;
+ ulint len1;
+
+ arg = func_node->args;
+ len = 0;
+
+ while (arg) {
+ len1 = dfield_get_len(que_node_get_val(arg));
+
+ len += len1;
+
+ arg = que_node_get_next(arg);
+ }
+
+ data = eval_node_ensure_val_buf(func_node, len);
+
+ arg = func_node->args;
+ len = 0;
+
+ while (arg) {
+ dfield = que_node_get_val(arg);
+ len1 = dfield_get_len(dfield);
+
+ ut_memcpy(data + len, dfield_get_data(dfield), len1);
+
+ len += len1;
+
+ arg = que_node_get_next(arg);
+ }
+}
+
+/*********************************************************************
+Evaluates a predefined function node. */
+UNIV_INLINE
+void
+eval_to_binary(
+/*===========*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg1;
+ que_node_t* arg2;
+ dfield_t* dfield;
+ byte* str1;
+ ulint len1;
+
+ arg1 = func_node->args;
+
+ str1 = dfield_get_data(que_node_get_val(arg1));
+
+ arg2 = que_node_get_next(arg1);
+
+ len1 = (ulint)eval_node_get_int_val(arg2);
+
+ if (len1 > 4) {
+
+ ut_error;
+ }
+
+ dfield = que_node_get_val(func_node);
+
+ dfield_set_data(dfield, str1 + (4 - len1), len1);
+}
+
+/*********************************************************************
+Evaluates a predefined function node. */
+UNIV_INLINE
+void
+eval_predefined(
+/*============*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg1;
+ lint int_val;
+ byte* str1;
+ byte* data;
+ int func;
+
+ func = func_node->func;
+
+ arg1 = func_node->args;
+
+ if (func == PARS_LENGTH_TOKEN) {
+
+ int_val = (lint)dfield_get_len(que_node_get_val(arg1));
+
+ } else if (func == PARS_TO_CHAR_TOKEN) {
+
+ int_val = eval_node_get_int_val(arg1);
+
+ data = eval_node_ensure_val_buf(func_node, 11);
+
+ sprintf((char*)data, "%10li", int_val);
+
+ dfield_set_len(que_node_get_val(func_node), 10);
+
+ return;
+
+ } else if (func == PARS_TO_NUMBER_TOKEN) {
+
+ str1 = dfield_get_data(que_node_get_val(arg1));
+
+ int_val = atoi((char*)str1);
+
+ } else if (func == PARS_SYSDATE_TOKEN) {
+ int_val = (lint)ut_time();
+ } else {
+ eval_predefined_2(func_node);
+
+ return;
+ }
+
+ eval_node_set_int_val(func_node, int_val);
+}
+
+/*********************************************************************
+Evaluates a function node. */
+
+void
+eval_func(
+/*======*/
+ func_node_t* func_node) /* in: function node */
+{
+ que_node_t* arg;
+ ulint class;
+ ulint func;
+
+ ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
+
+ class = func_node->class;
+ func = func_node->func;
+
+ arg = func_node->args;
+
+ /* Evaluate first the argument list */
+ while (arg) {
+ eval_exp(arg);
+
+ /* The functions are not defined for SQL null argument
+ values, except for eval_cmp and notfound */
+
+ if ((dfield_get_len(que_node_get_val(arg)) == UNIV_SQL_NULL)
+ && (class != PARS_FUNC_CMP)
+ && (func != PARS_NOTFOUND_TOKEN)
+ && (func != PARS_PRINTF_TOKEN)) {
+ ut_error;
+ }
+
+ arg = que_node_get_next(arg);
+ }
+
+ if (class == PARS_FUNC_CMP) {
+ eval_cmp(func_node);
+ } else if (class == PARS_FUNC_ARITH) {
+ eval_arith(func_node);
+ } else if (class == PARS_FUNC_AGGREGATE) {
+ eval_aggregate(func_node);
+ } else if (class == PARS_FUNC_PREDEFINED) {
+
+ if (func == PARS_NOTFOUND_TOKEN) {
+ eval_notfound(func_node);
+ } else if (func == PARS_SUBSTR_TOKEN) {
+ eval_substr(func_node);
+ } else if (func == PARS_REPLSTR_TOKEN) {
+ eval_replstr(func_node);
+ } else if (func == PARS_INSTR_TOKEN) {
+ eval_instr(func_node);
+ } else if (func == PARS_BINARY_TO_NUMBER_TOKEN) {
+ eval_binary_to_number(func_node);
+ } else if (func == PARS_CONCAT_TOKEN) {
+ eval_concat(func_node);
+ } else if (func == PARS_TO_BINARY_TOKEN) {
+ eval_to_binary(func_node);
+ } else {
+ eval_predefined(func_node);
+ }
+ } else {
+ ut_ad(class == PARS_FUNC_LOGICAL);
+
+ eval_logical(func_node);
+ }
+}
diff --git a/innobase/eval/eval0proc.c b/innobase/eval/eval0proc.c
new file mode 100644
index 00000000000..f710fed880f
--- /dev/null
+++ b/innobase/eval/eval0proc.c
@@ -0,0 +1,245 @@
+/******************************************************
+Executes SQL stored procedures and their control structures
+
+(c) 1998 Innobase Oy
+
+Created 1/20/1998 Heikki Tuuri
+*******************************************************/
+
+#include "eval0proc.h"
+
+#ifdef UNIV_NONINL
+#include "eval0proc.ic"
+#endif
+
+/**************************************************************************
+Performs an execution step of an if-statement node. */
+
+que_thr_t*
+if_step(
+/*====*/
+ /* out: query thread to run next or NULL */
+ que_thr_t* thr) /* in: query thread */
+{
+ if_node_t* node;
+ elsif_node_t* elsif_node;
+
+ ut_ad(thr);
+
+ node = thr->run_node;
+ ut_ad(que_node_get_type(node) == QUE_NODE_IF);
+
+ if (thr->prev_node == que_node_get_parent(node)) {
+
+ /* Evaluate the condition */
+
+ eval_exp(node->cond);
+
+ if (eval_node_get_ibool_val(node->cond)) {
+
+ /* The condition evaluated to TRUE: start execution
+ from the first statement in the statement list */
+
+ thr->run_node = node->stat_list;
+
+ } else if (node->else_part) {
+ thr->run_node = node->else_part;
+
+ } else if (node->elsif_list) {
+ elsif_node = node->elsif_list;
+
+ for (;;) {
+ eval_exp(elsif_node->cond);
+
+ if (eval_node_get_ibool_val(elsif_node->cond)) {
+
+ /* The condition evaluated to TRUE:
+ start execution from the first
+ statement in the statement list */
+
+ thr->run_node = elsif_node->stat_list;
+
+ break;
+ }
+
+ elsif_node = que_node_get_next(elsif_node);
+
+ if (elsif_node == NULL) {
+ thr->run_node = NULL;
+
+ break;
+ }
+ }
+ } else {
+ thr->run_node = NULL;
+ }
+ } else {
+ /* Move to the next statement */
+ ut_ad(que_node_get_next(thr->prev_node) == NULL);
+
+ thr->run_node = NULL;
+ }
+
+ if (thr->run_node == NULL) {
+ thr->run_node = que_node_get_parent(node);
+ }
+
+ return(thr);
+}
+
+/**************************************************************************
+Performs an execution step of a while-statement node. */
+
+que_thr_t*
+while_step(
+/*=======*/
+ /* out: query thread to run next or NULL */
+ que_thr_t* thr) /* in: query thread */
+{
+ while_node_t* node;
+
+ ut_ad(thr);
+
+ node = thr->run_node;
+ ut_ad(que_node_get_type(node) == QUE_NODE_WHILE);
+
+ ut_ad((thr->prev_node == que_node_get_parent(node))
+ || (que_node_get_next(thr->prev_node) == NULL));
+
+ /* Evaluate the condition */
+
+ eval_exp(node->cond);
+
+ if (eval_node_get_ibool_val(node->cond)) {
+
+ /* The condition evaluated to TRUE: start execution
+ from the first statement in the statement list */
+
+ thr->run_node = node->stat_list;
+ } else {
+ thr->run_node = que_node_get_parent(node);
+ }
+
+ return(thr);
+}
+
+/**************************************************************************
+Performs an execution step of an assignment statement node. */
+
+que_thr_t*
+assign_step(
+/*========*/
+ /* out: query thread to run next or NULL */
+ que_thr_t* thr) /* in: query thread */
+{
+ assign_node_t* node;
+
+ ut_ad(thr);
+
+ node = thr->run_node;
+ ut_ad(que_node_get_type(node) == QUE_NODE_ASSIGNMENT);
+
+ /* Evaluate the value to assign */
+
+ eval_exp(node->val);
+
+ eval_node_copy_val(node->var->alias, node->val);
+
+ thr->run_node = que_node_get_parent(node);
+
+ return(thr);
+}
+
+/**************************************************************************
+Performs an execution step of a for-loop node. */
+
+que_thr_t*
+for_step(
+/*=====*/
+ /* out: query thread to run next or NULL */
+ que_thr_t* thr) /* in: query thread */
+{
+ for_node_t* node;
+ que_node_t* parent;
+ int loop_var_value;
+
+ ut_ad(thr);
+
+ node = thr->run_node;
+
+ ut_ad(que_node_get_type(node) == QUE_NODE_FOR);
+
+ parent = que_node_get_parent(node);
+
+ if (thr->prev_node != parent) {
+
+ /* Move to the next statement */
+ thr->run_node = que_node_get_next(thr->prev_node);
+
+ if (thr->run_node != NULL) {
+
+ return(thr);
+ }
+
+ /* Increment the value of loop_var */
+
+ loop_var_value = 1 + eval_node_get_int_val(node->loop_var);
+ } else {
+ /* Initialize the loop */
+
+ eval_exp(node->loop_start_limit);
+ eval_exp(node->loop_end_limit);
+
+ loop_var_value = eval_node_get_int_val(node->loop_start_limit);
+
+ node->loop_end_value = eval_node_get_int_val(
+ node->loop_end_limit);
+ }
+
+ /* Check if we should do another loop */
+
+ if (loop_var_value > node->loop_end_value) {
+
+ /* Enough loops done */
+
+ thr->run_node = parent;
+ } else {
+ eval_node_set_int_val(node->loop_var, loop_var_value);
+
+ thr->run_node = node->stat_list;
+ }
+
+ return(thr);
+}
+
+/**************************************************************************
+Performs an execution step of a return-statement node. */
+
+que_thr_t*
+return_step(
+/*========*/
+ /* out: query thread to run next or NULL */
+ que_thr_t* thr) /* in: query thread */
+{
+ return_node_t* node;
+ que_node_t* parent;
+
+ ut_ad(thr);
+
+ node = thr->run_node;
+
+ ut_ad(que_node_get_type(node) == QUE_NODE_RETURN);
+
+ parent = node;
+
+ while (que_node_get_type(parent) != QUE_NODE_PROC) {
+
+ parent = que_node_get_parent(parent);
+ }
+
+ ut_a(parent);
+
+ thr->run_node = que_node_get_parent(parent);
+
+ return(thr);
+}
diff --git a/innobase/eval/makefilewin b/innobase/eval/makefilewin
new file mode 100644
index 00000000000..f587f2a05a6
--- /dev/null
+++ b/innobase/eval/makefilewin
@@ -0,0 +1,10 @@
+include ..\include\makefile.i
+
+eval.lib: eval0eval.obj eval0proc.obj
+ lib -out:..\libs\eval.lib eval0eval.obj eval0proc.obj
+
+eval0eval.obj: eval0eval.c
+ $(CCOM) $(CFL) -c eval0eval.c
+
+eval0proc.obj: eval0proc.c
+ $(CCOM) $(CFL) -c eval0proc.c