/******************************************************
Select

(c) 1997 Innobase Oy

Created 12/19/1997 Heikki Tuuri
*******************************************************/

#ifndef row0sel_h
#define row0sel_h

#include "univ.i"
#include "data0data.h"
#include "que0types.h"
#include "dict0types.h"
#include "trx0types.h"
#include "row0types.h"
#include "que0types.h"
#include "pars0sym.h"
#include "btr0pcur.h"
#include "read0read.h"
#include "row0mysql.h"

/*************************************************************************
Creates a select node struct. */

sel_node_t*
sel_node_create(
/*============*/
				/* out, own: select node struct */
	mem_heap_t*	heap);	/* in: memory heap where created */
/*************************************************************************
Frees the memory private to a select node when a query graph is freed,
does not free the heap where the node was originally created. */

void
sel_node_free_private(
/*==================*/
	sel_node_t*	node);	/* in: select node struct */
/*************************************************************************
Frees a prefetch buffer for a column, including the dynamically allocated
memory for data stored there. */

void
sel_col_prefetch_buf_free(
/*======================*/
	sel_buf_t*	prefetch_buf);	/* in, own: prefetch buffer */
/*************************************************************************
Gets the plan node for the nth table in a join. */
UNIV_INLINE
plan_t*
sel_node_get_nth_plan(
/*==================*/
	sel_node_t*	node,
	ulint		i);
/**************************************************************************
Performs a select step. This is a high-level function used in SQL execution
graphs. */

que_thr_t*
row_sel_step(
/*=========*/
				/* out: query thread to run next or NULL */
	que_thr_t*	thr);	/* in: query thread */
/**************************************************************************
Performs an execution step of an open or close cursor statement node. */
UNIV_INLINE
que_thr_t*
open_step(
/*======*/
				/* out: query thread to run next or NULL */
	que_thr_t*	thr);	/* in: query thread */
/**************************************************************************
Performs a fetch for a cursor. */

que_thr_t*
fetch_step(
/*=======*/
				/* out: query thread to run next or NULL */
	que_thr_t*	thr);	/* in: query thread */
/***************************************************************
Prints a row in a select result. */

que_thr_t*
row_printf_step(
/*============*/
				/* out: query thread to run next or NULL */
	que_thr_t*	thr);	/* in: query thread */
/********************************************************************
Converts a key value stored in MySQL format to an Innobase dtuple. The last
field of the key value may be just a prefix of a fixed length field: hence
the parameter key_len. But currently we do not allow search keys where the
last field is only a prefix of the full key field len and print a warning if
such appears. */

void
row_sel_convert_mysql_key_to_innobase(
/*==================================*/
	dtuple_t*	tuple,		/* in: tuple where to build;
					NOTE: we assume that the type info
					in the tuple is already according
					to index! */
	byte*		buf,		/* in: buffer to use in field
					conversions */
	ulint		buf_len,	/* in: buffer length */
	dict_index_t*	index,		/* in: index of the key value */
	byte*		key_ptr,	/* in: MySQL key value */
	ulint		key_len);	/* in: MySQL key value length */
/************************************************************************
Searches for rows in the database. This is used in the interface to
MySQL. This function opens a cursor, and also implements fetch next
and fetch prev. NOTE that if we do a search with a full key value
from a unique index (ROW_SEL_EXACT), then we will not store the cursor
position and fetch next or fetch prev must not be tried to the cursor! */

ulint
row_search_for_mysql(
/*=================*/
					/* out: DB_SUCCESS,
					DB_RECORD_NOT_FOUND, 
					DB_END_OF_INDEX, or DB_DEADLOCK */
	byte*		buf,		/* in/out: buffer for the fetched
					row in the MySQL format */
	ulint		mode,		/* in: search mode PAGE_CUR_L, ... */
	row_prebuilt_t*	prebuilt,	/* in: prebuilt struct for the
					table handle; this contains the info
					of search_tuple, index; if search
					tuple contains 0 fields then we
					position the cursor at the start or
					the end of the index, depending on
					'mode' */
	ulint		match_mode,	/* in: 0 or ROW_SEL_EXACT or
					ROW_SEL_EXACT_PREFIX */ 
	ulint		direction);	/* in: 0 or ROW_SEL_NEXT or
					ROW_SEL_PREV; NOTE: if this is != 0,
					then prebuilt must have a pcur
					with stored position! In opening of a
					cursor 'direction' should be 0. */
/***********************************************************************
Checks if MySQL at the moment is allowed for this table to retrieve a
consistent read result, or store it to the query cache. */

ibool
row_search_check_if_query_cache_permitted(
/*======================================*/
				/* out: TRUE if storing or retrieving from
				the query cache is permitted */
	trx_t*	trx,		/* in: transaction object */
	char*	norm_name);	/* in: concatenation of database name, '/'
				char, table name */


/* A structure for caching column values for prefetched rows */
struct sel_buf_struct{
	byte*		data;	/* data, or NULL; if not NULL, this field
				has allocated memory which must be explicitly
				freed; can be != NULL even when len is
				UNIV_SQL_NULL */
	ulint		len;	/* data length or UNIV_SQL_NULL */
	ulint		val_buf_size;
				/* size of memory buffer allocated for data:
				this can be more than len; this is defined
				when data != NULL */
};

struct plan_struct{
	dict_table_t*	table;		/* table struct in the dictionary
					cache */
	dict_index_t*	index;		/* table index used in the search */
	btr_pcur_t	pcur;		/* persistent cursor used to search
					the index */
	ibool		asc;		/* TRUE if cursor traveling upwards */
	ibool		pcur_is_open;	/* TRUE if pcur has been positioned
					and we can try to fetch new rows */
	ibool		cursor_at_end;	/* TRUE if the cursor is open but
					we know that there are no more
					qualifying rows left to retrieve from
					the index tree; NOTE though, that
					there may still be unprocessed rows in
					the prefetch stack; always FALSE when
					pcur_is_open is FALSE */
	ibool		stored_cursor_rec_processed;
					/* TRUE if the pcur position has been
					stored and the record it is positioned
					on has already been processed */
	que_node_t**	tuple_exps;	/* array of expressions which are used
					to calculate the field values in the
					search tuple: there is one expression
					for each field in the search tuple */
	dtuple_t*	tuple;		/* search tuple */
	ulint		mode;		/* search mode: PAGE_CUR_G, ... */
	ulint		n_exact_match;	/* number of first fields in the search
					tuple which must be exactly matched */
	ibool		unique_search;	/* TRUE if we are searching an
					index record with a unique key */
	ulint		n_rows_fetched;	/* number of rows fetched using pcur
					after it was opened */
	ulint		n_rows_prefetched;/* number of prefetched rows cached
					for fetch: fetching several rows in
					the same mtr saves CPU time */
	ulint		first_prefetched;/* index of the first cached row in
					select buffer arrays for each column */
	ibool		no_prefetch;	/* no prefetch for this table */
	ibool		mixed_index;	/* TRUE if index is a clustered index
					in a mixed cluster */
	sym_node_list_t	columns;	/* symbol table nodes for the columns
					to retrieve from the table */
	UT_LIST_BASE_NODE_T(func_node_t)
			end_conds;	/* conditions which determine the
					fetch limit of the index segment we
					have to look at: when one of these
					fails, the result set has been
					exhausted for the cursor in this
					index; these conditions are normalized
					so that in a comparison the column
					for this table is the first argument */
	UT_LIST_BASE_NODE_T(func_node_t)
			other_conds;	/* the rest of search conditions we can
					test at this table in a join */
	ibool		must_get_clust;	/* TRUE if index is a non-clustered
					index and we must also fetch the
					clustered index record; this is the
					case if the non-clustered record does
					not contain all the needed columns, or
					if this is a single-table explicit
					cursor, or a searched update or
					delete */
	ulint*		clust_map;	/* map telling how clust_ref is built
					from the fields of a non-clustered
					record */
	dtuple_t*	clust_ref;	/* the reference to the clustered
					index entry is built here if index is
					a non-clustered index */
	btr_pcur_t	clust_pcur;	/* if index is non-clustered, we use
					this pcur to search the clustered
					index */
	mem_heap_t*	old_vers_heap;	/* memory heap used in building an old
					version of a row, or NULL */	
};	

struct sel_node_struct{
	que_common_t	common;		/* node type: QUE_NODE_SELECT */
	ulint		state;		/* node state */
	que_node_t*	select_list;	/* select list */
	sym_node_t*	into_list;	/* variables list or NULL */
	sym_node_t*	table_list;	/* table list */
	ibool		asc;		/* TRUE if the rows should be fetched
					in an ascending order */
	ibool		set_x_locks;	/* TRUE if the cursor is for update or
					delete, which means that a row x-lock
					should be placed on the cursor row */
	ibool		select_will_do_update;
					/* TRUE if the select is for a searched
					update which can be performed in-place:
					in this case the select will take care
					of the update */
	ulint		latch_mode;	/* BTR_SEARCH_LEAF, or BTR_MODIFY_LEAF
					if select_will_do_update is TRUE */
	ulint		row_lock_mode;	/* LOCK_X or LOCK_S */
	ulint		n_tables;	/* number of tables */
	ulint		fetch_table;	/* number of the next table to access
					in the join */
	plan_t*		plans;		/* array of n_tables many plan nodes
					containing the search plan and the
					search data structures */
	que_node_t*	search_cond;	/* search condition */
	read_view_t*	read_view;	/* if the query is a non-locking
					consistent read, its read view is
					placed here, otherwise NULL */
	ibool		consistent_read;/* TRUE if the select is a consistent,
					non-locking read */
	order_node_t*	order_by;	/* order by column definition, or
					NULL */
	ibool		is_aggregate;	/* TRUE if the select list consists of
					aggregate functions */
	ibool		aggregate_already_fetched;
					/* TRUE if the aggregate row has
					already been fetched for the current
					cursor */
	ibool		can_get_updated;/* this is TRUE if the select is in a
					single-table explicit cursor which can
					get updated within the stored procedure,
					or in a searched update or delete;
					NOTE that to determine of an explicit
					cursor if it can get updated, the
					parser checks from a stored procedure
					if it contains positioned update or
					delete statements */
	sym_node_t*	explicit_cursor;/* not NULL if an explicit cursor */
	UT_LIST_BASE_NODE_T(sym_node_t)
			copy_variables; /* variables whose values we have to
					copy when an explicit cursor is opened,
					so that they do not change between
					fetches */
};
	
/* Select node states */
#define	SEL_NODE_CLOSED		0	/* it is a declared cursor which is not
					currently open */
#define SEL_NODE_OPEN		1	/* intention locks not yet set on
					tables */
#define SEL_NODE_FETCH		2	/* intention locks have been set */
#define SEL_NODE_NO_MORE_ROWS	3	/* cursor has reached the result set
					end */

/* Fetch statement node */
struct fetch_node_struct{
	que_common_t	common;		/* type: QUE_NODE_FETCH */
	sel_node_t*	cursor_def;	/* cursor definition */
	sym_node_t*	into_list;	/* variables to set */
};

/* Open or close cursor statement node */
struct open_node_struct{
	que_common_t	common;		/* type: QUE_NODE_OPEN */
	ulint		op_type;	/* ROW_SEL_OPEN_CURSOR or
					ROW_SEL_CLOSE_CURSOR */
	sel_node_t*	cursor_def;	/* cursor definition */
};

/* Row printf statement node */
struct row_printf_node_struct{
	que_common_t	common;		/* type: QUE_NODE_ROW_PRINTF */
	sel_node_t*	sel_node;	/* select */
};

#define ROW_SEL_OPEN_CURSOR	0
#define ROW_SEL_CLOSE_CURSOR	1

/* Flags for the MySQL interface */
#define ROW_SEL_NEXT		1
#define ROW_SEL_PREV		2

#define ROW_SEL_EXACT		1	/* search using a complete key value */
#define ROW_SEL_EXACT_PREFIX 	2	/* search using a key prefix which
					must match to rows: the prefix may
					contain an incomplete field (the
					last field in prefix may be just
					a prefix of a fixed length column) */

#ifndef UNIV_NONINL
#include "row0sel.ic"
#endif

#endif 
