1/*****************************************************************************
2
3Copyright (c) 1997, 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/eval0eval.cc
21SQL evaluator: evaluates simple data structures, like expressions, in
22a query graph
23
24Created 12/29/1997 Heikki Tuuri
25*******************************************************/
26
27#include "eval0eval.h"
28#include "data0data.h"
29#include "row0sel.h"
30#include "rem0cmp.h"
31
32/** The RND function seed */
33static ulint eval_rnd = 128367121;
34
35/** Dummy adress used when we should allocate a buffer of size 0 in
36eval_node_alloc_val_buf */
37
38static byte eval_dummy;
39
40/*************************************************************************
41Gets the like node from the node */
42UNIV_INLINE
43que_node_t*
44que_node_get_like_node(
45/*===================*/
46 /* out: next node in a list of nodes */
47 que_node_t* node) /* in: node in a list */
48{
49 return(((sym_node_t*) node)->like_node);
50}
51
52/*****************************************************************//**
53Allocate a buffer from global dynamic memory for a value of a que_node.
54NOTE that this memory must be explicitly freed when the query graph is
55freed. If the node already has an allocated buffer, that buffer is freed
56here. NOTE that this is the only function where dynamic memory should be
57allocated for a query node val field.
58@return pointer to allocated buffer */
59byte*
60eval_node_alloc_val_buf(
61/*====================*/
62 que_node_t* node, /*!< in: query graph node; sets the val field
63 data field to point to the new buffer, and
64 len field equal to size */
65 ulint size) /*!< in: buffer size */
66{
67 dfield_t* dfield;
68 byte* data;
69
70 ut_ad(que_node_get_type(node) == QUE_NODE_SYMBOL
71 || que_node_get_type(node) == QUE_NODE_FUNC);
72
73 dfield = que_node_get_val(node);
74
75 data = static_cast<byte*>(dfield_get_data(dfield));
76
77 if (data != &eval_dummy) {
78 ut_free(data);
79 }
80
81 if (size == 0) {
82 data = &eval_dummy;
83 } else {
84 data = static_cast<byte*>(ut_malloc_nokey(size));
85 }
86
87 que_node_set_val_buf_size(node, size);
88
89 dfield_set_data(dfield, data, size);
90
91 return(data);
92}
93
94/*****************************************************************//**
95Free the buffer from global dynamic memory for a value of a que_node,
96if it has been allocated in the above function. The freeing for pushed
97column values is done in sel_col_prefetch_buf_free. */
98void
99eval_node_free_val_buf(
100/*===================*/
101 que_node_t* node) /*!< in: query graph node */
102{
103 dfield_t* dfield;
104 byte* data;
105
106 ut_ad(que_node_get_type(node) == QUE_NODE_SYMBOL
107 || que_node_get_type(node) == QUE_NODE_FUNC);
108
109 dfield = que_node_get_val(node);
110
111 data = static_cast<byte*>(dfield_get_data(dfield));
112
113 if (que_node_get_val_buf_size(node) > 0) {
114 ut_a(data);
115
116 ut_free(data);
117 }
118}
119
120/*********************************************************************
121Evaluates a LIKE comparison node.
122@return the result of the comparison */
123UNIV_INLINE
124ibool
125eval_cmp_like(
126/*==========*/
127 que_node_t* arg1, /* !< in: left operand */
128 que_node_t* arg2) /* !< in: right operand */
129{
130 ib_like_t op;
131 que_node_t* arg3;
132 que_node_t* arg4;
133 const dfield_t* dfield;
134
135 arg3 = que_node_get_like_node(arg2);
136
137 /* Get the comparison type operator */
138 ut_a(arg3);
139
140 dfield = que_node_get_val(arg3);
141 ut_ad(dtype_get_mtype(dfield_get_type(dfield)) == DATA_INT);
142 op = static_cast<ib_like_t>(
143 mach_read_from_4(static_cast<const byte*>(
144 dfield_get_data(dfield))));
145
146 switch (op) {
147 case IB_LIKE_PREFIX:
148 arg4 = que_node_get_next(arg3);
149 return(!cmp_dfield_dfield_like_prefix(que_node_get_val(arg1),
150 que_node_get_val(arg4)));
151 case IB_LIKE_EXACT:
152 return(!cmp_dfield_dfield(que_node_get_val(arg1),
153 que_node_get_val(arg2)));
154 }
155
156 ut_error;
157 return(FALSE);
158}
159
160/*********************************************************************
161Evaluates a comparison node.
162@return the result of the comparison */
163ibool
164eval_cmp(
165/*=====*/
166 func_node_t* cmp_node) /*!< in: comparison node */
167{
168 que_node_t* arg1;
169 que_node_t* arg2;
170 int res;
171 ibool val = FALSE; /* remove warning */
172
173 ut_ad(que_node_get_type(cmp_node) == QUE_NODE_FUNC);
174
175 arg1 = cmp_node->args;
176 arg2 = que_node_get_next(arg1);
177
178 switch (cmp_node->func) {
179 case '<':
180 case '=':
181 case '>':
182 case PARS_LE_TOKEN:
183 case PARS_NE_TOKEN:
184 case PARS_GE_TOKEN:
185 res = cmp_dfield_dfield(
186 que_node_get_val(arg1), que_node_get_val(arg2));
187
188 switch (cmp_node->func) {
189 case '<':
190 val = (res < 0);
191 break;
192 case '=':
193 val = (res == 0);
194 break;
195 case '>':
196 val = (res > 0);
197 break;
198 case PARS_LE_TOKEN:
199 val = (res <= 0);
200 break;
201 case PARS_NE_TOKEN:
202 val = (res != 0);
203 break;
204 case PARS_GE_TOKEN:
205 val = (res >= 0);
206 break;
207 }
208 break;
209 default:
210 val = eval_cmp_like(arg1, arg2);
211 break;
212 }
213
214 eval_node_set_ibool_val(cmp_node, val);
215
216 return(val);
217}
218
219/*****************************************************************//**
220Evaluates a logical operation node. */
221UNIV_INLINE
222void
223eval_logical(
224/*=========*/
225 func_node_t* logical_node) /*!< in: logical operation node */
226{
227 que_node_t* arg1;
228 que_node_t* arg2;
229 ibool val1;
230 ibool val2 = 0; /* remove warning */
231 ibool val = 0; /* remove warning */
232 int func;
233
234 ut_ad(que_node_get_type(logical_node) == QUE_NODE_FUNC);
235
236 arg1 = logical_node->args;
237 arg2 = que_node_get_next(arg1); /* arg2 is NULL if func is 'NOT' */
238
239 val1 = eval_node_get_ibool_val(arg1);
240
241 if (arg2) {
242 val2 = eval_node_get_ibool_val(arg2);
243 }
244
245 func = logical_node->func;
246
247 if (func == PARS_AND_TOKEN) {
248 val = val1 & val2;
249 } else if (func == PARS_OR_TOKEN) {
250 val = val1 | val2;
251 } else if (func == PARS_NOT_TOKEN) {
252 val = TRUE - val1;
253 } else {
254 ut_error;
255 }
256
257 eval_node_set_ibool_val(logical_node, val);
258}
259
260/*****************************************************************//**
261Evaluates an arithmetic operation node. */
262UNIV_INLINE
263void
264eval_arith(
265/*=======*/
266 func_node_t* arith_node) /*!< in: arithmetic operation node */
267{
268 que_node_t* arg1;
269 que_node_t* arg2;
270 lint val1;
271 lint val2 = 0; /* remove warning */
272 lint val;
273 int func;
274
275 ut_ad(que_node_get_type(arith_node) == QUE_NODE_FUNC);
276
277 arg1 = arith_node->args;
278 arg2 = que_node_get_next(arg1); /* arg2 is NULL if func is unary '-' */
279
280 val1 = eval_node_get_int_val(arg1);
281
282 if (arg2) {
283 val2 = eval_node_get_int_val(arg2);
284 }
285
286 func = arith_node->func;
287
288 if (func == '+') {
289 val = val1 + val2;
290 } else if ((func == '-') && arg2) {
291 val = val1 - val2;
292 } else if (func == '-') {
293 val = -val1;
294 } else if (func == '*') {
295 val = val1 * val2;
296 } else {
297 ut_ad(func == '/');
298 val = val1 / val2;
299 }
300
301 eval_node_set_int_val(arith_node, val);
302}
303
304/*****************************************************************//**
305Evaluates an aggregate operation node. */
306UNIV_INLINE
307void
308eval_aggregate(
309/*===========*/
310 func_node_t* node) /*!< in: aggregate operation node */
311{
312 que_node_t* arg;
313 lint val;
314 lint arg_val;
315 int func;
316
317 ut_ad(que_node_get_type(node) == QUE_NODE_FUNC);
318
319 val = eval_node_get_int_val(node);
320
321 func = node->func;
322
323 if (func == PARS_COUNT_TOKEN) {
324
325 val = val + 1;
326 } else {
327 ut_ad(func == PARS_SUM_TOKEN);
328
329 arg = node->args;
330 arg_val = eval_node_get_int_val(arg);
331
332 val = val + arg_val;
333 }
334
335 eval_node_set_int_val(node, val);
336}
337
338/*****************************************************************//**
339Evaluates a predefined function node where the function is not relevant
340in benchmarks. */
341static
342void
343eval_predefined_2(
344/*==============*/
345 func_node_t* func_node) /*!< in: predefined function node */
346{
347 que_node_t* arg;
348 que_node_t* arg1;
349 que_node_t* arg2 = 0; /* remove warning (??? bug ???) */
350 lint int_val;
351 byte* data;
352 ulint len1;
353 ulint len2;
354 int func;
355 ulint i;
356
357 ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
358
359 arg1 = func_node->args;
360
361 if (arg1) {
362 arg2 = que_node_get_next(arg1);
363 }
364
365 func = func_node->func;
366
367 if (func == PARS_PRINTF_TOKEN) {
368
369 arg = arg1;
370
371 while (arg) {
372 dfield_print(que_node_get_val(arg));
373
374 arg = que_node_get_next(arg);
375 }
376
377 putc('\n', stderr);
378
379 } else if (func == PARS_ASSERT_TOKEN) {
380
381 if (!eval_node_get_ibool_val(arg1)) {
382 fputs("SQL assertion fails in a stored procedure!\n",
383 stderr);
384 }
385
386 ut_a(eval_node_get_ibool_val(arg1));
387
388 /* This function, or more precisely, a debug procedure,
389 returns no value */
390
391 } else if (func == PARS_RND_TOKEN) {
392
393 len1 = (ulint) eval_node_get_int_val(arg1);
394 len2 = (ulint) eval_node_get_int_val(arg2);
395
396 ut_ad(len2 >= len1);
397
398 if (len2 > len1) {
399 int_val = (lint) (len1
400 + (eval_rnd % (len2 - len1 + 1)));
401 } else {
402 int_val = (lint) len1;
403 }
404
405 eval_rnd = ut_rnd_gen_next_ulint(eval_rnd);
406
407 eval_node_set_int_val(func_node, int_val);
408
409 } else if (func == PARS_RND_STR_TOKEN) {
410
411 len1 = (ulint) eval_node_get_int_val(arg1);
412
413 data = eval_node_ensure_val_buf(func_node, len1);
414
415 for (i = 0; i < len1; i++) {
416 data[i] = (byte)(97 + (eval_rnd % 3));
417
418 eval_rnd = ut_rnd_gen_next_ulint(eval_rnd);
419 }
420 } else {
421 ut_error;
422 }
423}
424
425/*****************************************************************//**
426Evaluates a notfound-function node. */
427UNIV_INLINE
428void
429eval_notfound(
430/*==========*/
431 func_node_t* func_node) /*!< in: function node */
432{
433 sym_node_t* cursor;
434 sel_node_t* sel_node;
435 ibool ibool_val;
436
437 ut_ad(func_node->func == PARS_NOTFOUND_TOKEN);
438
439 cursor = static_cast<sym_node_t*>(func_node->args);
440
441 ut_ad(que_node_get_type(cursor) == QUE_NODE_SYMBOL);
442
443 if (cursor->token_type == SYM_LIT) {
444
445 ut_ad(ut_memcmp(dfield_get_data(que_node_get_val(cursor)),
446 "SQL", 3) == 0);
447
448 sel_node = cursor->sym_table->query_graph->last_sel_node;
449 } else {
450 sel_node = cursor->alias->cursor_def;
451 }
452
453 if (sel_node->state == SEL_NODE_NO_MORE_ROWS) {
454 ibool_val = TRUE;
455 } else {
456 ibool_val = FALSE;
457 }
458
459 eval_node_set_ibool_val(func_node, ibool_val);
460}
461
462/*****************************************************************//**
463Evaluates a substr-function node. */
464UNIV_INLINE
465void
466eval_substr(
467/*========*/
468 func_node_t* func_node) /*!< in: function node */
469{
470 que_node_t* arg1;
471 que_node_t* arg2;
472 que_node_t* arg3;
473 dfield_t* dfield;
474 byte* str1;
475 ulint len1;
476 ulint len2;
477
478 arg1 = func_node->args;
479 arg2 = que_node_get_next(arg1);
480
481 ut_ad(func_node->func == PARS_SUBSTR_TOKEN);
482
483 arg3 = que_node_get_next(arg2);
484
485 str1 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg1)));
486
487 len1 = (ulint) eval_node_get_int_val(arg2);
488 len2 = (ulint) eval_node_get_int_val(arg3);
489
490 dfield = que_node_get_val(func_node);
491
492 dfield_set_data(dfield, str1 + len1, len2);
493}
494
495/*****************************************************************//**
496Evaluates a replstr-procedure node. */
497static
498void
499eval_replstr(
500/*=========*/
501 func_node_t* func_node) /*!< in: function node */
502{
503 que_node_t* arg1;
504 que_node_t* arg2;
505 que_node_t* arg3;
506 que_node_t* arg4;
507 byte* str1;
508 byte* str2;
509 ulint len1;
510 ulint len2;
511
512 arg1 = func_node->args;
513 arg2 = que_node_get_next(arg1);
514
515 ut_ad(que_node_get_type(arg1) == QUE_NODE_SYMBOL);
516
517 arg3 = que_node_get_next(arg2);
518 arg4 = que_node_get_next(arg3);
519
520 str1 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg1)));
521 str2 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg2)));
522
523 len1 = (ulint) eval_node_get_int_val(arg3);
524 len2 = (ulint) eval_node_get_int_val(arg4);
525
526 if ((dfield_get_len(que_node_get_val(arg1)) < len1 + len2)
527 || (dfield_get_len(que_node_get_val(arg2)) < len2)) {
528
529 ut_error;
530 }
531
532 ut_memcpy(str1 + len1, str2, len2);
533}
534
535/*****************************************************************//**
536Evaluates an instr-function node. */
537static
538void
539eval_instr(
540/*=======*/
541 func_node_t* func_node) /*!< in: function node */
542{
543 que_node_t* arg1;
544 que_node_t* arg2;
545 dfield_t* dfield1;
546 dfield_t* dfield2;
547 lint int_val;
548 byte* str1;
549 byte* str2;
550 byte match_char;
551 ulint len1;
552 ulint len2;
553 ulint i;
554 ulint j;
555
556 arg1 = func_node->args;
557 arg2 = que_node_get_next(arg1);
558
559 dfield1 = que_node_get_val(arg1);
560 dfield2 = que_node_get_val(arg2);
561
562 str1 = static_cast<byte*>(dfield_get_data(dfield1));
563 str2 = static_cast<byte*>(dfield_get_data(dfield2));
564
565 len1 = dfield_get_len(dfield1);
566 len2 = dfield_get_len(dfield2);
567
568 if (len2 == 0) {
569 ut_error;
570 }
571
572 match_char = str2[0];
573
574 for (i = 0; i < len1; i++) {
575 /* In this outer loop, the number of matched characters is 0 */
576
577 if (str1[i] == match_char) {
578
579 if (i + len2 > len1) {
580
581 break;
582 }
583
584 for (j = 1;; j++) {
585 /* We have already matched j characters */
586
587 if (j == len2) {
588 int_val = lint(i) + 1;
589
590 goto match_found;
591 }
592
593 if (str1[i + j] != str2[j]) {
594
595 break;
596 }
597 }
598 }
599 }
600
601 int_val = 0;
602
603match_found:
604 eval_node_set_int_val(func_node, int_val);
605}
606
607/*****************************************************************//**
608Evaluates a predefined function node. */
609UNIV_INLINE
610void
611eval_binary_to_number(
612/*==================*/
613 func_node_t* func_node) /*!< in: function node */
614{
615 que_node_t* arg1;
616 dfield_t* dfield;
617 byte* str1;
618 byte* str2;
619 ulint len1;
620 ulint int_val;
621
622 arg1 = func_node->args;
623
624 dfield = que_node_get_val(arg1);
625
626 str1 = static_cast<byte*>(dfield_get_data(dfield));
627 len1 = dfield_get_len(dfield);
628
629 if (len1 > 4) {
630 ut_error;
631 }
632
633 if (len1 == 4) {
634 str2 = str1;
635 } else {
636 int_val = 0;
637 str2 = (byte*) &int_val;
638
639 ut_memcpy(str2 + (4 - len1), str1, len1);
640 }
641
642 eval_node_copy_and_alloc_val(func_node, str2, 4);
643}
644
645/*****************************************************************//**
646Evaluates a predefined function node. */
647static
648void
649eval_concat(
650/*========*/
651 func_node_t* func_node) /*!< in: function node */
652{
653 que_node_t* arg;
654 dfield_t* dfield;
655 byte* data;
656 ulint len;
657 ulint len1;
658
659 arg = func_node->args;
660 len = 0;
661
662 while (arg) {
663 len1 = dfield_get_len(que_node_get_val(arg));
664
665 len += len1;
666
667 arg = que_node_get_next(arg);
668 }
669
670 data = eval_node_ensure_val_buf(func_node, len);
671
672 arg = func_node->args;
673 len = 0;
674
675 while (arg) {
676 dfield = que_node_get_val(arg);
677 len1 = dfield_get_len(dfield);
678
679 ut_memcpy(data + len, dfield_get_data(dfield), len1);
680
681 len += len1;
682
683 arg = que_node_get_next(arg);
684 }
685}
686
687/*****************************************************************//**
688Evaluates a predefined function node. If the first argument is an integer,
689this function looks at the second argument which is the integer length in
690bytes, and converts the integer to a VARCHAR.
691If the first argument is of some other type, this function converts it to
692BINARY. */
693UNIV_INLINE
694void
695eval_to_binary(
696/*===========*/
697 func_node_t* func_node) /*!< in: function node */
698{
699 que_node_t* arg1;
700 que_node_t* arg2;
701 dfield_t* dfield;
702 byte* str1;
703 ulint len;
704 ulint len1;
705
706 arg1 = func_node->args;
707
708 str1 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg1)));
709
710 if (dtype_get_mtype(que_node_get_data_type(arg1)) != DATA_INT) {
711
712 len = dfield_get_len(que_node_get_val(arg1));
713
714 dfield = que_node_get_val(func_node);
715
716 dfield_set_data(dfield, str1, len);
717
718 return;
719 }
720
721 arg2 = que_node_get_next(arg1);
722
723 len1 = (ulint) eval_node_get_int_val(arg2);
724
725 if (len1 > 4) {
726
727 ut_error;
728 }
729
730 dfield = que_node_get_val(func_node);
731
732 dfield_set_data(dfield, str1 + (4 - len1), len1);
733}
734
735/*****************************************************************//**
736Evaluates a predefined function node. */
737UNIV_INLINE
738void
739eval_predefined(
740/*============*/
741 func_node_t* func_node) /*!< in: function node */
742{
743 que_node_t* arg1;
744 lint int_val;
745 byte* data;
746 int func;
747
748 func = func_node->func;
749
750 arg1 = func_node->args;
751
752 if (func == PARS_LENGTH_TOKEN) {
753
754 int_val = (lint) dfield_get_len(que_node_get_val(arg1));
755
756 } else if (func == PARS_TO_CHAR_TOKEN) {
757
758 /* Convert number to character string as a
759 signed decimal integer. */
760
761 ulint uint_val;
762 int int_len;
763
764 int_val = eval_node_get_int_val(arg1);
765
766 /* Determine the length of the string. */
767
768 if (int_val == 0) {
769 int_len = 1; /* the number 0 occupies 1 byte */
770 } else {
771 int_len = 0;
772 if (int_val < 0) {
773 uint_val = ((ulint) -int_val - 1) + 1;
774 int_len++; /* reserve space for minus sign */
775 } else {
776 uint_val = (ulint) int_val;
777 }
778 for (; uint_val > 0; int_len++) {
779 uint_val /= 10;
780 }
781 }
782
783 /* allocate the string */
784 data = eval_node_ensure_val_buf(func_node, ulint(int_len) + 1);
785
786 /* add terminating NUL character */
787 data[int_len] = 0;
788
789 /* convert the number */
790
791 if (int_val == 0) {
792 data[0] = '0';
793 } else {
794 int tmp;
795 if (int_val < 0) {
796 data[0] = '-'; /* preceding minus sign */
797 uint_val = ((ulint) -int_val - 1) + 1;
798 } else {
799 uint_val = (ulint) int_val;
800 }
801 for (tmp = int_len; uint_val > 0; uint_val /= 10) {
802 data[--tmp] = (byte)
803 ('0' + (byte)(uint_val % 10));
804 }
805 }
806
807 dfield_set_len(que_node_get_val(func_node), ulint(int_len));
808
809 return;
810
811 } else if (func == PARS_TO_NUMBER_TOKEN) {
812
813 int_val = atoi((char*)
814 dfield_get_data(que_node_get_val(arg1)));
815
816 } else if (func == PARS_SYSDATE_TOKEN) {
817 int_val = (lint) ut_time();
818 } else {
819 eval_predefined_2(func_node);
820
821 return;
822 }
823
824 eval_node_set_int_val(func_node, int_val);
825}
826
827/*****************************************************************//**
828Evaluates a function node. */
829void
830eval_func(
831/*======*/
832 func_node_t* func_node) /*!< in: function node */
833{
834 que_node_t* arg;
835 ulint fclass;
836
837 ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
838
839 fclass = func_node->fclass;
840 const int func = func_node->func;
841
842 arg = func_node->args;
843
844 /* Evaluate first the argument list */
845 while (arg) {
846 eval_exp(arg);
847
848 /* The functions are not defined for SQL null argument
849 values, except for eval_cmp and notfound */
850
851 if (dfield_is_null(que_node_get_val(arg))
852 && (fclass != PARS_FUNC_CMP)
853 && (func != PARS_NOTFOUND_TOKEN)
854 && (func != PARS_PRINTF_TOKEN)) {
855 ut_error;
856 }
857
858 arg = que_node_get_next(arg);
859 }
860
861 switch (fclass) {
862 case PARS_FUNC_CMP:
863 eval_cmp(func_node);
864 return;
865 case PARS_FUNC_ARITH:
866 eval_arith(func_node);
867 return;
868 case PARS_FUNC_AGGREGATE:
869 eval_aggregate(func_node);
870 return;
871 case PARS_FUNC_PREDEFINED:
872 switch (func) {
873 case PARS_NOTFOUND_TOKEN:
874 eval_notfound(func_node);
875 return;
876 case PARS_SUBSTR_TOKEN:
877 eval_substr(func_node);
878 return;
879 case PARS_REPLSTR_TOKEN:
880 eval_replstr(func_node);
881 return;
882 case PARS_INSTR_TOKEN:
883 eval_instr(func_node);
884 return;
885 case PARS_BINARY_TO_NUMBER_TOKEN:
886 eval_binary_to_number(func_node);
887 return;
888 case PARS_CONCAT_TOKEN:
889 eval_concat(func_node);
890 return;
891 case PARS_TO_BINARY_TOKEN:
892 eval_to_binary(func_node);
893 return;
894 default:
895 eval_predefined(func_node);
896 return;
897 }
898 case PARS_FUNC_LOGICAL:
899 eval_logical(func_node);
900 return;
901 }
902
903 ut_error;
904}
905