mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	This is loosely based on the InnoDB changes in mysql/mysql-server@97fd8b1b69 that I had developed in 2015 or 2016. For each B-tree key field, we will allow a flag ASC/DESC to be associated. When PRIMARY KEY fields are internally appended to secondary indexes, the ASC/DESC attribute will be inherited, so that covering index scans will work as expected. Note: Until the subsequent commit, the DESC attribute will be ignored (no HA_REVERSE_SORT flag will be written to .frm files). dict_field_t::descending: A new flag to denote descending order. cmp_data(), cmp_dfield_dfield(): Add a new parameter descending. cmp_dtuple_rec(), cmp_dtuple_rec_with_match(): Add a parameter "index". dtuple_coll_eq(): Replaces dtuple_coll_cmp(). cmp_dfield_dfield_eq_prefix(): Replaces cmp_dfield_dfield_like_prefix(). dict_index_t::is_btree(): Check whether the index is a regular B-tree index (not SPATIAL, FULLTEXT, or the ibuf.index, or a corrupted index. btr_cur_search_to_nth_level_func(): Only attempt to use the adaptive hash index if index->is_btree(). This function may also be invoked on ibuf.index, and cmp_dtuple_rec_with_match_bytes() will no longer work on ibuf.index because it assumes that the index and record fields exactly match. The ibuf.index is a special variadic index tree. Thanks to Thirunarayanan Balathandayuthapani for fixing some bugs: MDEV-27439, MDEV-27374/MDEV-27445.
		
			
				
	
	
		
			643 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			643 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*****************************************************************************
 | 
						|
 | 
						|
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
 | 
						|
Copyright (c) 2019, 2021, MariaDB Corporation.
 | 
						|
 | 
						|
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; version 2 of the License.
 | 
						|
 | 
						|
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.,
 | 
						|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
 | 
						|
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
/**************************************************//**
 | 
						|
@file eval/eval0eval.cc
 | 
						|
SQL evaluator: evaluates simple data structures, like expressions, in
 | 
						|
a query graph
 | 
						|
 | 
						|
Created 12/29/1997 Heikki Tuuri
 | 
						|
*******************************************************/
 | 
						|
 | 
						|
#include "eval0eval.h"
 | 
						|
#include "data0data.h"
 | 
						|
#include "row0sel.h"
 | 
						|
#include "rem0cmp.h"
 | 
						|
 | 
						|
/** Dummy adress used when we should allocate a buffer of size 0 in
 | 
						|
eval_node_alloc_val_buf */
 | 
						|
 | 
						|
static byte	eval_dummy;
 | 
						|
 | 
						|
/*************************************************************************
 | 
						|
Gets the like node from the node */
 | 
						|
UNIV_INLINE
 | 
						|
que_node_t*
 | 
						|
que_node_get_like_node(
 | 
						|
/*===================*/
 | 
						|
				/* out: next node in a list of nodes */
 | 
						|
	que_node_t*     node)   /* in: node in a list */
 | 
						|
{
 | 
						|
	return(((sym_node_t*) node)->like_node);
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************//**
 | 
						|
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.
 | 
						|
@return pointer to allocated buffer */
 | 
						|
byte*
 | 
						|
eval_node_alloc_val_buf(
 | 
						|
/*====================*/
 | 
						|
	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 = static_cast<byte*>(dfield_get_data(dfield));
 | 
						|
 | 
						|
	if (data != &eval_dummy) {
 | 
						|
		ut_free(data);
 | 
						|
	}
 | 
						|
 | 
						|
	if (size == 0) {
 | 
						|
		data = &eval_dummy;
 | 
						|
	} else {
 | 
						|
		data = static_cast<byte*>(ut_malloc_nokey(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 = static_cast<byte*>(dfield_get_data(dfield));
 | 
						|
 | 
						|
	if (que_node_get_val_buf_size(node) > 0) {
 | 
						|
		ut_a(data);
 | 
						|
 | 
						|
		ut_free(data);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************
 | 
						|
Evaluates a LIKE comparison node.
 | 
						|
@return the result of the comparison */
 | 
						|
UNIV_INLINE
 | 
						|
ibool
 | 
						|
eval_cmp_like(
 | 
						|
/*==========*/
 | 
						|
	que_node_t*	arg1,		/* !< in: left operand */
 | 
						|
	que_node_t*	arg2)		/* !< in: right operand */
 | 
						|
{
 | 
						|
	ib_like_t	op;
 | 
						|
	que_node_t*	arg3;
 | 
						|
	que_node_t*	arg4;
 | 
						|
	const dfield_t*	dfield;
 | 
						|
 | 
						|
	arg3 = que_node_get_like_node(arg2);
 | 
						|
 | 
						|
	/* Get the comparison type operator */
 | 
						|
	ut_a(arg3);
 | 
						|
 | 
						|
	dfield = que_node_get_val(arg3);
 | 
						|
	ut_ad(dtype_get_mtype(dfield_get_type(dfield)) == DATA_INT);
 | 
						|
	op = static_cast<ib_like_t>(
 | 
						|
		mach_read_from_4(static_cast<const byte*>(
 | 
						|
					 dfield_get_data(dfield))));
 | 
						|
 | 
						|
	switch (op) {
 | 
						|
	case IB_LIKE_PREFIX:
 | 
						|
		arg4 = que_node_get_next(arg3);
 | 
						|
		return(cmp_dfield_dfield_eq_prefix(que_node_get_val(arg1),
 | 
						|
						   que_node_get_val(arg4)));
 | 
						|
	case IB_LIKE_EXACT:
 | 
						|
		return(!cmp_dfield_dfield(que_node_get_val(arg1),
 | 
						|
					  que_node_get_val(arg2)));
 | 
						|
	}
 | 
						|
 | 
						|
	ut_error;
 | 
						|
	return(FALSE);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************
 | 
						|
Evaluates a comparison node.
 | 
						|
@return the result of the comparison */
 | 
						|
ibool
 | 
						|
eval_cmp(
 | 
						|
/*=====*/
 | 
						|
	func_node_t*	cmp_node)	/*!< in: comparison node */
 | 
						|
{
 | 
						|
	que_node_t*	arg1;
 | 
						|
	que_node_t*	arg2;
 | 
						|
	int		res;
 | 
						|
	ibool		val	= FALSE; /* remove warning */
 | 
						|
 | 
						|
	ut_ad(que_node_get_type(cmp_node) == QUE_NODE_FUNC);
 | 
						|
 | 
						|
	arg1 = cmp_node->args;
 | 
						|
	arg2 = que_node_get_next(arg1);
 | 
						|
 | 
						|
	switch (cmp_node->func) {
 | 
						|
	case '<':
 | 
						|
	case '=':
 | 
						|
	case '>':
 | 
						|
	case PARS_LE_TOKEN:
 | 
						|
	case PARS_NE_TOKEN:
 | 
						|
	case PARS_GE_TOKEN:
 | 
						|
		res = cmp_dfield_dfield(
 | 
						|
			que_node_get_val(arg1), que_node_get_val(arg2));
 | 
						|
 | 
						|
		switch (cmp_node->func) {
 | 
						|
		case '<':
 | 
						|
			val = (res < 0);
 | 
						|
			break;
 | 
						|
		case '=':
 | 
						|
			val = (res == 0);
 | 
						|
			break;
 | 
						|
		case '>':
 | 
						|
			val = (res > 0);
 | 
						|
			break;
 | 
						|
		case PARS_LE_TOKEN:
 | 
						|
			val = (res <= 0);
 | 
						|
			break;
 | 
						|
		case PARS_NE_TOKEN:
 | 
						|
			val = (res != 0);
 | 
						|
			break;
 | 
						|
		case PARS_GE_TOKEN:
 | 
						|
			val = (res >= 0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		val = eval_cmp_like(arg1, arg2);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	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 = 0; /* remove warning */
 | 
						|
	ibool		val = 0;  /* remove warning */
 | 
						|
	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 = 0; /* remove warning */
 | 
						|
	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 */
 | 
						|
{
 | 
						|
	lint		val;
 | 
						|
 | 
						|
	ut_ad(que_node_get_type(node) == QUE_NODE_FUNC);
 | 
						|
 | 
						|
	val = eval_node_get_int_val(node);
 | 
						|
 | 
						|
	ut_a(node->func == PARS_COUNT_TOKEN);
 | 
						|
	val = val + 1;
 | 
						|
	eval_node_set_int_val(node, val);
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************//**
 | 
						|
Evaluates a notfound-function node. */
 | 
						|
UNIV_INLINE
 | 
						|
void
 | 
						|
eval_notfound(
 | 
						|
/*==========*/
 | 
						|
	func_node_t*	func_node)	/*!< in: function node */
 | 
						|
{
 | 
						|
	sym_node_t*	cursor;
 | 
						|
	sel_node_t*	sel_node;
 | 
						|
	ibool		ibool_val;
 | 
						|
 | 
						|
	ut_ad(func_node->func == PARS_NOTFOUND_TOKEN);
 | 
						|
 | 
						|
	cursor = static_cast<sym_node_t*>(func_node->args);
 | 
						|
 | 
						|
	ut_ad(que_node_get_type(cursor) == QUE_NODE_SYMBOL);
 | 
						|
 | 
						|
	if (cursor->token_type == SYM_LIT) {
 | 
						|
		ut_ad(!memcmp(dfield_get_data(que_node_get_val(cursor)),
 | 
						|
			      "SQL", 3));
 | 
						|
		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 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg1)));
 | 
						|
 | 
						|
	const ulint str1_len = dfield_get_len(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);
 | 
						|
 | 
						|
	if (len1 > str1_len) {
 | 
						|
		len2 = 0;
 | 
						|
	} else {
 | 
						|
		str1 += len1;
 | 
						|
		if (len2 > str1_len - len1) {
 | 
						|
			len2 = str1_len - len1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	dfield_set_data(dfield, str1, 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 = static_cast<byte*>(dfield_get_data(dfield1));
 | 
						|
	str2 = static_cast<byte*>(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 = lint(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. */
 | 
						|
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);
 | 
						|
 | 
						|
		memcpy(data + len, dfield_get_data(dfield), len1);
 | 
						|
 | 
						|
		len += len1;
 | 
						|
 | 
						|
		arg = que_node_get_next(arg);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************//**
 | 
						|
Evaluates a predefined function node. If the first argument is an integer,
 | 
						|
this function looks at the second argument which is the integer length in
 | 
						|
bytes, and converts the integer to a VARCHAR.
 | 
						|
If the first argument is of some other type, this function converts it to
 | 
						|
BINARY. */
 | 
						|
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		len;
 | 
						|
	ulint		len1;
 | 
						|
 | 
						|
	arg1 = func_node->args;
 | 
						|
 | 
						|
	str1 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg1)));
 | 
						|
 | 
						|
	if (dtype_get_mtype(que_node_get_data_type(arg1)) != DATA_INT) {
 | 
						|
 | 
						|
		len = dfield_get_len(que_node_get_val(arg1));
 | 
						|
 | 
						|
		dfield = que_node_get_val(func_node);
 | 
						|
 | 
						|
		dfield_set_data(dfield, str1, len);
 | 
						|
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	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);
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************//**
 | 
						|
Evaluate LENGTH(). */
 | 
						|
inline void eval_length(func_node_t* func_node)
 | 
						|
{
 | 
						|
	eval_node_set_int_val(func_node,
 | 
						|
			      dfield_get_len(que_node_get_val
 | 
						|
					     (func_node->args)));
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************//**
 | 
						|
Evaluates a function node. */
 | 
						|
void
 | 
						|
eval_func(
 | 
						|
/*======*/
 | 
						|
	func_node_t*	func_node)	/*!< in: function node */
 | 
						|
{
 | 
						|
	que_node_t*	arg;
 | 
						|
	ulint		fclass;
 | 
						|
 | 
						|
	ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
 | 
						|
 | 
						|
	fclass = func_node->fclass;
 | 
						|
	const int 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_is_null(que_node_get_val(arg))
 | 
						|
		    && (fclass != PARS_FUNC_CMP)
 | 
						|
		    && (func != PARS_NOTFOUND_TOKEN)) {
 | 
						|
			ut_error;
 | 
						|
		}
 | 
						|
 | 
						|
		arg = que_node_get_next(arg);
 | 
						|
	}
 | 
						|
 | 
						|
	switch (fclass) {
 | 
						|
	case PARS_FUNC_CMP:
 | 
						|
		eval_cmp(func_node);
 | 
						|
		return;
 | 
						|
	case PARS_FUNC_ARITH:
 | 
						|
		eval_arith(func_node);
 | 
						|
		return;
 | 
						|
	case PARS_FUNC_AGGREGATE:
 | 
						|
		eval_aggregate(func_node);
 | 
						|
		return;
 | 
						|
	case PARS_FUNC_PREDEFINED:
 | 
						|
		switch (func) {
 | 
						|
		case PARS_NOTFOUND_TOKEN:
 | 
						|
			eval_notfound(func_node);
 | 
						|
			return;
 | 
						|
		case PARS_SUBSTR_TOKEN:
 | 
						|
			eval_substr(func_node);
 | 
						|
			return;
 | 
						|
		case PARS_INSTR_TOKEN:
 | 
						|
			eval_instr(func_node);
 | 
						|
			return;
 | 
						|
		case PARS_CONCAT_TOKEN:
 | 
						|
			eval_concat(func_node);
 | 
						|
			return;
 | 
						|
		case PARS_TO_BINARY_TOKEN:
 | 
						|
			eval_to_binary(func_node);
 | 
						|
			return;
 | 
						|
		case PARS_LENGTH_TOKEN:
 | 
						|
			eval_length(func_node);
 | 
						|
			return;
 | 
						|
		default:
 | 
						|
			ut_error;
 | 
						|
		}
 | 
						|
	case PARS_FUNC_LOGICAL:
 | 
						|
		eval_logical(func_node);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	ut_error;
 | 
						|
}
 |