mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	dict_stats_fetch_from_ps(): Acquire dict_sys.latch as few times as possible, and release dict_sys.latch after invoking pars_sql(), so that we will not be unnecessarily holding dict_sys.latch while possibly waiting for data to be read into the buffer pool.
		
			
				
	
	
		
			2373 lines
		
	
	
	
		
			58 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2373 lines
		
	
	
	
		
			58 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*****************************************************************************
 | 
						|
 | 
						|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
 | 
						|
Copyright (c) 2018, 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 St,
 | 
						|
Fifth Floor, Boston, MA 02110-1335 USA
 | 
						|
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
/**************************************************//**
 | 
						|
@file pars/pars0pars.c
 | 
						|
SQL parser
 | 
						|
 | 
						|
Created 11/19/1996 Heikki Tuuri
 | 
						|
*******************************************************/
 | 
						|
 | 
						|
/* Historical note: Innobase executed its first SQL string (CREATE TABLE)
 | 
						|
on 1/27/1998 */
 | 
						|
 | 
						|
#include "pars0pars.h"
 | 
						|
#include "row0sel.h"
 | 
						|
#include "row0ins.h"
 | 
						|
#include "row0upd.h"
 | 
						|
#include "dict0dict.h"
 | 
						|
#include "dict0mem.h"
 | 
						|
#include "dict0crea.h"
 | 
						|
#include "que0que.h"
 | 
						|
#include "pars0grm.h"
 | 
						|
#include "pars0opt.h"
 | 
						|
#include "data0data.h"
 | 
						|
#include "data0type.h"
 | 
						|
#include "trx0trx.h"
 | 
						|
#include "trx0roll.h"
 | 
						|
#include "eval0eval.h"
 | 
						|
 | 
						|
/* Global variable used while parsing a single procedure or query : the code is
 | 
						|
NOT re-entrant */
 | 
						|
sym_tab_t*	pars_sym_tab_global;
 | 
						|
 | 
						|
/* Global variables used to denote certain reserved words, used in
 | 
						|
constructing the parsing tree */
 | 
						|
 | 
						|
pars_res_word_t	pars_to_binary_token = {PARS_TO_BINARY_TOKEN};
 | 
						|
pars_res_word_t	pars_substr_token = {PARS_SUBSTR_TOKEN};
 | 
						|
pars_res_word_t	pars_concat_token = {PARS_CONCAT_TOKEN};
 | 
						|
pars_res_word_t	pars_instr_token = {PARS_INSTR_TOKEN};
 | 
						|
pars_res_word_t	pars_length_token = {PARS_LENGTH_TOKEN};
 | 
						|
pars_res_word_t	pars_count_token = {PARS_COUNT_TOKEN};
 | 
						|
pars_res_word_t	pars_int_token = {PARS_INT_TOKEN};
 | 
						|
pars_res_word_t	pars_bigint_token = {PARS_BIGINT_TOKEN};
 | 
						|
pars_res_word_t	pars_char_token = {PARS_CHAR_TOKEN};
 | 
						|
pars_res_word_t	pars_update_token = {PARS_UPDATE_TOKEN};
 | 
						|
pars_res_word_t	pars_asc_token = {PARS_ASC_TOKEN};
 | 
						|
pars_res_word_t	pars_desc_token = {PARS_DESC_TOKEN};
 | 
						|
pars_res_word_t	pars_open_token = {PARS_OPEN_TOKEN};
 | 
						|
pars_res_word_t	pars_close_token = {PARS_CLOSE_TOKEN};
 | 
						|
pars_res_word_t	pars_share_token = {PARS_SHARE_TOKEN};
 | 
						|
pars_res_word_t	pars_unique_token = {PARS_UNIQUE_TOKEN};
 | 
						|
pars_res_word_t	pars_clustered_token = {PARS_CLUSTERED_TOKEN};
 | 
						|
 | 
						|
/** Global variable used to denote the '*' in SELECT * FROM.. */
 | 
						|
ulint	pars_star_denoter	= 12345678;
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
Get user function with the given name.*/
 | 
						|
UNIV_INLINE
 | 
						|
pars_user_func_t*
 | 
						|
pars_info_lookup_user_func(
 | 
						|
/*=======================*/
 | 
						|
					/* out: user func, or NULL if not
 | 
						|
					found */
 | 
						|
	pars_info_t*		info,	/* in: info struct */
 | 
						|
	const char*		name)	/* in: function name to find*/
 | 
						|
{
 | 
						|
	if (info && info->funcs) {
 | 
						|
		ulint		i;
 | 
						|
		ib_vector_t*	vec = info->funcs;
 | 
						|
 | 
						|
		for (i = 0; i < ib_vector_size(vec); i++) {
 | 
						|
			pars_user_func_t*	puf;
 | 
						|
 | 
						|
			puf = static_cast<pars_user_func_t*>(
 | 
						|
				ib_vector_get(vec, i));
 | 
						|
 | 
						|
			if (strcmp(puf->name, name) == 0) {
 | 
						|
				return(puf);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return(NULL);
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
Get bound identifier with the given name.*/
 | 
						|
UNIV_INLINE
 | 
						|
pars_bound_id_t*
 | 
						|
pars_info_lookup_bound_id(
 | 
						|
/*======================*/
 | 
						|
					/* out: bound literal, or NULL if
 | 
						|
					not found */
 | 
						|
	pars_info_t*		info,	/* in: info struct */
 | 
						|
	const char*		name)	/* in: bound literal name to find */
 | 
						|
{
 | 
						|
	if (info && info->bound_ids) {
 | 
						|
		ulint		i;
 | 
						|
		ib_vector_t*	vec = info->bound_ids;
 | 
						|
 | 
						|
		for (i = 0; i < ib_vector_size(vec); i++) {
 | 
						|
			pars_bound_id_t*	bid;
 | 
						|
 | 
						|
		       	bid = static_cast<pars_bound_id_t*>(
 | 
						|
				ib_vector_get(vec, i));
 | 
						|
 | 
						|
			if (strcmp(bid->name, name) == 0) {
 | 
						|
				return(bid);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return(NULL);
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
Get bound literal with the given name.*/
 | 
						|
UNIV_INLINE
 | 
						|
pars_bound_lit_t*
 | 
						|
pars_info_lookup_bound_lit(
 | 
						|
/*=======================*/
 | 
						|
					/* out: bound literal, or NULL if
 | 
						|
					not found */
 | 
						|
	pars_info_t*		info,	/* in: info struct */
 | 
						|
	const char*		name)	/* in: bound literal name to find */
 | 
						|
{
 | 
						|
	if (info && info->bound_lits) {
 | 
						|
		ulint		i;
 | 
						|
		ib_vector_t*	vec = info->bound_lits;
 | 
						|
 | 
						|
		for (i = 0; i < ib_vector_size(vec); i++) {
 | 
						|
			pars_bound_lit_t*	pbl;
 | 
						|
 | 
						|
			pbl = static_cast<pars_bound_lit_t*>(
 | 
						|
				ib_vector_get(vec, i));
 | 
						|
 | 
						|
			if (strcmp(pbl->name, name) == 0) {
 | 
						|
				return(pbl);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return(NULL);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Determines the class of a function code.
 | 
						|
@return function class: PARS_FUNC_ARITH, ... */
 | 
						|
static
 | 
						|
ulint
 | 
						|
pars_func_get_class(
 | 
						|
/*================*/
 | 
						|
	int	func)	/*!< in: function code: '=', PARS_GE_TOKEN, ... */
 | 
						|
{
 | 
						|
	switch (func) {
 | 
						|
	case '+': case '-': case '*': case '/':
 | 
						|
		return(PARS_FUNC_ARITH);
 | 
						|
 | 
						|
	case '=': case '<': case '>':
 | 
						|
	case PARS_GE_TOKEN: case PARS_LE_TOKEN: case PARS_NE_TOKEN:
 | 
						|
		return(PARS_FUNC_CMP);
 | 
						|
 | 
						|
	case PARS_AND_TOKEN: case PARS_OR_TOKEN: case PARS_NOT_TOKEN:
 | 
						|
		return(PARS_FUNC_LOGICAL);
 | 
						|
 | 
						|
	case PARS_COUNT_TOKEN:
 | 
						|
		return(PARS_FUNC_AGGREGATE);
 | 
						|
 | 
						|
	case PARS_TO_BINARY_TOKEN:
 | 
						|
	case PARS_SUBSTR_TOKEN:
 | 
						|
	case PARS_CONCAT_TOKEN:
 | 
						|
	case PARS_LENGTH_TOKEN:
 | 
						|
	case PARS_INSTR_TOKEN:
 | 
						|
	case PARS_NOTFOUND_TOKEN:
 | 
						|
		return(PARS_FUNC_PREDEFINED);
 | 
						|
 | 
						|
	default:
 | 
						|
		return(PARS_FUNC_OTHER);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an operator or predefined function expression.
 | 
						|
@return own: function node in a query tree */
 | 
						|
static
 | 
						|
func_node_t*
 | 
						|
pars_func_low(
 | 
						|
/*==========*/
 | 
						|
	int		func,	/*!< in: function token code */
 | 
						|
	que_node_t*	arg)	/*!< in: first argument in the argument list */
 | 
						|
{
 | 
						|
	func_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<func_node_t*>(
 | 
						|
		mem_heap_alloc(pars_sym_tab_global->heap, sizeof(func_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_FUNC;
 | 
						|
	dfield_set_data(&(node->common.val), NULL, 0);
 | 
						|
	node->common.val_buf_size = 0;
 | 
						|
 | 
						|
	node->func = func;
 | 
						|
 | 
						|
	node->fclass = pars_func_get_class(func);
 | 
						|
 | 
						|
	node->args = arg;
 | 
						|
 | 
						|
	UT_LIST_ADD_LAST(pars_sym_tab_global->func_node_list, node);
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a function expression.
 | 
						|
@return own: function node in a query tree */
 | 
						|
func_node_t*
 | 
						|
pars_func(
 | 
						|
/*======*/
 | 
						|
	que_node_t*	res_word,/*!< in: function name reserved word */
 | 
						|
	que_node_t*	arg)	/*!< in: first argument in the argument list */
 | 
						|
{
 | 
						|
	return(pars_func_low(((pars_res_word_t*) res_word)->code, arg));
 | 
						|
}
 | 
						|
 | 
						|
/*************************************************************************
 | 
						|
Rebind a LIKE search string. NOTE: We ignore any '%' characters embedded
 | 
						|
within the search string.*/
 | 
						|
int
 | 
						|
pars_like_rebind(
 | 
						|
/*=============*/
 | 
						|
				/* out, own: function node in a query tree */
 | 
						|
	sym_node_t*	node,	/* in: The search string node.*/
 | 
						|
	const byte*	ptr,	/* in: literal to (re) bind */
 | 
						|
	ulint		ptr_len)/* in: length of literal to (re) bind*/
 | 
						|
{
 | 
						|
	dtype_t*	dtype;
 | 
						|
	dfield_t*	dfield;
 | 
						|
	ib_like_t	op_check;
 | 
						|
	sym_node_t*	like_node;
 | 
						|
	sym_node_t*	str_node = NULL;
 | 
						|
	ib_like_t	op = IB_LIKE_EXACT;
 | 
						|
	int		func = PARS_LIKE_TOKEN_EXACT;
 | 
						|
 | 
						|
	/* Is this a STRING% ? */
 | 
						|
	if (ptr[ptr_len - 1] == '%') {
 | 
						|
		op = IB_LIKE_PREFIX;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Is this a '%STRING' or %STRING% ?*/
 | 
						|
	ut_ad(*ptr != '%');
 | 
						|
 | 
						|
	if (node->like_node == NULL) {
 | 
						|
		/* Add the LIKE operator info node to the node list.
 | 
						|
		This will be used during the comparison phase to determine
 | 
						|
		how to match.*/
 | 
						|
		like_node = sym_tab_add_int_lit(node->sym_table, op);
 | 
						|
		que_node_list_add_last(NULL, like_node);
 | 
						|
		node->like_node = like_node;
 | 
						|
		str_node = sym_tab_add_str_lit(node->sym_table, ptr, ptr_len);
 | 
						|
		que_node_list_add_last(like_node, str_node);
 | 
						|
	} else {
 | 
						|
		like_node = node->like_node;
 | 
						|
 | 
						|
		/* Change the value of the string in the existing
 | 
						|
		string node of like node */
 | 
						|
		str_node = static_cast<sym_node_t*>(
 | 
						|
			que_node_list_get_last(like_node));
 | 
						|
 | 
						|
		/* Must find the string node */
 | 
						|
		ut_a(str_node);
 | 
						|
		ut_a(str_node != like_node);
 | 
						|
		ut_a(str_node->token_type == SYM_LIT);
 | 
						|
 | 
						|
		dfield = que_node_get_val(str_node);
 | 
						|
		dfield_set_data(dfield, ptr, ptr_len);
 | 
						|
	}
 | 
						|
 | 
						|
	dfield = que_node_get_val(like_node);
 | 
						|
	dtype = dfield_get_type(dfield);
 | 
						|
 | 
						|
	ut_a(dtype_get_mtype(dtype) == DATA_INT);
 | 
						|
	op_check = static_cast<ib_like_t>(
 | 
						|
		mach_read_from_4(static_cast<byte*>(dfield_get_data(dfield))));
 | 
						|
 | 
						|
	switch (op_check) {
 | 
						|
	case IB_LIKE_PREFIX:
 | 
						|
	case IB_LIKE_EXACT:
 | 
						|
		break;
 | 
						|
 | 
						|
	default:
 | 
						|
		ut_error;
 | 
						|
	}
 | 
						|
 | 
						|
	mach_write_to_4(static_cast<byte*>(dfield_get_data(dfield)), op);
 | 
						|
 | 
						|
	dfield = que_node_get_val(node);
 | 
						|
 | 
						|
	/* Adjust the length of the search value so the '%' is not
 | 
						|
	visible. Then create and add a search string node to the
 | 
						|
	search value node. Searching for %SUFFIX and %SUBSTR% requires
 | 
						|
	a full table scan and so we set the search value to ''.
 | 
						|
	For PREFIX% we simply remove the trailing '%'.*/
 | 
						|
 | 
						|
	switch (op) {
 | 
						|
	case	IB_LIKE_EXACT:
 | 
						|
		dfield = que_node_get_val(str_node);
 | 
						|
		dtype = dfield_get_type(dfield);
 | 
						|
 | 
						|
		ut_a(dtype_get_mtype(dtype) == DATA_VARCHAR);
 | 
						|
 | 
						|
		dfield_set_data(dfield, ptr, ptr_len);
 | 
						|
		break;
 | 
						|
 | 
						|
	case	IB_LIKE_PREFIX:
 | 
						|
		func = PARS_LIKE_TOKEN_PREFIX;
 | 
						|
 | 
						|
		/* Modify the original node */
 | 
						|
		dfield_set_len(dfield, ptr_len - 1);
 | 
						|
 | 
						|
		dfield = que_node_get_val(str_node);
 | 
						|
		dtype = dfield_get_type(dfield);
 | 
						|
 | 
						|
		ut_a(dtype_get_mtype(dtype) == DATA_VARCHAR);
 | 
						|
 | 
						|
		dfield_set_data(dfield, ptr, ptr_len - 1);
 | 
						|
		break;
 | 
						|
 | 
						|
	default:
 | 
						|
		ut_error;
 | 
						|
	}
 | 
						|
 | 
						|
	return(func);
 | 
						|
}
 | 
						|
 | 
						|
/*************************************************************************
 | 
						|
Parses a LIKE operator expression. */
 | 
						|
static
 | 
						|
int
 | 
						|
pars_like_op(
 | 
						|
/*=========*/
 | 
						|
				/* out, own: function node in a query tree */
 | 
						|
	que_node_t*	arg)	/* in: LIKE comparison string.*/
 | 
						|
{
 | 
						|
	char*		ptr;
 | 
						|
	ulint		ptr_len;
 | 
						|
	int		func = PARS_LIKE_TOKEN_EXACT;
 | 
						|
	dfield_t*	dfield = que_node_get_val(arg);
 | 
						|
	dtype_t*	dtype = dfield_get_type(dfield);
 | 
						|
 | 
						|
	ut_a(dtype_get_mtype(dtype) == DATA_CHAR
 | 
						|
	     || dtype_get_mtype(dtype) == DATA_VARCHAR);
 | 
						|
 | 
						|
	ptr = static_cast<char*>(dfield_get_data(dfield));
 | 
						|
	ptr_len = strlen(ptr);
 | 
						|
 | 
						|
	if (ptr_len) {
 | 
						|
 | 
						|
		func = pars_like_rebind(
 | 
						|
			static_cast<sym_node_t*>(arg), (byte*) ptr, ptr_len);
 | 
						|
	}
 | 
						|
 | 
						|
	return(func);
 | 
						|
}
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an operator expression.
 | 
						|
@return own: function node in a query tree */
 | 
						|
func_node_t*
 | 
						|
pars_op(
 | 
						|
/*====*/
 | 
						|
	int		func,	/*!< in: operator token code */
 | 
						|
	que_node_t*	arg1,	/*!< in: first argument */
 | 
						|
	que_node_t*	arg2)	/*!< in: second argument or NULL for an unary
 | 
						|
				operator */
 | 
						|
{
 | 
						|
	que_node_list_add_last(NULL, arg1);
 | 
						|
 | 
						|
	if (arg2) {
 | 
						|
		que_node_list_add_last(arg1, arg2);
 | 
						|
	}
 | 
						|
 | 
						|
	/* We need to parse the string and determine whether it's a
 | 
						|
	PREFIX, SUFFIX or SUBSTRING comparison */
 | 
						|
	if (func == PARS_LIKE_TOKEN) {
 | 
						|
 | 
						|
		ut_a(que_node_get_type(arg2) == QUE_NODE_SYMBOL);
 | 
						|
 | 
						|
		func = pars_like_op(arg2);
 | 
						|
 | 
						|
		ut_a(func == PARS_LIKE_TOKEN_EXACT
 | 
						|
		     || func == PARS_LIKE_TOKEN_PREFIX
 | 
						|
		     || func == PARS_LIKE_TOKEN_SUFFIX
 | 
						|
		     || func == PARS_LIKE_TOKEN_SUBSTR);
 | 
						|
	}
 | 
						|
 | 
						|
	return(pars_func_low(func, arg1));
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an ORDER BY clause. Order by a single column only is supported.
 | 
						|
@return own: order-by node in a query tree */
 | 
						|
order_node_t*
 | 
						|
pars_order_by(
 | 
						|
/*==========*/
 | 
						|
	sym_node_t*	column,	/*!< in: column name */
 | 
						|
	pars_res_word_t* asc)	/*!< in: &pars_asc_token or pars_desc_token */
 | 
						|
{
 | 
						|
	order_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<order_node_t*>(
 | 
						|
		mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(order_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_ORDER;
 | 
						|
 | 
						|
	node->column = column;
 | 
						|
 | 
						|
	if (asc == &pars_asc_token) {
 | 
						|
		node->asc = TRUE;
 | 
						|
	} else {
 | 
						|
		ut_a(asc == &pars_desc_token);
 | 
						|
		node->asc = FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Determine if a data type is a built-in string data type of the InnoDB
 | 
						|
SQL parser.
 | 
						|
@return TRUE if string data type */
 | 
						|
static
 | 
						|
ibool
 | 
						|
pars_is_string_type(
 | 
						|
/*================*/
 | 
						|
	ulint	mtype)	/*!< in: main data type */
 | 
						|
{
 | 
						|
	switch (mtype) {
 | 
						|
	case DATA_VARCHAR: case DATA_CHAR:
 | 
						|
	case DATA_FIXBINARY: case DATA_BINARY:
 | 
						|
		return(TRUE);
 | 
						|
	}
 | 
						|
 | 
						|
	return(FALSE);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Resolves the data type of a function in an expression. The argument data
 | 
						|
types must already be resolved. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_resolve_func_data_type(
 | 
						|
/*========================*/
 | 
						|
	func_node_t*	node)	/*!< in: function node */
 | 
						|
{
 | 
						|
	que_node_t*	arg;
 | 
						|
 | 
						|
	ut_a(que_node_get_type(node) == QUE_NODE_FUNC);
 | 
						|
 | 
						|
	arg = node->args;
 | 
						|
 | 
						|
	switch (node->func) {
 | 
						|
	case '+': case '-': case '*': case '/':
 | 
						|
		/* Inherit the data type from the first argument (which must
 | 
						|
		not be the SQL null literal whose type is DATA_ERROR) */
 | 
						|
 | 
						|
		dtype_copy(que_node_get_data_type(node),
 | 
						|
			   que_node_get_data_type(arg));
 | 
						|
 | 
						|
		ut_a(dtype_get_mtype(que_node_get_data_type(node))
 | 
						|
		     == DATA_INT);
 | 
						|
		break;
 | 
						|
 | 
						|
	case PARS_COUNT_TOKEN:
 | 
						|
		ut_a(arg);
 | 
						|
		dtype_set(que_node_get_data_type(node), DATA_INT, 0, 4);
 | 
						|
		break;
 | 
						|
 | 
						|
	case PARS_TO_BINARY_TOKEN:
 | 
						|
		if (dtype_get_mtype(que_node_get_data_type(arg)) == DATA_INT) {
 | 
						|
			dtype_set(que_node_get_data_type(node), DATA_VARCHAR,
 | 
						|
				  DATA_ENGLISH, 0);
 | 
						|
		} else {
 | 
						|
			dtype_set(que_node_get_data_type(node), DATA_BINARY,
 | 
						|
				  0, 0);
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
	case PARS_LENGTH_TOKEN:
 | 
						|
	case PARS_INSTR_TOKEN:
 | 
						|
		ut_a(pars_is_string_type(que_node_get_data_type(arg)->mtype));
 | 
						|
		dtype_set(que_node_get_data_type(node), DATA_INT, 0, 4);
 | 
						|
		break;
 | 
						|
 | 
						|
	case PARS_SUBSTR_TOKEN:
 | 
						|
	case PARS_CONCAT_TOKEN:
 | 
						|
		ut_a(pars_is_string_type(que_node_get_data_type(arg)->mtype));
 | 
						|
		dtype_set(que_node_get_data_type(node), DATA_VARCHAR,
 | 
						|
			  DATA_ENGLISH, 0);
 | 
						|
		break;
 | 
						|
 | 
						|
	case '>': case '<': case '=':
 | 
						|
	case PARS_GE_TOKEN:
 | 
						|
	case PARS_LE_TOKEN:
 | 
						|
	case PARS_NE_TOKEN:
 | 
						|
	case PARS_AND_TOKEN:
 | 
						|
	case PARS_OR_TOKEN:
 | 
						|
	case PARS_NOT_TOKEN:
 | 
						|
	case PARS_NOTFOUND_TOKEN:
 | 
						|
 | 
						|
		/* We currently have no iboolean type: use integer type */
 | 
						|
		dtype_set(que_node_get_data_type(node), DATA_INT, 0, 4);
 | 
						|
		break;
 | 
						|
 | 
						|
	case PARS_LIKE_TOKEN_EXACT:
 | 
						|
	case PARS_LIKE_TOKEN_PREFIX:
 | 
						|
	case PARS_LIKE_TOKEN_SUFFIX:
 | 
						|
	case PARS_LIKE_TOKEN_SUBSTR:
 | 
						|
		dtype_set(que_node_get_data_type(node), DATA_VARCHAR,
 | 
						|
			  DATA_ENGLISH, 0);
 | 
						|
		break;
 | 
						|
 | 
						|
	default:
 | 
						|
		ut_error;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Resolves the meaning of variables in an expression and the data types of
 | 
						|
functions. It is an error if some identifier cannot be resolved here. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_resolve_exp_variables_and_types(
 | 
						|
/*=================================*/
 | 
						|
	sel_node_t*	select_node,	/*!< in: select node or NULL; if
 | 
						|
					this is not NULL then the variable
 | 
						|
					sym nodes are added to the
 | 
						|
					copy_variables list of select_node */
 | 
						|
	que_node_t*	exp_node)	/*!< in: expression */
 | 
						|
{
 | 
						|
	func_node_t*	func_node;
 | 
						|
	que_node_t*	arg;
 | 
						|
	sym_node_t*	sym_node;
 | 
						|
	sym_node_t*	node;
 | 
						|
 | 
						|
	ut_a(exp_node);
 | 
						|
 | 
						|
	if (que_node_get_type(exp_node) == QUE_NODE_FUNC) {
 | 
						|
		func_node = static_cast<func_node_t*>(exp_node);
 | 
						|
 | 
						|
		arg = func_node->args;
 | 
						|
 | 
						|
		while (arg) {
 | 
						|
			pars_resolve_exp_variables_and_types(select_node, arg);
 | 
						|
 | 
						|
			arg = que_node_get_next(arg);
 | 
						|
		}
 | 
						|
 | 
						|
		pars_resolve_func_data_type(func_node);
 | 
						|
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	ut_a(que_node_get_type(exp_node) == QUE_NODE_SYMBOL);
 | 
						|
 | 
						|
	sym_node = static_cast<sym_node_t*>(exp_node);
 | 
						|
 | 
						|
	if (sym_node->resolved) {
 | 
						|
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Not resolved yet: look in the symbol table for a variable
 | 
						|
	or a cursor or a function with the same name */
 | 
						|
 | 
						|
	node = UT_LIST_GET_FIRST(pars_sym_tab_global->sym_list);
 | 
						|
 | 
						|
	while (node) {
 | 
						|
		if (node->resolved
 | 
						|
		    && ((node->token_type == SYM_VAR)
 | 
						|
			|| (node->token_type == SYM_CURSOR)
 | 
						|
			|| (node->token_type == SYM_FUNCTION))
 | 
						|
		    && node->name
 | 
						|
		    && sym_node->name_len == node->name_len
 | 
						|
		    && !memcmp(sym_node->name, node->name, node->name_len)) {
 | 
						|
 | 
						|
			/* Found a variable or a cursor declared with
 | 
						|
			the same name */
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		node = UT_LIST_GET_NEXT(sym_list, node);
 | 
						|
	}
 | 
						|
 | 
						|
	if (!node) {
 | 
						|
		fprintf(stderr, "PARSER ERROR: Unresolved identifier %s\n",
 | 
						|
			sym_node->name);
 | 
						|
	}
 | 
						|
 | 
						|
	ut_a(node);
 | 
						|
 | 
						|
	sym_node->resolved = TRUE;
 | 
						|
	sym_node->token_type = SYM_IMPLICIT_VAR;
 | 
						|
	sym_node->alias = node;
 | 
						|
	sym_node->indirection = node;
 | 
						|
 | 
						|
	if (select_node) {
 | 
						|
		UT_LIST_ADD_LAST(select_node->copy_variables, sym_node);
 | 
						|
	}
 | 
						|
 | 
						|
	dfield_set_type(que_node_get_val(sym_node),
 | 
						|
			que_node_get_data_type(node));
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Resolves the meaning of variables in an expression list. It is an error if
 | 
						|
some identifier cannot be resolved here. Resolves also the data types of
 | 
						|
functions. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_resolve_exp_list_variables_and_types(
 | 
						|
/*======================================*/
 | 
						|
	sel_node_t*	select_node,	/*!< in: select node or NULL */
 | 
						|
	que_node_t*	exp_node)	/*!< in: expression list first node, or
 | 
						|
					NULL */
 | 
						|
{
 | 
						|
	while (exp_node) {
 | 
						|
		pars_resolve_exp_variables_and_types(select_node, exp_node);
 | 
						|
 | 
						|
		exp_node = que_node_get_next(exp_node);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Resolves the columns in an expression. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_resolve_exp_columns(
 | 
						|
/*=====================*/
 | 
						|
	sym_node_t*	table_node,	/*!< in: first node in a table list */
 | 
						|
	que_node_t*	exp_node)	/*!< in: expression */
 | 
						|
{
 | 
						|
	func_node_t*	func_node;
 | 
						|
	que_node_t*	arg;
 | 
						|
	sym_node_t*	sym_node;
 | 
						|
	dict_table_t*	table;
 | 
						|
	sym_node_t*	t_node;
 | 
						|
	ulint		n_cols;
 | 
						|
	ulint		i;
 | 
						|
 | 
						|
	ut_a(exp_node);
 | 
						|
 | 
						|
	if (que_node_get_type(exp_node) == QUE_NODE_FUNC) {
 | 
						|
		func_node = static_cast<func_node_t*>(exp_node);
 | 
						|
 | 
						|
		arg = func_node->args;
 | 
						|
 | 
						|
		while (arg) {
 | 
						|
			pars_resolve_exp_columns(table_node, arg);
 | 
						|
 | 
						|
			arg = que_node_get_next(arg);
 | 
						|
		}
 | 
						|
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	ut_a(que_node_get_type(exp_node) == QUE_NODE_SYMBOL);
 | 
						|
 | 
						|
	sym_node = static_cast<sym_node_t*>(exp_node);
 | 
						|
 | 
						|
	if (sym_node->resolved) {
 | 
						|
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Not resolved yet: look in the table list for a column with the
 | 
						|
	same name */
 | 
						|
 | 
						|
	t_node = table_node;
 | 
						|
 | 
						|
	while (t_node) {
 | 
						|
		table = t_node->table;
 | 
						|
 | 
						|
		n_cols = dict_table_get_n_cols(table);
 | 
						|
 | 
						|
		for (i = 0; i < n_cols; i++) {
 | 
						|
			const dict_col_t*	col
 | 
						|
				= dict_table_get_nth_col(table, i);
 | 
						|
			const char*		col_name
 | 
						|
				= dict_table_get_col_name(table, i);
 | 
						|
 | 
						|
			if (sym_node->name_len == strlen(col_name)
 | 
						|
			    && !memcmp(sym_node->name, col_name,
 | 
						|
				       sym_node->name_len)) {
 | 
						|
				/* Found */
 | 
						|
				sym_node->resolved = TRUE;
 | 
						|
				sym_node->token_type = SYM_COLUMN;
 | 
						|
				sym_node->table = table;
 | 
						|
				sym_node->col_no = i;
 | 
						|
				sym_node->prefetch_buf = NULL;
 | 
						|
 | 
						|
				dict_col_copy_type(
 | 
						|
					col,
 | 
						|
					dfield_get_type(&sym_node
 | 
						|
							->common.val));
 | 
						|
 | 
						|
				return;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		t_node = static_cast<sym_node_t*>(que_node_get_next(t_node));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Resolves the meaning of columns in an expression list. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_resolve_exp_list_columns(
 | 
						|
/*==========================*/
 | 
						|
	sym_node_t*	table_node,	/*!< in: first node in a table list */
 | 
						|
	que_node_t*	exp_node)	/*!< in: expression list first node, or
 | 
						|
					NULL */
 | 
						|
{
 | 
						|
	while (exp_node) {
 | 
						|
		pars_resolve_exp_columns(table_node, exp_node);
 | 
						|
 | 
						|
		exp_node = que_node_get_next(exp_node);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Retrieves the table definition for a table name id. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_retrieve_table_def(
 | 
						|
/*====================*/
 | 
						|
	sym_node_t*	sym_node)	/*!< in: table node */
 | 
						|
{
 | 
						|
	ut_a(sym_node);
 | 
						|
	ut_a(que_node_get_type(sym_node) == QUE_NODE_SYMBOL);
 | 
						|
 | 
						|
	/* Open the table only if it is not already opened. */
 | 
						|
	if (sym_node->token_type != SYM_TABLE_REF_COUNTED) {
 | 
						|
 | 
						|
		ut_a(sym_node->table == NULL);
 | 
						|
 | 
						|
		sym_node->resolved = TRUE;
 | 
						|
		sym_node->token_type = SYM_TABLE_REF_COUNTED;
 | 
						|
 | 
						|
		sym_node->table = dict_table_open_on_name(
 | 
						|
			sym_node->name, true, DICT_ERR_IGNORE_NONE);
 | 
						|
 | 
						|
		ut_a(sym_node->table != NULL);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Retrieves the table definitions for a list of table name ids.
 | 
						|
@return number of tables */
 | 
						|
static
 | 
						|
ulint
 | 
						|
pars_retrieve_table_list_defs(
 | 
						|
/*==========================*/
 | 
						|
	sym_node_t*	sym_node)	/*!< in: first table node in list */
 | 
						|
{
 | 
						|
	ulint		count		= 0;
 | 
						|
 | 
						|
	while (sym_node) {
 | 
						|
		pars_retrieve_table_def(sym_node);
 | 
						|
 | 
						|
		count++;
 | 
						|
 | 
						|
		sym_node = static_cast<sym_node_t*>(
 | 
						|
			que_node_get_next(sym_node));
 | 
						|
	}
 | 
						|
 | 
						|
	return(count);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Adds all columns to the select list if the query is SELECT * FROM ... */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_select_all_columns(
 | 
						|
/*====================*/
 | 
						|
	sel_node_t*	select_node)	/*!< in: select node already containing
 | 
						|
					the table list */
 | 
						|
{
 | 
						|
	sym_node_t*	col_node;
 | 
						|
	sym_node_t*	table_node;
 | 
						|
	dict_table_t*	table;
 | 
						|
	ulint		i;
 | 
						|
 | 
						|
	select_node->select_list = NULL;
 | 
						|
 | 
						|
	table_node = select_node->table_list;
 | 
						|
 | 
						|
	while (table_node) {
 | 
						|
		table = table_node->table;
 | 
						|
 | 
						|
		for (i = 0; i < dict_table_get_n_user_cols(table); i++) {
 | 
						|
			const char*	col_name = dict_table_get_col_name(
 | 
						|
				table, i);
 | 
						|
 | 
						|
			col_node = sym_tab_add_id(pars_sym_tab_global,
 | 
						|
						  (byte*) col_name,
 | 
						|
						  strlen(col_name));
 | 
						|
 | 
						|
			select_node->select_list = que_node_list_add_last(
 | 
						|
				select_node->select_list, col_node);
 | 
						|
		}
 | 
						|
 | 
						|
		table_node = static_cast<sym_node_t*>(
 | 
						|
			que_node_get_next(table_node));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a select list; creates a query graph node for the whole SELECT
 | 
						|
statement.
 | 
						|
@return own: select node in a query tree */
 | 
						|
sel_node_t*
 | 
						|
pars_select_list(
 | 
						|
/*=============*/
 | 
						|
	que_node_t*	select_list,	/*!< in: select list */
 | 
						|
	sym_node_t*	into_list)	/*!< in: variables list or NULL */
 | 
						|
{
 | 
						|
	sel_node_t*	node;
 | 
						|
 | 
						|
	node = sel_node_create(pars_sym_tab_global->heap);
 | 
						|
 | 
						|
	node->select_list = select_list;
 | 
						|
	node->into_list = into_list;
 | 
						|
 | 
						|
	pars_resolve_exp_list_variables_and_types(NULL, into_list);
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Checks if the query is an aggregate query, in which case the selct list must
 | 
						|
contain only aggregate function items. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_check_aggregate(
 | 
						|
/*=================*/
 | 
						|
	sel_node_t*	select_node)	/*!< in: select node already containing
 | 
						|
					the select list */
 | 
						|
{
 | 
						|
	que_node_t*	exp_node;
 | 
						|
	func_node_t*	func_node;
 | 
						|
	ulint		n_nodes			= 0;
 | 
						|
	ulint		n_aggregate_nodes	= 0;
 | 
						|
 | 
						|
	exp_node = select_node->select_list;
 | 
						|
 | 
						|
	while (exp_node) {
 | 
						|
 | 
						|
		n_nodes++;
 | 
						|
 | 
						|
		if (que_node_get_type(exp_node) == QUE_NODE_FUNC) {
 | 
						|
 | 
						|
			func_node = static_cast<func_node_t*>(exp_node);
 | 
						|
 | 
						|
			if (func_node->fclass == PARS_FUNC_AGGREGATE) {
 | 
						|
 | 
						|
				n_aggregate_nodes++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		exp_node = que_node_get_next(exp_node);
 | 
						|
	}
 | 
						|
 | 
						|
	if (n_aggregate_nodes > 0) {
 | 
						|
		ut_a(n_nodes == n_aggregate_nodes);
 | 
						|
 | 
						|
		select_node->is_aggregate = TRUE;
 | 
						|
	} else {
 | 
						|
		select_node->is_aggregate = FALSE;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a select statement.
 | 
						|
@return own: select node in a query tree */
 | 
						|
sel_node_t*
 | 
						|
pars_select_statement(
 | 
						|
/*==================*/
 | 
						|
	sel_node_t*	select_node,	/*!< in: select node already containing
 | 
						|
					the select list */
 | 
						|
	sym_node_t*	table_list,	/*!< in: table list */
 | 
						|
	que_node_t*	search_cond,	/*!< in: search condition or NULL */
 | 
						|
	pars_res_word_t* for_update,	/*!< in: NULL or &pars_update_token */
 | 
						|
	pars_res_word_t* lock_shared,	/*!< in: NULL or &pars_share_token */
 | 
						|
	order_node_t*	order_by)	/*!< in: NULL or an order-by node */
 | 
						|
{
 | 
						|
	select_node->state = SEL_NODE_OPEN;
 | 
						|
 | 
						|
	select_node->table_list = table_list;
 | 
						|
	select_node->n_tables = pars_retrieve_table_list_defs(table_list);
 | 
						|
 | 
						|
	if (select_node->select_list == &pars_star_denoter) {
 | 
						|
 | 
						|
		/* SELECT * FROM ... */
 | 
						|
		pars_select_all_columns(select_node);
 | 
						|
	}
 | 
						|
 | 
						|
	if (select_node->into_list) {
 | 
						|
		ut_a(que_node_list_get_len(select_node->into_list)
 | 
						|
		     == que_node_list_get_len(select_node->select_list));
 | 
						|
	}
 | 
						|
 | 
						|
	UT_LIST_INIT(select_node->copy_variables, &sym_node_t::col_var_list);
 | 
						|
 | 
						|
	pars_resolve_exp_list_columns(table_list, select_node->select_list);
 | 
						|
	pars_resolve_exp_list_variables_and_types(select_node,
 | 
						|
						  select_node->select_list);
 | 
						|
	pars_check_aggregate(select_node);
 | 
						|
 | 
						|
	select_node->search_cond = search_cond;
 | 
						|
 | 
						|
	if (search_cond) {
 | 
						|
		pars_resolve_exp_columns(table_list, search_cond);
 | 
						|
		pars_resolve_exp_variables_and_types(select_node, search_cond);
 | 
						|
	}
 | 
						|
 | 
						|
	if (for_update) {
 | 
						|
		ut_a(!lock_shared);
 | 
						|
 | 
						|
		select_node->set_x_locks = TRUE;
 | 
						|
		select_node->row_lock_mode = LOCK_X;
 | 
						|
 | 
						|
		select_node->consistent_read = FALSE;
 | 
						|
		select_node->read_view = NULL;
 | 
						|
	} else if (lock_shared){
 | 
						|
		select_node->set_x_locks = FALSE;
 | 
						|
		select_node->row_lock_mode = LOCK_S;
 | 
						|
 | 
						|
		select_node->consistent_read = FALSE;
 | 
						|
		select_node->read_view = NULL;
 | 
						|
	} else {
 | 
						|
		select_node->set_x_locks = FALSE;
 | 
						|
		select_node->row_lock_mode = LOCK_S;
 | 
						|
 | 
						|
		select_node->consistent_read = TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	select_node->order_by = order_by;
 | 
						|
 | 
						|
	if (order_by) {
 | 
						|
		pars_resolve_exp_columns(table_list, order_by->column);
 | 
						|
	}
 | 
						|
 | 
						|
	/* The final value of the following fields depend on the environment
 | 
						|
	where the select statement appears: */
 | 
						|
 | 
						|
	select_node->can_get_updated = FALSE;
 | 
						|
	select_node->explicit_cursor = NULL;
 | 
						|
 | 
						|
	opt_search_plan(select_node);
 | 
						|
 | 
						|
	return(select_node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a cursor declaration.
 | 
						|
@return sym_node */
 | 
						|
que_node_t*
 | 
						|
pars_cursor_declaration(
 | 
						|
/*====================*/
 | 
						|
	sym_node_t*	sym_node,	/*!< in: cursor id node in the symbol
 | 
						|
					table */
 | 
						|
	sel_node_t*	select_node)	/*!< in: select node */
 | 
						|
{
 | 
						|
	sym_node->resolved = TRUE;
 | 
						|
	sym_node->token_type = SYM_CURSOR;
 | 
						|
	sym_node->cursor_def = select_node;
 | 
						|
 | 
						|
	select_node->state = SEL_NODE_CLOSED;
 | 
						|
	select_node->explicit_cursor = sym_node;
 | 
						|
 | 
						|
	return(sym_node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a function declaration.
 | 
						|
@return sym_node */
 | 
						|
que_node_t*
 | 
						|
pars_function_declaration(
 | 
						|
/*======================*/
 | 
						|
	sym_node_t*	sym_node)	/*!< in: function id node in the symbol
 | 
						|
					table */
 | 
						|
{
 | 
						|
	sym_node->resolved = TRUE;
 | 
						|
	sym_node->token_type = SYM_FUNCTION;
 | 
						|
 | 
						|
	/* Check that the function exists. */
 | 
						|
	ut_a(pars_info_lookup_user_func(
 | 
						|
		pars_sym_tab_global->info, sym_node->name));
 | 
						|
 | 
						|
	return(sym_node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a delete or update statement start.
 | 
						|
@return own: update node in a query tree */
 | 
						|
upd_node_t*
 | 
						|
pars_update_statement_start(
 | 
						|
/*========================*/
 | 
						|
	ibool		is_delete,	/*!< in: TRUE if delete */
 | 
						|
	sym_node_t*	table_sym,	/*!< in: table name node */
 | 
						|
	col_assign_node_t* col_assign_list)/*!< in: column assignment list, NULL
 | 
						|
					if delete */
 | 
						|
{
 | 
						|
	upd_node_t*	node;
 | 
						|
 | 
						|
	node = upd_node_create(pars_sym_tab_global->heap);
 | 
						|
 | 
						|
	node->is_delete = is_delete ? PLAIN_DELETE : NO_DELETE;
 | 
						|
 | 
						|
	node->table_sym = table_sym;
 | 
						|
	node->col_assign_list = col_assign_list;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a column assignment in an update.
 | 
						|
@return column assignment node */
 | 
						|
col_assign_node_t*
 | 
						|
pars_column_assignment(
 | 
						|
/*===================*/
 | 
						|
	sym_node_t*	column,	/*!< in: column to assign */
 | 
						|
	que_node_t*	exp)	/*!< in: value to assign */
 | 
						|
{
 | 
						|
	col_assign_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<col_assign_node_t*>(
 | 
						|
		mem_heap_alloc(pars_sym_tab_global->heap,
 | 
						|
			      sizeof(col_assign_node_t)));
 | 
						|
	node->common.type = QUE_NODE_COL_ASSIGNMENT;
 | 
						|
 | 
						|
	node->col = column;
 | 
						|
	node->val = exp;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Processes an update node assignment list. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_process_assign_list(
 | 
						|
/*=====================*/
 | 
						|
	upd_node_t*	node)	/*!< in: update node */
 | 
						|
{
 | 
						|
	col_assign_node_t*	col_assign_list;
 | 
						|
	sym_node_t*		table_sym;
 | 
						|
	col_assign_node_t*	assign_node;
 | 
						|
	upd_field_t*		upd_field;
 | 
						|
	dict_index_t*		clust_index;
 | 
						|
	sym_node_t*		col_sym;
 | 
						|
	ulint			changes_ord_field;
 | 
						|
	ulint			changes_field_size;
 | 
						|
	ulint			n_assigns;
 | 
						|
	ulint			i;
 | 
						|
 | 
						|
	table_sym = node->table_sym;
 | 
						|
	col_assign_list = static_cast<col_assign_node_t*>(
 | 
						|
		 node->col_assign_list);
 | 
						|
	clust_index = dict_table_get_first_index(node->table);
 | 
						|
 | 
						|
	assign_node = col_assign_list;
 | 
						|
	n_assigns = 0;
 | 
						|
 | 
						|
	while (assign_node) {
 | 
						|
		pars_resolve_exp_columns(table_sym, assign_node->col);
 | 
						|
		pars_resolve_exp_columns(table_sym, assign_node->val);
 | 
						|
		pars_resolve_exp_variables_and_types(NULL, assign_node->val);
 | 
						|
#if 0
 | 
						|
		ut_a(dtype_get_mtype(
 | 
						|
			     dfield_get_type(que_node_get_val(
 | 
						|
						     assign_node->col)))
 | 
						|
		     == dtype_get_mtype(
 | 
						|
			     dfield_get_type(que_node_get_val(
 | 
						|
						     assign_node->val))));
 | 
						|
#endif
 | 
						|
 | 
						|
		/* Add to the update node all the columns found in assignment
 | 
						|
		values as columns to copy: therefore, TRUE */
 | 
						|
 | 
						|
		opt_find_all_cols(TRUE, clust_index, &(node->columns), NULL,
 | 
						|
				  assign_node->val);
 | 
						|
		n_assigns++;
 | 
						|
 | 
						|
		assign_node = static_cast<col_assign_node_t*>(
 | 
						|
				que_node_get_next(assign_node));
 | 
						|
	}
 | 
						|
 | 
						|
	node->update = upd_create(n_assigns, pars_sym_tab_global->heap);
 | 
						|
 | 
						|
	assign_node = col_assign_list;
 | 
						|
 | 
						|
	changes_field_size = UPD_NODE_NO_SIZE_CHANGE;
 | 
						|
 | 
						|
	for (i = 0; i < n_assigns; i++) {
 | 
						|
		upd_field = upd_get_nth_field(node->update, i);
 | 
						|
 | 
						|
		col_sym = assign_node->col;
 | 
						|
 | 
						|
		ulint field_no = dict_index_get_nth_col_pos(
 | 
						|
			clust_index, col_sym->col_no, NULL);
 | 
						|
		ut_ad(field_no < clust_index->n_fields);
 | 
						|
		upd_field_set_field_no(upd_field,
 | 
						|
				       static_cast<uint16_t>(field_no),
 | 
						|
				       clust_index);
 | 
						|
		upd_field->exp = assign_node->val;
 | 
						|
 | 
						|
		if (!dict_col_get_fixed_size(
 | 
						|
			    dict_index_get_nth_col(clust_index,
 | 
						|
						   upd_field->field_no),
 | 
						|
			    dict_table_is_comp(node->table))) {
 | 
						|
			changes_field_size = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		assign_node = static_cast<col_assign_node_t*>(
 | 
						|
				que_node_get_next(assign_node));
 | 
						|
	}
 | 
						|
 | 
						|
	/* Find out if the update can modify an ordering field in any index */
 | 
						|
 | 
						|
	changes_ord_field = UPD_NODE_NO_ORD_CHANGE;
 | 
						|
 | 
						|
	if (row_upd_changes_some_index_ord_field_binary(node->table,
 | 
						|
							node->update)) {
 | 
						|
		changes_ord_field = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	node->cmpl_info = changes_ord_field | changes_field_size;
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an update or delete statement.
 | 
						|
@return own: update node in a query tree */
 | 
						|
upd_node_t*
 | 
						|
pars_update_statement(
 | 
						|
/*==================*/
 | 
						|
	upd_node_t*	node,		/*!< in: update node */
 | 
						|
	sym_node_t*	cursor_sym,	/*!< in: pointer to a cursor entry in
 | 
						|
					the symbol table or NULL */
 | 
						|
	que_node_t*	search_cond)	/*!< in: search condition or NULL */
 | 
						|
{
 | 
						|
	sym_node_t*	table_sym;
 | 
						|
	sel_node_t*	sel_node;
 | 
						|
	plan_t*		plan;
 | 
						|
 | 
						|
	table_sym = node->table_sym;
 | 
						|
 | 
						|
	pars_retrieve_table_def(table_sym);
 | 
						|
	node->table = table_sym->table;
 | 
						|
 | 
						|
	UT_LIST_INIT(node->columns, &sym_node_t::col_var_list);
 | 
						|
 | 
						|
	/* Make the single table node into a list of table nodes of length 1 */
 | 
						|
 | 
						|
	que_node_list_add_last(NULL, table_sym);
 | 
						|
 | 
						|
	if (cursor_sym) {
 | 
						|
		pars_resolve_exp_variables_and_types(NULL, cursor_sym);
 | 
						|
 | 
						|
		sel_node = cursor_sym->alias->cursor_def;
 | 
						|
 | 
						|
		node->searched_update = FALSE;
 | 
						|
	} else {
 | 
						|
		sel_node = pars_select_list(NULL, NULL);
 | 
						|
 | 
						|
		pars_select_statement(sel_node, table_sym, search_cond, NULL,
 | 
						|
				      &pars_share_token, NULL);
 | 
						|
		node->searched_update = TRUE;
 | 
						|
		sel_node->common.parent = node;
 | 
						|
	}
 | 
						|
 | 
						|
	node->select = sel_node;
 | 
						|
 | 
						|
	ut_a(!node->is_delete || (node->col_assign_list == NULL));
 | 
						|
	ut_a(node->is_delete == PLAIN_DELETE || node->col_assign_list != NULL);
 | 
						|
 | 
						|
	if (node->is_delete == PLAIN_DELETE) {
 | 
						|
		node->cmpl_info = 0;
 | 
						|
	} else {
 | 
						|
		pars_process_assign_list(node);
 | 
						|
	}
 | 
						|
 | 
						|
	if (node->searched_update) {
 | 
						|
		node->has_clust_rec_x_lock = TRUE;
 | 
						|
		sel_node->set_x_locks = TRUE;
 | 
						|
		sel_node->row_lock_mode = LOCK_X;
 | 
						|
	} else {
 | 
						|
		node->has_clust_rec_x_lock = sel_node->set_x_locks;
 | 
						|
		ut_ad(node->has_clust_rec_x_lock);
 | 
						|
	}
 | 
						|
 | 
						|
	ut_a(sel_node->n_tables == 1);
 | 
						|
	ut_a(sel_node->consistent_read == FALSE);
 | 
						|
	ut_a(sel_node->order_by == NULL);
 | 
						|
	ut_a(sel_node->is_aggregate == FALSE);
 | 
						|
 | 
						|
	sel_node->can_get_updated = TRUE;
 | 
						|
 | 
						|
	node->state = UPD_NODE_UPDATE_CLUSTERED;
 | 
						|
 | 
						|
	plan = sel_node_get_nth_plan(sel_node, 0);
 | 
						|
 | 
						|
	plan->no_prefetch = TRUE;
 | 
						|
 | 
						|
	if (!dict_index_is_clust(plan->index)) {
 | 
						|
 | 
						|
		plan->must_get_clust = TRUE;
 | 
						|
 | 
						|
		node->pcur = &(plan->clust_pcur);
 | 
						|
	} else {
 | 
						|
		node->pcur = &(plan->pcur);
 | 
						|
	}
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an insert statement.
 | 
						|
@return own: update node in a query tree */
 | 
						|
ins_node_t*
 | 
						|
pars_insert_statement(
 | 
						|
/*==================*/
 | 
						|
	sym_node_t*	table_sym,	/*!< in: table name node */
 | 
						|
	que_node_t*	values_list,	/*!< in: value expression list or NULL */
 | 
						|
	sel_node_t*	select)		/*!< in: select condition or NULL */
 | 
						|
{
 | 
						|
	ins_node_t*	node;
 | 
						|
	dtuple_t*	row;
 | 
						|
	ulint		ins_type;
 | 
						|
 | 
						|
	ut_a(values_list || select);
 | 
						|
	ut_a(!values_list || !select);
 | 
						|
 | 
						|
	if (values_list) {
 | 
						|
		ins_type = INS_VALUES;
 | 
						|
	} else {
 | 
						|
		ins_type = INS_SEARCHED;
 | 
						|
	}
 | 
						|
 | 
						|
	pars_retrieve_table_def(table_sym);
 | 
						|
 | 
						|
	node = ins_node_create(ins_type, table_sym->table,
 | 
						|
			       pars_sym_tab_global->heap);
 | 
						|
 | 
						|
	row = dtuple_create(pars_sym_tab_global->heap,
 | 
						|
			    dict_table_get_n_cols(node->table));
 | 
						|
 | 
						|
	dict_table_copy_types(row, table_sym->table);
 | 
						|
 | 
						|
	ins_node_set_new_row(node, row);
 | 
						|
 | 
						|
	node->select = select;
 | 
						|
 | 
						|
	if (select) {
 | 
						|
		select->common.parent = node;
 | 
						|
 | 
						|
		ut_a(que_node_list_get_len(select->select_list)
 | 
						|
		     == dict_table_get_n_user_cols(table_sym->table));
 | 
						|
	}
 | 
						|
 | 
						|
	node->values_list = values_list;
 | 
						|
 | 
						|
	if (node->values_list) {
 | 
						|
		pars_resolve_exp_list_variables_and_types(NULL, values_list);
 | 
						|
 | 
						|
		ut_a(que_node_list_get_len(values_list)
 | 
						|
		     == dict_table_get_n_user_cols(table_sym->table));
 | 
						|
	}
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Set the type of a dfield. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_set_dfield_type(
 | 
						|
/*=================*/
 | 
						|
	dfield_t*		dfield,		/*!< in: dfield */
 | 
						|
	pars_res_word_t*	type,		/*!< in: pointer to a type
 | 
						|
						token */
 | 
						|
	ulint			len,		/*!< in: length, or 0 */
 | 
						|
	bool			is_not_null)	/*!< in: whether the column is
 | 
						|
						NOT NULL. */
 | 
						|
{
 | 
						|
	ulint flags = 0;
 | 
						|
 | 
						|
	if (is_not_null) {
 | 
						|
		flags |= DATA_NOT_NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (type == &pars_bigint_token) {
 | 
						|
		ut_a(len == 0);
 | 
						|
 | 
						|
		dtype_set(dfield_get_type(dfield), DATA_INT, flags, 8);
 | 
						|
	} else if (type == &pars_int_token) {
 | 
						|
		ut_a(len == 0);
 | 
						|
 | 
						|
		dtype_set(dfield_get_type(dfield), DATA_INT, flags, 4);
 | 
						|
 | 
						|
	} else if (type == &pars_char_token) {
 | 
						|
		//ut_a(len == 0);
 | 
						|
 | 
						|
		dtype_set(dfield_get_type(dfield), DATA_VARCHAR,
 | 
						|
			  DATA_ENGLISH | flags, len);
 | 
						|
	} else {
 | 
						|
		ut_error;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a variable declaration.
 | 
						|
@return own: symbol table node of type SYM_VAR */
 | 
						|
sym_node_t*
 | 
						|
pars_variable_declaration(
 | 
						|
/*======================*/
 | 
						|
	sym_node_t*	node,	/*!< in: symbol table node allocated for the
 | 
						|
				id of the variable */
 | 
						|
	pars_res_word_t* type)	/*!< in: pointer to a type token */
 | 
						|
{
 | 
						|
	node->resolved = TRUE;
 | 
						|
	node->token_type = SYM_VAR;
 | 
						|
 | 
						|
	node->param_type = PARS_NOT_PARAM;
 | 
						|
 | 
						|
	pars_set_dfield_type(que_node_get_val(node), type, 0, false);
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Sets the parent field in a query node list. */
 | 
						|
static
 | 
						|
void
 | 
						|
pars_set_parent_in_list(
 | 
						|
/*====================*/
 | 
						|
	que_node_t*	node_list,	/*!< in: first node in a list */
 | 
						|
	que_node_t*	parent)		/*!< in: parent value to set in all
 | 
						|
					nodes of the list */
 | 
						|
{
 | 
						|
	que_common_t*	common;
 | 
						|
 | 
						|
	common = static_cast<que_common_t*>(node_list);
 | 
						|
 | 
						|
	while (common) {
 | 
						|
		common->parent = parent;
 | 
						|
 | 
						|
		common = static_cast<que_common_t*>(que_node_get_next(common));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an elsif element.
 | 
						|
@return elsif node */
 | 
						|
elsif_node_t*
 | 
						|
pars_elsif_element(
 | 
						|
/*===============*/
 | 
						|
	que_node_t*	cond,		/*!< in: if-condition */
 | 
						|
	que_node_t*	stat_list)	/*!< in: statement list */
 | 
						|
{
 | 
						|
	elsif_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<elsif_node_t*>(
 | 
						|
		mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(elsif_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_ELSIF;
 | 
						|
 | 
						|
	node->cond = cond;
 | 
						|
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, cond);
 | 
						|
 | 
						|
	node->stat_list = stat_list;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an if-statement.
 | 
						|
@return if-statement node */
 | 
						|
if_node_t*
 | 
						|
pars_if_statement(
 | 
						|
/*==============*/
 | 
						|
	que_node_t*	cond,		/*!< in: if-condition */
 | 
						|
	que_node_t*	stat_list,	/*!< in: statement list */
 | 
						|
	que_node_t*	else_part)	/*!< in: else-part statement list
 | 
						|
					or elsif element list */
 | 
						|
{
 | 
						|
	if_node_t*	node;
 | 
						|
	elsif_node_t*	elsif_node;
 | 
						|
 | 
						|
	node = static_cast<if_node_t*>(
 | 
						|
		 mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(if_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_IF;
 | 
						|
 | 
						|
	node->cond = cond;
 | 
						|
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, cond);
 | 
						|
 | 
						|
	node->stat_list = stat_list;
 | 
						|
 | 
						|
	if (else_part && (que_node_get_type(else_part) == QUE_NODE_ELSIF)) {
 | 
						|
 | 
						|
		/* There is a list of elsif conditions */
 | 
						|
 | 
						|
		node->else_part = NULL;
 | 
						|
		node->elsif_list = static_cast<elsif_node_t*>(else_part);
 | 
						|
 | 
						|
		elsif_node = static_cast<elsif_node_t*>(else_part);
 | 
						|
 | 
						|
		while (elsif_node) {
 | 
						|
			pars_set_parent_in_list(elsif_node->stat_list, node);
 | 
						|
 | 
						|
			elsif_node = static_cast<elsif_node_t*>(
 | 
						|
				que_node_get_next(elsif_node));
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		node->else_part = else_part;
 | 
						|
		node->elsif_list = NULL;
 | 
						|
 | 
						|
		pars_set_parent_in_list(else_part, node);
 | 
						|
	}
 | 
						|
 | 
						|
	pars_set_parent_in_list(stat_list, node);
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a while-statement.
 | 
						|
@return while-statement node */
 | 
						|
while_node_t*
 | 
						|
pars_while_statement(
 | 
						|
/*=================*/
 | 
						|
	que_node_t*	cond,		/*!< in: while-condition */
 | 
						|
	que_node_t*	stat_list)	/*!< in: statement list */
 | 
						|
{
 | 
						|
	while_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<while_node_t*>(
 | 
						|
		mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(while_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_WHILE;
 | 
						|
 | 
						|
	node->cond = cond;
 | 
						|
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, cond);
 | 
						|
 | 
						|
	node->stat_list = stat_list;
 | 
						|
 | 
						|
	pars_set_parent_in_list(stat_list, node);
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a for-loop-statement.
 | 
						|
@return for-statement node */
 | 
						|
for_node_t*
 | 
						|
pars_for_statement(
 | 
						|
/*===============*/
 | 
						|
	sym_node_t*	loop_var,	/*!< in: loop variable */
 | 
						|
	que_node_t*	loop_start_limit,/*!< in: loop start expression */
 | 
						|
	que_node_t*	loop_end_limit,	/*!< in: loop end expression */
 | 
						|
	que_node_t*	stat_list)	/*!< in: statement list */
 | 
						|
{
 | 
						|
	for_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<for_node_t*>(
 | 
						|
		mem_heap_alloc(pars_sym_tab_global->heap, sizeof(for_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_FOR;
 | 
						|
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, loop_var);
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, loop_start_limit);
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, loop_end_limit);
 | 
						|
 | 
						|
	node->loop_var = loop_var->indirection;
 | 
						|
 | 
						|
	ut_a(loop_var->indirection);
 | 
						|
 | 
						|
	node->loop_start_limit = loop_start_limit;
 | 
						|
	node->loop_end_limit = loop_end_limit;
 | 
						|
 | 
						|
	node->stat_list = stat_list;
 | 
						|
 | 
						|
	pars_set_parent_in_list(stat_list, node);
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an exit statement.
 | 
						|
@return exit statement node */
 | 
						|
exit_node_t*
 | 
						|
pars_exit_statement(void)
 | 
						|
/*=====================*/
 | 
						|
{
 | 
						|
	exit_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<exit_node_t*>(
 | 
						|
		mem_heap_alloc(pars_sym_tab_global->heap, sizeof(exit_node_t)));
 | 
						|
	node->common.type = QUE_NODE_EXIT;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a return-statement.
 | 
						|
@return return-statement node */
 | 
						|
return_node_t*
 | 
						|
pars_return_statement(void)
 | 
						|
/*=======================*/
 | 
						|
{
 | 
						|
	return_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<return_node_t*>(
 | 
						|
		mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(return_node_t)));
 | 
						|
	node->common.type = QUE_NODE_RETURN;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an assignment statement.
 | 
						|
@return assignment statement node */
 | 
						|
assign_node_t*
 | 
						|
pars_assignment_statement(
 | 
						|
/*======================*/
 | 
						|
	sym_node_t*	var,	/*!< in: variable to assign */
 | 
						|
	que_node_t*	val)	/*!< in: value to assign */
 | 
						|
{
 | 
						|
	assign_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<assign_node_t*>(
 | 
						|
		mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(assign_node_t)));
 | 
						|
	node->common.type = QUE_NODE_ASSIGNMENT;
 | 
						|
 | 
						|
	node->var = var;
 | 
						|
	node->val = val;
 | 
						|
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, var);
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, val);
 | 
						|
 | 
						|
	ut_a(dtype_get_mtype(dfield_get_type(que_node_get_val(var)))
 | 
						|
	     == dtype_get_mtype(dfield_get_type(que_node_get_val(val))));
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a procedure call.
 | 
						|
@return function node */
 | 
						|
func_node_t*
 | 
						|
pars_procedure_call(
 | 
						|
/*================*/
 | 
						|
	que_node_t*	res_word,/*!< in: procedure name reserved word */
 | 
						|
	que_node_t*	args)	/*!< in: argument list */
 | 
						|
{
 | 
						|
	func_node_t*	node;
 | 
						|
 | 
						|
	node = pars_func(res_word, args);
 | 
						|
 | 
						|
	pars_resolve_exp_list_variables_and_types(NULL, args);
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a fetch statement. into_list or user_func (but not both) must be
 | 
						|
non-NULL.
 | 
						|
@return fetch statement node */
 | 
						|
fetch_node_t*
 | 
						|
pars_fetch_statement(
 | 
						|
/*=================*/
 | 
						|
	sym_node_t*	cursor,		/*!< in: cursor node */
 | 
						|
	sym_node_t*	into_list,	/*!< in: variables to set, or NULL */
 | 
						|
	sym_node_t*	user_func)	/*!< in: user function name, or NULL */
 | 
						|
{
 | 
						|
	sym_node_t*	cursor_decl;
 | 
						|
	fetch_node_t*	node;
 | 
						|
 | 
						|
	/* Logical XOR. */
 | 
						|
	ut_a(!into_list != !user_func);
 | 
						|
 | 
						|
	node = static_cast<fetch_node_t*>(
 | 
						|
		mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(fetch_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_FETCH;
 | 
						|
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, cursor);
 | 
						|
 | 
						|
	if (into_list) {
 | 
						|
		pars_resolve_exp_list_variables_and_types(NULL, into_list);
 | 
						|
		node->into_list = into_list;
 | 
						|
		node->func = NULL;
 | 
						|
	} else {
 | 
						|
		pars_resolve_exp_variables_and_types(NULL, user_func);
 | 
						|
 | 
						|
		node->func = pars_info_lookup_user_func(
 | 
						|
			pars_sym_tab_global->info, user_func->name);
 | 
						|
 | 
						|
		ut_a(node->func);
 | 
						|
 | 
						|
		node->into_list = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	cursor_decl = cursor->alias;
 | 
						|
 | 
						|
	ut_a(cursor_decl->token_type == SYM_CURSOR);
 | 
						|
 | 
						|
	node->cursor_def = cursor_decl->cursor_def;
 | 
						|
 | 
						|
	if (into_list) {
 | 
						|
		ut_a(que_node_list_get_len(into_list)
 | 
						|
		     == que_node_list_get_len(node->cursor_def->select_list));
 | 
						|
	}
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an open or close cursor statement.
 | 
						|
@return fetch statement node */
 | 
						|
open_node_t*
 | 
						|
pars_open_statement(
 | 
						|
/*================*/
 | 
						|
	ulint		type,	/*!< in: ROW_SEL_OPEN_CURSOR
 | 
						|
				or ROW_SEL_CLOSE_CURSOR */
 | 
						|
	sym_node_t*	cursor)	/*!< in: cursor node */
 | 
						|
{
 | 
						|
	sym_node_t*	cursor_decl;
 | 
						|
	open_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<open_node_t*>(
 | 
						|
		mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(open_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_OPEN;
 | 
						|
 | 
						|
	pars_resolve_exp_variables_and_types(NULL, cursor);
 | 
						|
 | 
						|
	cursor_decl = cursor->alias;
 | 
						|
 | 
						|
	ut_a(cursor_decl->token_type == SYM_CURSOR);
 | 
						|
 | 
						|
	node->op_type = static_cast<open_node_op>(type);
 | 
						|
	node->cursor_def = cursor_decl->cursor_def;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a row_printf-statement.
 | 
						|
@return row_printf-statement node */
 | 
						|
row_printf_node_t*
 | 
						|
pars_row_printf_statement(
 | 
						|
/*======================*/
 | 
						|
	sel_node_t*	sel_node)	/*!< in: select node */
 | 
						|
{
 | 
						|
	row_printf_node_t*	node;
 | 
						|
 | 
						|
	node = static_cast<row_printf_node_t*>(
 | 
						|
		mem_heap_alloc(
 | 
						|
			pars_sym_tab_global->heap, sizeof(row_printf_node_t)));
 | 
						|
	node->common.type = QUE_NODE_ROW_PRINTF;
 | 
						|
 | 
						|
	node->sel_node = sel_node;
 | 
						|
 | 
						|
	sel_node->common.parent = node;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a commit statement.
 | 
						|
@return own: commit node struct */
 | 
						|
commit_node_t*
 | 
						|
pars_commit_statement(void)
 | 
						|
/*=======================*/
 | 
						|
{
 | 
						|
	return(trx_commit_node_create(pars_sym_tab_global->heap));
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a rollback statement.
 | 
						|
@return own: rollback node struct */
 | 
						|
roll_node_t*
 | 
						|
pars_rollback_statement(void)
 | 
						|
/*=========================*/
 | 
						|
{
 | 
						|
	return(roll_node_create(pars_sym_tab_global->heap));
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a column definition at a table creation.
 | 
						|
@return column sym table node */
 | 
						|
sym_node_t*
 | 
						|
pars_column_def(
 | 
						|
/*============*/
 | 
						|
	sym_node_t*		sym_node,	/*!< in: column node in the
 | 
						|
						symbol table */
 | 
						|
	pars_res_word_t*	type,		/*!< in: data type */
 | 
						|
	sym_node_t*		len,		/*!< in: length of column, or
 | 
						|
						NULL */
 | 
						|
	void*			is_not_null)	/*!< in: if not NULL, column
 | 
						|
						is of type NOT NULL. */
 | 
						|
{
 | 
						|
	ulint len2;
 | 
						|
 | 
						|
	if (len) {
 | 
						|
		len2 = ulint(eval_node_get_int_val(len));
 | 
						|
	} else {
 | 
						|
		len2 = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	pars_set_dfield_type(que_node_get_val(sym_node), type, len2,
 | 
						|
			     is_not_null != NULL);
 | 
						|
 | 
						|
	return(sym_node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a table creation operation.
 | 
						|
@return table create subgraph */
 | 
						|
tab_node_t*
 | 
						|
pars_create_table(
 | 
						|
/*==============*/
 | 
						|
	sym_node_t*	table_sym,	/*!< in: table name node in the symbol
 | 
						|
					table */
 | 
						|
	sym_node_t*	column_defs)	/*!< in: list of column names */
 | 
						|
{
 | 
						|
	dict_table_t*	table;
 | 
						|
	sym_node_t*	column;
 | 
						|
	tab_node_t*	node;
 | 
						|
	const dtype_t*	dtype;
 | 
						|
	ulint		n_cols;
 | 
						|
	ulint		flags = 0;
 | 
						|
	ulint		flags2 = DICT_TF2_FTS_AUX_HEX_NAME;
 | 
						|
 | 
						|
	n_cols = que_node_list_get_len(column_defs);
 | 
						|
 | 
						|
	table = dict_table_t::create(
 | 
						|
		{table_sym->name, strlen(table_sym->name)},
 | 
						|
		nullptr, n_cols, 0, flags, flags2);
 | 
						|
 | 
						|
	mem_heap_t* heap = pars_sym_tab_global->heap;
 | 
						|
	column = column_defs;
 | 
						|
 | 
						|
	while (column) {
 | 
						|
		dtype = dfield_get_type(que_node_get_val(column));
 | 
						|
 | 
						|
		dict_mem_table_add_col(table, heap,
 | 
						|
				       column->name, dtype->mtype,
 | 
						|
				       dtype->prtype, dtype->len);
 | 
						|
		column->resolved = TRUE;
 | 
						|
		column->token_type = SYM_COLUMN;
 | 
						|
 | 
						|
		column = static_cast<sym_node_t*>(que_node_get_next(column));
 | 
						|
	}
 | 
						|
 | 
						|
	dict_table_add_system_columns(table, heap);
 | 
						|
	node = tab_create_graph_create(table, heap);
 | 
						|
 | 
						|
	table_sym->resolved = TRUE;
 | 
						|
	table_sym->token_type = SYM_TABLE;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses an index creation operation.
 | 
						|
@return index create subgraph */
 | 
						|
ind_node_t*
 | 
						|
pars_create_index(
 | 
						|
/*==============*/
 | 
						|
	pars_res_word_t* unique_def,	/*!< in: not NULL if a unique index */
 | 
						|
	pars_res_word_t* clustered_def,	/*!< in: not NULL if a clustered index */
 | 
						|
	sym_node_t*	index_sym,	/*!< in: index name node in the symbol
 | 
						|
					table */
 | 
						|
	sym_node_t*	table_sym,	/*!< in: table name node in the symbol
 | 
						|
					table */
 | 
						|
	sym_node_t*	column_list)	/*!< in: list of column names */
 | 
						|
{
 | 
						|
	dict_index_t*	index;
 | 
						|
	sym_node_t*	column;
 | 
						|
	ind_node_t*	node;
 | 
						|
	ulint		n_fields;
 | 
						|
	ulint		ind_type;
 | 
						|
 | 
						|
	n_fields = que_node_list_get_len(column_list);
 | 
						|
 | 
						|
	ind_type = 0;
 | 
						|
 | 
						|
	if (unique_def) {
 | 
						|
		ind_type = ind_type | DICT_UNIQUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (clustered_def) {
 | 
						|
		ind_type = ind_type | DICT_CLUSTERED;
 | 
						|
	}
 | 
						|
 | 
						|
	index = dict_mem_index_create(NULL, index_sym->name,
 | 
						|
				      ind_type, n_fields);
 | 
						|
	column = column_list;
 | 
						|
 | 
						|
	while (column) {
 | 
						|
		dict_mem_index_add_field(index, column->name, 0);
 | 
						|
 | 
						|
		column->resolved = TRUE;
 | 
						|
		column->token_type = SYM_COLUMN;
 | 
						|
 | 
						|
		column = static_cast<sym_node_t*>(que_node_get_next(column));
 | 
						|
	}
 | 
						|
 | 
						|
	node = ind_create_graph_create(index, table_sym->name,
 | 
						|
				       pars_sym_tab_global->heap,
 | 
						|
				       FIL_ENCRYPTION_DEFAULT,
 | 
						|
				       FIL_DEFAULT_ENCRYPTION_KEY);
 | 
						|
 | 
						|
	table_sym->resolved = TRUE;
 | 
						|
	table_sym->token_type = SYM_TABLE;
 | 
						|
 | 
						|
	index_sym->resolved = TRUE;
 | 
						|
	index_sym->token_type = SYM_TABLE;
 | 
						|
 | 
						|
	return(node);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
Parses a procedure definition.
 | 
						|
@return query fork node */
 | 
						|
que_fork_t*
 | 
						|
pars_procedure_definition(
 | 
						|
/*======================*/
 | 
						|
	sym_node_t*	sym_node,	/*!< in: procedure id node in the symbol
 | 
						|
					table */
 | 
						|
	que_node_t*	stat_list)	/*!< in: statement list */
 | 
						|
{
 | 
						|
	proc_node_t*	node;
 | 
						|
	que_fork_t*	fork;
 | 
						|
	que_thr_t*	thr;
 | 
						|
	mem_heap_t*	heap;
 | 
						|
 | 
						|
	heap = pars_sym_tab_global->heap;
 | 
						|
 | 
						|
	fork = que_fork_create(heap);
 | 
						|
	fork->trx = NULL;
 | 
						|
 | 
						|
	thr = que_thr_create(fork, heap, NULL);
 | 
						|
 | 
						|
	node = static_cast<proc_node_t*>(
 | 
						|
		mem_heap_alloc(heap, sizeof(proc_node_t)));
 | 
						|
 | 
						|
	node->common.type = QUE_NODE_PROC;
 | 
						|
	node->common.parent = thr;
 | 
						|
 | 
						|
	sym_node->token_type = SYM_PROCEDURE_NAME;
 | 
						|
	sym_node->resolved = TRUE;
 | 
						|
 | 
						|
	node->proc_id = sym_node;
 | 
						|
	node->stat_list = stat_list;
 | 
						|
 | 
						|
	pars_set_parent_in_list(stat_list, node);
 | 
						|
 | 
						|
	node->sym_tab = pars_sym_tab_global;
 | 
						|
 | 
						|
	thr->child = node;
 | 
						|
 | 
						|
	pars_sym_tab_global->query_graph = fork;
 | 
						|
 | 
						|
	return(fork);
 | 
						|
}
 | 
						|
 | 
						|
/*************************************************************//**
 | 
						|
Retrieves characters to the lexical analyzer. */
 | 
						|
int
 | 
						|
pars_get_lex_chars(
 | 
						|
/*===============*/
 | 
						|
	char*	buf,		/*!< in/out: buffer where to copy */
 | 
						|
	size_t	max_size)	/*!< in: maximum number of characters which fit
 | 
						|
				in the buffer */
 | 
						|
{
 | 
						|
	size_t len = pars_sym_tab_global->string_len
 | 
						|
		- pars_sym_tab_global->next_char_pos;
 | 
						|
	if (len == 0) {
 | 
						|
		return(0);
 | 
						|
	}
 | 
						|
 | 
						|
	if (len > max_size) {
 | 
						|
		len = max_size;
 | 
						|
	}
 | 
						|
 | 
						|
	memcpy(buf, pars_sym_tab_global->sql_string
 | 
						|
	       + pars_sym_tab_global->next_char_pos, len);
 | 
						|
 | 
						|
	pars_sym_tab_global->next_char_pos += len;
 | 
						|
 | 
						|
	return static_cast<int>(len);
 | 
						|
}
 | 
						|
 | 
						|
/*************************************************************//**
 | 
						|
Called by yyparse on error. */
 | 
						|
void
 | 
						|
yyerror(
 | 
						|
/*====*/
 | 
						|
	const char*	s MY_ATTRIBUTE((unused)))
 | 
						|
				/*!< in: error message string */
 | 
						|
{
 | 
						|
	ut_ad(s);
 | 
						|
 | 
						|
	ib::fatal() << "PARSER: Syntax error in SQL string";
 | 
						|
}
 | 
						|
 | 
						|
/*************************************************************//**
 | 
						|
Parses an SQL string returning the query graph.
 | 
						|
@return own: the query graph */
 | 
						|
que_t*
 | 
						|
pars_sql(
 | 
						|
/*=====*/
 | 
						|
	pars_info_t*	info,	/*!< in: extra information, or NULL */
 | 
						|
	const char*	str)	/*!< in: SQL string */
 | 
						|
{
 | 
						|
	sym_node_t*	sym_node;
 | 
						|
	mem_heap_t*	heap;
 | 
						|
	que_t*		graph;
 | 
						|
 | 
						|
	ut_ad(str);
 | 
						|
 | 
						|
	heap = mem_heap_create(16000);
 | 
						|
 | 
						|
	/* Currently, the parser is not reentrant: */
 | 
						|
	ut_ad(dict_sys.locked());
 | 
						|
 | 
						|
	pars_sym_tab_global = sym_tab_create(heap);
 | 
						|
 | 
						|
	pars_sym_tab_global->string_len = strlen(str);
 | 
						|
	pars_sym_tab_global->sql_string = static_cast<char*>(
 | 
						|
		mem_heap_dup(heap, str, pars_sym_tab_global->string_len + 1));
 | 
						|
	pars_sym_tab_global->next_char_pos = 0;
 | 
						|
	pars_sym_tab_global->info = info;
 | 
						|
 | 
						|
	yyparse();
 | 
						|
 | 
						|
	sym_node = UT_LIST_GET_FIRST(pars_sym_tab_global->sym_list);
 | 
						|
 | 
						|
	while (sym_node) {
 | 
						|
		ut_a(sym_node->resolved);
 | 
						|
 | 
						|
		sym_node = UT_LIST_GET_NEXT(sym_list, sym_node);
 | 
						|
	}
 | 
						|
 | 
						|
	graph = pars_sym_tab_global->query_graph;
 | 
						|
 | 
						|
	graph->sym_tab = pars_sym_tab_global;
 | 
						|
	graph->info = info;
 | 
						|
 | 
						|
	pars_sym_tab_global = NULL;
 | 
						|
 | 
						|
	/* fprintf(stderr, "SQL graph size %lu\n", mem_heap_get_size(heap)); */
 | 
						|
 | 
						|
	return(graph);
 | 
						|
}
 | 
						|
 | 
						|
/** Completes a query graph by adding query thread and fork nodes
 | 
						|
above it and prepares the graph for running.
 | 
						|
@param[in]	node		root node for an incomplete query
 | 
						|
				graph, or NULL for dummy graph
 | 
						|
@param[in]	trx		transaction handle
 | 
						|
@param[in]	heap		memory heap from which allocated
 | 
						|
@param[in]	prebuilt	row prebuilt structure
 | 
						|
@return query thread node to run */
 | 
						|
que_thr_t*
 | 
						|
pars_complete_graph_for_exec(
 | 
						|
	que_node_t*	node,
 | 
						|
	trx_t*		trx,
 | 
						|
	mem_heap_t*	heap,
 | 
						|
	row_prebuilt_t*	prebuilt)
 | 
						|
{
 | 
						|
	que_fork_t*	fork;
 | 
						|
	que_thr_t*	thr;
 | 
						|
 | 
						|
	fork = que_fork_create(heap);
 | 
						|
	fork->trx = trx;
 | 
						|
 | 
						|
	thr = que_thr_create(fork, heap, prebuilt);
 | 
						|
 | 
						|
	thr->child = node;
 | 
						|
 | 
						|
	if (node) {
 | 
						|
		que_node_set_parent(node, thr);
 | 
						|
	}
 | 
						|
 | 
						|
	trx->graph = NULL;
 | 
						|
 | 
						|
	return(thr);
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************//**
 | 
						|
Create parser info struct.
 | 
						|
@return own: info struct */
 | 
						|
pars_info_t*
 | 
						|
pars_info_create(void)
 | 
						|
/*==================*/
 | 
						|
{
 | 
						|
	pars_info_t*	info;
 | 
						|
	mem_heap_t*	heap;
 | 
						|
 | 
						|
	heap = mem_heap_create(512);
 | 
						|
 | 
						|
	info = static_cast<pars_info_t*>(mem_heap_zalloc(heap, sizeof(*info)));
 | 
						|
 | 
						|
	info->heap = heap;
 | 
						|
 | 
						|
	return(info);
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************//**
 | 
						|
Add bound literal. */
 | 
						|
void
 | 
						|
pars_info_add_literal(
 | 
						|
/*==================*/
 | 
						|
	pars_info_t*	info,		/*!< in: info struct */
 | 
						|
	const char*	name,		/*!< in: name */
 | 
						|
	const void*	address,	/*!< in: address */
 | 
						|
	ulint		length,		/*!< in: length of data */
 | 
						|
	ulint		type,		/*!< in: type, e.g. DATA_FIXBINARY */
 | 
						|
	ulint		prtype)		/*!< in: precise type, e.g.
 | 
						|
					DATA_UNSIGNED */
 | 
						|
{
 | 
						|
	pars_bound_lit_t*	pbl;
 | 
						|
 | 
						|
	ut_ad(!pars_info_get_bound_lit(info, name));
 | 
						|
 | 
						|
	pbl = static_cast<pars_bound_lit_t*>(
 | 
						|
		mem_heap_alloc(info->heap, sizeof(*pbl)));
 | 
						|
 | 
						|
	pbl->name = name;
 | 
						|
 | 
						|
	pbl->address = address;
 | 
						|
	pbl->length = length;
 | 
						|
	pbl->type = type;
 | 
						|
	pbl->prtype = prtype;
 | 
						|
 | 
						|
	if (!info->bound_lits) {
 | 
						|
		ib_alloc_t*     heap_alloc;
 | 
						|
 | 
						|
		heap_alloc = ib_heap_allocator_create(info->heap);
 | 
						|
 | 
						|
		info->bound_lits = ib_vector_create(heap_alloc, sizeof(*pbl), 8);
 | 
						|
	}
 | 
						|
 | 
						|
	ib_vector_push(info->bound_lits, pbl);
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************//**
 | 
						|
Equivalent to pars_info_add_literal(info, name, str, strlen(str),
 | 
						|
DATA_VARCHAR, DATA_ENGLISH). */
 | 
						|
void
 | 
						|
pars_info_add_str_literal(
 | 
						|
/*======================*/
 | 
						|
	pars_info_t*	info,		/*!< in: info struct */
 | 
						|
	const char*	name,		/*!< in: name */
 | 
						|
	const char*	str)		/*!< in: string */
 | 
						|
{
 | 
						|
	pars_info_add_literal(info, name, str, strlen(str),
 | 
						|
			      DATA_VARCHAR, DATA_ENGLISH);
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
If the literal value already exists then it rebinds otherwise it
 | 
						|
creates a new entry.*/
 | 
						|
void
 | 
						|
pars_info_bind_literal(
 | 
						|
/*===================*/
 | 
						|
	pars_info_t*	info,		/* in: info struct */
 | 
						|
	const char*	name,		/* in: name */
 | 
						|
	const void*	address,	/* in: address */
 | 
						|
	ulint		length,		/* in: length of data */
 | 
						|
	ulint		type,		/* in: type, e.g. DATA_FIXBINARY */
 | 
						|
	ulint		prtype)		/* in: precise type, e.g. */
 | 
						|
{
 | 
						|
	pars_bound_lit_t*	pbl;
 | 
						|
 | 
						|
	pbl = pars_info_lookup_bound_lit(info, name);
 | 
						|
 | 
						|
	if (!pbl) {
 | 
						|
		pars_info_add_literal(
 | 
						|
			info, name, address, length, type, prtype);
 | 
						|
	} else {
 | 
						|
		pbl->address = address;
 | 
						|
		pbl->length = length;
 | 
						|
 | 
						|
		sym_tab_rebind_lit(pbl->node, address, length);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
If the literal value already exists then it rebinds otherwise it
 | 
						|
creates a new entry.*/
 | 
						|
void
 | 
						|
pars_info_bind_varchar_literal(
 | 
						|
/*===========================*/
 | 
						|
	pars_info_t*	info,		/*!< in: info struct */
 | 
						|
	const char*	name,		/*!< in: name */
 | 
						|
	const byte*	str,		/*!< in: string */
 | 
						|
	ulint		str_len)	/*!< in: string length */
 | 
						|
{
 | 
						|
	pars_bound_lit_t*	pbl;
 | 
						|
 | 
						|
	pbl = pars_info_lookup_bound_lit(info, name);
 | 
						|
 | 
						|
	if (!pbl) {
 | 
						|
		pars_info_add_literal(
 | 
						|
			info, name, str, str_len, DATA_VARCHAR, DATA_ENGLISH);
 | 
						|
	} else {
 | 
						|
 | 
						|
		pbl->address = str;
 | 
						|
		pbl->length = str_len;
 | 
						|
 | 
						|
		sym_tab_rebind_lit(pbl->node, str, str_len);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************//**
 | 
						|
Equivalent to:
 | 
						|
 | 
						|
char buf[4];
 | 
						|
mach_write_to_4(buf, val);
 | 
						|
pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
 | 
						|
 | 
						|
except that the buffer is dynamically allocated from the info struct's
 | 
						|
heap. */
 | 
						|
void
 | 
						|
pars_info_add_int4_literal(
 | 
						|
/*=======================*/
 | 
						|
	pars_info_t*	info,		/*!< in: info struct */
 | 
						|
	const char*	name,		/*!< in: name */
 | 
						|
	ulint		val)		/*!< in: value */
 | 
						|
{
 | 
						|
	byte*	buf = static_cast<byte*>(mem_heap_alloc(info->heap, 4));
 | 
						|
 | 
						|
	mach_write_to_4(buf, val);
 | 
						|
	pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
If the literal value already exists then it rebinds otherwise it
 | 
						|
creates a new entry. */
 | 
						|
void
 | 
						|
pars_info_bind_int4_literal(
 | 
						|
/*========================*/
 | 
						|
	pars_info_t*		info,   /* in: info struct */
 | 
						|
	const char*		name,   /* in: name */
 | 
						|
	const ib_uint32_t*	val)    /* in: value */
 | 
						|
{
 | 
						|
	pars_bound_lit_t*       pbl;
 | 
						|
 | 
						|
	pbl = pars_info_lookup_bound_lit(info, name);
 | 
						|
 | 
						|
	if (!pbl) {
 | 
						|
		pars_info_add_literal(info, name, val, 4, DATA_INT, 0);
 | 
						|
	} else {
 | 
						|
 | 
						|
		pbl->address = val;
 | 
						|
		pbl->length = sizeof(*val);
 | 
						|
 | 
						|
		sym_tab_rebind_lit(pbl->node, val, sizeof(*val));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
If the literal value already exists then it rebinds otherwise it
 | 
						|
creates a new entry. */
 | 
						|
void
 | 
						|
pars_info_bind_int8_literal(
 | 
						|
/*========================*/
 | 
						|
	pars_info_t*		info,	/* in: info struct */
 | 
						|
	const char*		name,	/* in: name */
 | 
						|
	const ib_uint64_t*	val)	/* in: value */
 | 
						|
{
 | 
						|
	pars_bound_lit_t*	pbl;
 | 
						|
 | 
						|
	pbl = pars_info_lookup_bound_lit(info, name);
 | 
						|
 | 
						|
	if (!pbl) {
 | 
						|
		pars_info_add_literal(
 | 
						|
			info, name, val, sizeof(*val), DATA_INT, 0);
 | 
						|
	} else {
 | 
						|
 | 
						|
		pbl->address = val;
 | 
						|
		pbl->length = sizeof(*val);
 | 
						|
 | 
						|
		sym_tab_rebind_lit(pbl->node, val, sizeof(*val));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************//**
 | 
						|
Equivalent to:
 | 
						|
 | 
						|
char buf[8];
 | 
						|
mach_write_to_8(buf, val);
 | 
						|
pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0);
 | 
						|
 | 
						|
except that the buffer is dynamically allocated from the info struct's
 | 
						|
heap. */
 | 
						|
void
 | 
						|
pars_info_add_ull_literal(
 | 
						|
/*======================*/
 | 
						|
	pars_info_t*	info,		/*!< in: info struct */
 | 
						|
	const char*	name,		/*!< in: name */
 | 
						|
	ib_uint64_t	val)		/*!< in: value */
 | 
						|
{
 | 
						|
	byte*	buf = static_cast<byte*>(mem_heap_alloc(info->heap, 8));
 | 
						|
 | 
						|
	mach_write_to_8(buf, val);
 | 
						|
 | 
						|
	pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0);
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************//**
 | 
						|
If the literal value already exists then it rebinds otherwise it
 | 
						|
creates a new entry. */
 | 
						|
void
 | 
						|
pars_info_bind_ull_literal(
 | 
						|
/*=======================*/
 | 
						|
	pars_info_t*		info,		/*!< in: info struct */
 | 
						|
	const char*		name,		/*!< in: name */
 | 
						|
	const ib_uint64_t*	val)		/*!< in: value */
 | 
						|
{
 | 
						|
	pars_bound_lit_t*	pbl;
 | 
						|
 | 
						|
	pbl = pars_info_lookup_bound_lit(info, name);
 | 
						|
 | 
						|
	if (!pbl) {
 | 
						|
		pars_info_add_literal(
 | 
						|
			info, name, val, sizeof(*val), DATA_FIXBINARY, 0);
 | 
						|
	} else {
 | 
						|
 | 
						|
		pbl->address = val;
 | 
						|
		pbl->length = sizeof(*val);
 | 
						|
 | 
						|
		sym_tab_rebind_lit(pbl->node, val, sizeof(*val));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************//**
 | 
						|
Add user function. */
 | 
						|
void
 | 
						|
pars_info_bind_function(
 | 
						|
/*====================*/
 | 
						|
	pars_info_t*		info,	/*!< in: info struct */
 | 
						|
	const char*		name,	/*!< in: function name */
 | 
						|
	pars_user_func_cb_t	func,	/*!< in: function address */
 | 
						|
	void*			arg)	/*!< in: user-supplied argument */
 | 
						|
{
 | 
						|
	pars_user_func_t*	puf;
 | 
						|
 | 
						|
	puf = pars_info_lookup_user_func(info, name);
 | 
						|
 | 
						|
	if (!puf) {
 | 
						|
		if (!info->funcs) {
 | 
						|
			ib_alloc_t*     heap_alloc;
 | 
						|
 | 
						|
			heap_alloc = ib_heap_allocator_create(info->heap);
 | 
						|
 | 
						|
			info->funcs = ib_vector_create(
 | 
						|
				heap_alloc, sizeof(*puf), 8);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Create a "new" element */
 | 
						|
		puf = static_cast<pars_user_func_t*>(
 | 
						|
			ib_vector_push(info->funcs, NULL));
 | 
						|
		puf->name = name;
 | 
						|
	}
 | 
						|
 | 
						|
	puf->arg = arg;
 | 
						|
	puf->func = func;
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
Add bound id. */
 | 
						|
void
 | 
						|
pars_info_bind_id(
 | 
						|
/*==============*/
 | 
						|
	pars_info_t*	info,		/*!< in: info struct */
 | 
						|
	const char*	name,		/*!< in: name */
 | 
						|
	const char*	id)		/*!< in: id */
 | 
						|
{
 | 
						|
	pars_bound_id_t*	bid;
 | 
						|
 | 
						|
	bid = pars_info_lookup_bound_id(info, name);
 | 
						|
 | 
						|
	if (!bid) {
 | 
						|
 | 
						|
		if (!info->bound_ids) {
 | 
						|
			ib_alloc_t*     heap_alloc;
 | 
						|
 | 
						|
			heap_alloc = ib_heap_allocator_create(info->heap);
 | 
						|
 | 
						|
			info->bound_ids = ib_vector_create(
 | 
						|
				heap_alloc, sizeof(*bid), 8);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Create a "new" element */
 | 
						|
		bid = static_cast<pars_bound_id_t*>(
 | 
						|
			ib_vector_push(info->bound_ids, NULL));
 | 
						|
 | 
						|
		bid->name = name;
 | 
						|
	}
 | 
						|
 | 
						|
	bid->id = id;
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************
 | 
						|
Get bound identifier with the given name.*/
 | 
						|
pars_bound_id_t*
 | 
						|
pars_info_get_bound_id(
 | 
						|
/*===================*/
 | 
						|
					/* out: bound id, or NULL if not
 | 
						|
					found */
 | 
						|
	pars_info_t*		info,	/* in: info struct */
 | 
						|
	const char*		name)	/* in: bound id name to find */
 | 
						|
{
 | 
						|
	return(pars_info_lookup_bound_id(info, name));
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************//**
 | 
						|
Get bound literal with the given name.
 | 
						|
@return bound literal, or NULL if not found */
 | 
						|
pars_bound_lit_t*
 | 
						|
pars_info_get_bound_lit(
 | 
						|
/*====================*/
 | 
						|
	pars_info_t*		info,	/*!< in: info struct */
 | 
						|
	const char*		name)	/*!< in: bound literal name to find */
 | 
						|
{
 | 
						|
	return(pars_info_lookup_bound_lit(info, name));
 | 
						|
}
 |