/* File:			statement.hPD
 *
 * Description:		See "statement.c"
 *
 * Comments:		See "notice.txt" for copyright and license information.
 *
 */

#ifndef __STATEMENT_H__
#define __STATEMENT_H__

#include "psqlodbc.h"
#include <time.h>

#include "pgtypes.h"
#include "bind.h"
#include "descriptor.h"
#include "tuple.h"

#if defined (POSIX_MULTITHREAD_SUPPORT)
#include <pthread.h>
#endif

typedef enum
{
	STMT_ALLOCATED,				/* The statement handle is allocated, but
								 * not used so far */
	STMT_READY,					/* the statement is waiting to be executed */
	STMT_DESCRIBED,				/* ODBC states that it is legal to call
								 * e.g. SQLDescribeCol before a call to
								 * SQLExecute, but after SQLPrepare. To
								 * get all the necessary information in
								 * such a case, we parse the query _before_
								 * the actual call to SQLExecute, and the
								 * result set contains only column information,
								 * but no actual data. */
	STMT_FINISHED,				/* statement execution has finished */
	STMT_EXECUTING				/* statement execution is still going on */
} STMT_Status;
/*
 *		ERROR status code
 *
 *		The code for warnings must be minus
 *		and  LOWEST_STMT_ERROR must be set to
 *		the least code number.
 *		The code for STMT_OK is 0 and error
 *		codes follow after it.
 */
enum {
	LOWEST_STMT_ERROR		=		(-6)
	/* minus values mean warning returns */
	,STMT_ERROR_IN_ROW		=		(-6)
	,STMT_OPTION_VALUE_CHANGED	=		(-5)
	,STMT_ROW_VERSION_CHANGED	=		(-4)
	,STMT_POS_BEFORE_RECORDSET	=		(-3)
	,STMT_TRUNCATED			=		(-2)
	,STMT_INFO_ONLY			=		(-1)
				/* not an error message,
				 * just a notification
				 * to be returned by
				 * SQLError
				 */
	,STMT_OK			=		0
	,STMT_EXEC_ERROR
	,STMT_STATUS_ERROR
	,STMT_SEQUENCE_ERROR
	,STMT_NO_MEMORY_ERROR
	,STMT_COLNUM_ERROR
	,STMT_NO_STMTSTRING
	,STMT_ERROR_TAKEN_FROM_BACKEND
	,STMT_INTERNAL_ERROR
	,STMT_STILL_EXECUTING
	,STMT_NOT_IMPLEMENTED_ERROR
	,STMT_BAD_PARAMETER_NUMBER_ERROR
	,STMT_OPTION_OUT_OF_RANGE_ERROR
	,STMT_INVALID_COLUMN_NUMBER_ERROR
	,STMT_RESTRICTED_DATA_TYPE_ERROR
	,STMT_INVALID_CURSOR_STATE_ERROR
	,STMT_CREATE_TABLE_ERROR
	,STMT_NO_CURSOR_NAME
	,STMT_INVALID_CURSOR_NAME
	,STMT_INVALID_ARGUMENT_NO
	,STMT_ROW_OUT_OF_RANGE
	,STMT_OPERATION_CANCELLED
	,STMT_INVALID_CURSOR_POSITION
	,STMT_VALUE_OUT_OF_RANGE
	,STMT_OPERATION_INVALID
	,STMT_PROGRAM_TYPE_OUT_OF_RANGE
	,STMT_BAD_ERROR
	,STMT_INVALID_OPTION_IDENTIFIER
	,STMT_RETURN_NULL_WITHOUT_INDICATOR
	,STMT_INVALID_DESCRIPTOR_IDENTIFIER
	,STMT_OPTION_NOT_FOR_THE_DRIVER
	,STMT_FETCH_OUT_OF_RANGE
	,STMT_COUNT_FIELD_INCORRECT
	,STMT_INVALID_NULL_ARG
	,STMT_NO_RESPONSE
	,STMT_COMMUNICATION_ERROR
	,STMT_STRING_CONVERSION_ERROR
};

/* statement types */
enum
{
	STMT_TYPE_UNKNOWN = -2
	,STMT_TYPE_OTHER = -1
	,STMT_TYPE_SELECT = 0
	,STMT_TYPE_WITH
	,STMT_TYPE_PROCCALL
	,STMT_TYPE_TRANSACTION
	,STMT_TYPE_DECLARE
	,STMT_TYPE_FETCH
	,STMT_TYPE_CLOSE
	,STMT_TYPE_INSERT
	,STMT_TYPE_UPDATE
	,STMT_TYPE_DELETE
	,STMT_TYPE_CREATE
	,STMT_TYPE_ALTER
	,STMT_TYPE_DROP
	,STMT_TYPE_GRANT
	,STMT_TYPE_REVOKE
	,STMT_TYPE_LOCK
	,STMT_TYPE_PREPARE
	,STMT_TYPE_EXECUTE
	,STMT_TYPE_DEALLOCATE
	,STMT_TYPE_ANALYZE
	,STMT_TYPE_NOTIFY
	,STMT_TYPE_EXPLAIN
	,STMT_TYPE_SET
	,STMT_TYPE_RESET
	,STMT_TYPE_MOVE
	,STMT_TYPE_COPY
	,STMT_TYPE_START
	,STMT_TYPE_SPECIAL
};

#define STMT_UPDATE(stmt)	((stmt)->statement_type > STMT_TYPE_PROCCALL)


/*	Parsing status */
enum
{
	STMT_PARSE_NONE = 0
	,STMT_PARSE_COMPLETE	/* the driver parsed the statement */
	,STMT_PARSE_INCOMPLETE
	,STMT_PARSE_FATAL
	,STMT_PARSE_MASK = 3L
	,STMT_PARSED_OIDS = (1L << 2)
	,STMT_FOUND_KEY = (1L << 3)
	,STMT_HAS_ROW_DESCRIPTION = (1L << 4) /* already got the col info */
	,STMT_REFLECTED_ROW_DESCRIPTION = (1L << 5)
};

/*	transition status */
enum
{
	STMT_TRANSITION_UNALLOCATED = 0
	,STMT_TRANSITION_ALLOCATED = 1
	,STMT_TRANSITION_FETCH_SCROLL = 6
	,STMT_TRANSITION_EXTENDED_FETCH = 7
};

/*	Result style */
enum
{
	STMT_FETCH_NONE = 0,
	STMT_FETCH_NORMAL,
	STMT_FETCH_EXTENDED
};

#define	PG_NUM_NORMAL_KEYS	2

typedef	RETCODE	(*NeedDataCallfunc)(RETCODE, void *);
typedef	struct
{
	NeedDataCallfunc	func;
	void			*data;
}	NeedDataCallback;


/*
 * ProcessedStmt represents a fragment of the original SQL query, after
 * converting ? markers to $n style, processing ODBC escapes, and splitting
 * a multi-statement into individual statements. Each individual statement
 * is represented by one ProcessedStmt struct.
 */
struct ProcessedStmt
{
	struct ProcessedStmt *next;
	char	   *query;
	int			num_params;		/* number of parameter markers in this,
								 * fragment or -1 if not known */
};
typedef struct ProcessedStmt ProcessedStmt;

/********	Statement Handle	***********/
struct StatementClass_
{
	ConnectionClass *hdbc;		/* pointer to ConnectionClass this
								 * statement belongs to */
	QResultClass *result;		/* result of the current statement */
	QResultClass *curres;		/* the current result in the chain */
	HSTMT	   *phstmt;
	StatementOptions options;
	StatementOptions options_orig;
	/* attached descriptor handles */
	DescriptorClass	*ard;
	DescriptorClass	*apd;
	DescriptorClass	*ird;
	DescriptorClass	*ipd;
	/* implicit descriptor handles */
	DescriptorClass	ardi;
	DescriptorClass	irdi;
	DescriptorClass apdi;
	DescriptorClass ipdi;

	STMT_Status status;
	char	   *__error_message;
	int			__error_number;
	PG_ErrorInfo	*pgerror;

	SQLLEN		currTuple;	/* current absolute row number (GetData,
						 * SetPos, SQLFetch) */
	GetDataInfo	gdata_info;
	SQLLEN		save_rowset_size;	/* saved rowset size in case of
							 * change/FETCH_NEXT */
	SQLLEN		rowset_start;	/* start of rowset (an absolute row
								 * number) */
	SQLSETPOSIROW	bind_row;	/* current offset for Multiple row/column
						 * binding */
	Int2		current_col;	/* current column for GetData -- used to
						 * handle multiple calls */
	SQLLEN		last_fetch_count;	/* number of rows retrieved in
						 * last fetch/extended fetch */
	int		lobj_fd;		/* fd of the current large object */

	char	   *statement;		/* if non--null pointer to the SQL
					 * statement that has been executed */
	/*
	 * processed_statements is the SQL after splitting multi-statement into
	 * parts, and replacing ? markers with $n style markers, or injecting the
	 * values in UseServerSidePrepare=0 mode.
	 */
	ProcessedStmt *processed_statements;

	TABLE_INFO	**ti;
	Int2		ntab;
	Int2		num_key_fields;
	Int2		statement_type; /* According to the defines above */
	Int2		num_params;
	Int2		data_at_exec; /* Number of params needing SQLPutData */
	Int2		current_exec_param;	/* The current parameter for
						 * SQLPutData */
	UDWORD		iflag;		/* PGAPI_AllocStmt parameter */
	PutDataInfo	pdata_info;
	po_ind_t	parse_status;
	po_ind_t	proc_return;
	po_ind_t	put_data;	/* Has SQLPutData been called ? */
	po_ind_t	catalog_result;	/* Is this a result of catalog function ? */
	po_ind_t	prepare;	/* is this a prepared statement ? */
	po_ind_t	prepared;	/* is this statement already
					 * prepared at the server ? */
	po_ind_t	external;	/* Allocated via SQLAllocHandle() */
	po_ind_t	transition_status;	/* Transition status */
	po_ind_t	multi_statement; /* -1:unknown 0:single 1:multi */
	po_ind_t	rb_or_tc;	/* rollback on error */
	po_ind_t	discard_output_params;	 /* discard output parameters on parse stage */
	po_ind_t	cancel_info;	/* cancel information */
	po_ind_t	ref_CC_error;	/* refer to CC_error ? */
//	po_ind_t	lock_CC_for_rb;	/* lock CC for statement rollback ? */
	po_ind_t	join_info;	/* have joins ? */
	po_ind_t	parse_method;	/* parse_statement is forced or ? */
	po_ind_t	curr_param_result; /* current param result is set ? */
	pgNAME		cursor_name;
	char		*plan_name;

	char		*stmt_with_params;	/* statement after parameter
							 * substitution */
	SQLLEN		exec_start_row;
	SQLLEN		exec_end_row;
	SQLLEN		exec_current_row;

	unsigned char	miscinfo;
	unsigned char	execinfo;
	po_ind_t	updatable;
	SQLLEN		diag_row_count;
	char		*load_statement; /* to (re)load updatable individual rows */
	ssize_t		from_pos;
	ssize_t		load_from_pos;
	ssize_t		where_pos;
	SQLLEN		last_fetch_count_include_ommitted;
	time_t		stmt_time;
	struct tm	localtime;
	/* SQL_NEED_DATA Callback list */
	StatementClass	*execute_delegate;
	StatementClass	*execute_parent;
	UInt2		allocated_callbacks;
	UInt2		num_callbacks;
	NeedDataCallback	*callbacks;
#if defined(WIN_MULTITHREAD_SUPPORT)
	CRITICAL_SECTION	cs;
#elif defined(POSIX_THREADMUTEX_SUPPORT)
	pthread_mutex_t		cs;
#endif /* WIN_MULTITHREAD_SUPPORT */

};

#define SC_get_conn(a)	  ((a)->hdbc)
void SC_init_Result(StatementClass *self);
void SC_set_Result(StatementClass *self, QResultClass *res);
#define SC_get_Result(a)  ((a)->result)
#define SC_set_Curres(a, b)  ((a)->curres = b)
#define SC_get_Curres(a)  ((a)->curres)
#define SC_get_ARD(a)  ((a)->ard)
#define SC_get_APD(a)  ((a)->apd)
#define SC_get_IRD(a)  ((a)->ird)
#define SC_get_IPD(a)  ((a)->ipd)
#define SC_get_ARDF(a)  (&(SC_get_ARD(a)->ardf))
#define SC_get_APDF(a)  (&(SC_get_APD(a)->apdf))
#define SC_get_IRDF(a)  (&(SC_get_IRD(a)->irdf))
#define SC_get_IPDF(a)  (&(SC_get_IPD(a)->ipdf))
#define SC_get_ARDi(a)  (&((a)->ardi))
#define SC_get_APDi(a)  (&((a)->apdi))
#define SC_get_IRDi(a)  (&((a)->irdi))
#define SC_get_IPDi(a)  (&((a)->ipdi))
#define SC_get_GDTI(a)  (&((a)->gdata_info))
#define SC_get_PDTI(a)  (&((a)->pdata_info))

#define	SC_get_errornumber(a) ((a)->__error_number)
#define	SC_set_errornumber(a, n) ((a)->__error_number = n)
#define	SC_get_errormsg(a) ((a)->__error_message)
#define	SC_is_prepare_statement(a) (0 != ((a)->prepare & PREPARE_STATEMENT))
#define	SC_get_prepare_method(a) ((a)->prepare & (~PREPARE_STATEMENT))

#define	SC_parsed_status(a)	((a)->parse_status & STMT_PARSE_MASK)
#define	SC_set_parse_status(a, s) ((a)->parse_status |= s)
#define	SC_update_not_ready(a)	(SC_parsed_status(a) == STMT_PARSE_NONE || 0 == ((a)->parse_status & STMT_PARSED_OIDS))
#define	SC_update_ready(a)	(SC_parsed_status(a) == STMT_PARSE_COMPLETE && 0 != ((a)->parse_status & STMT_FOUND_KEY) && (a)->updatable)
#define	SC_set_checked_hasoids(a, b)	((a)->parse_status |= (STMT_PARSED_OIDS | (b ? STMT_FOUND_KEY : 0)))
#define	SC_checked_hasoids(a)	(0 != ((a)->parse_status & STMT_PARSED_OIDS))
#define	SC_set_delegate(p, c) ((p)->execute_delegate = c, (c)->execute_parent = p)

#define	SC_is_updatable(s)	(0 < ((s)->updatable))
#define	SC_reset_updatable(s)	((s)->updatable = -1)
#define	SC_set_updatable(s, b)	((s)->updatable = (b))
#define	SC_clear_parse_method(s)	((s)->parse_method = 0)
#define	SC_is_parse_forced(s)	(0 != ((s)->parse_method & 1L))
#define	SC_set_parse_forced(s)	((s)->parse_method |= 1L)

#define	SC_cursor_is_valid(s)	(NAME_IS_VALID((s)->cursor_name))
#define	SC_cursor_name(s)	(SAFE_NAME((s)->cursor_name))

void	SC_reset_delegate(RETCODE, StatementClass *);
StatementClass *SC_get_ancestor(StatementClass *);

#define	SC_is_lower_case(a, b) ((a)->options.metadata_id || (b)->connInfo.lower_case_identifier)

#define	SC_MALLOC_return_with_error(t, tp, s, a, m, r) \
do { \
	if (t = (tp *) malloc(s), NULL == t) \
	{ \
		SC_set_error(a, STMT_NO_MEMORY_ERROR, m, "SC_MALLOC"); \
		return r; \
	} \
} while (0)
#define	SC_MALLOC_gexit_with_error(t, tp, s, a, m, r) \
do { \
	if (t = (tp *) malloc(s), NULL == t) \
	{ \
		SC_set_error(a, STMT_NO_MEMORY_ERROR, m, "SC_MALLOC"); \
		r; \
		goto cleanup; \
	} \
} while (0)
#define	SC_REALLOC_return_with_error(t, tp, s, a, m, r) \
do { \
	tp *tmp; \
	if (tmp = (tp *) realloc(t, s), NULL == tmp) \
	{ \
		SC_set_error(a, STMT_NO_MEMORY_ERROR, m, "SC_REALLOC"); \
		return r; \
	} \
	t = tmp; \
} while (0)
#define	SC_REALLOC_gexit_with_error(t, tp, s, a, m, r) \
do { \
	tp *tmp; \
	if (tmp = (tp *) realloc(t, s), NULL == tmp) \
	{ \
		SC_set_error(a, STMT_NO_MEMORY_ERROR, m, __FUNCTION__); \
		r; \
		goto cleanup; \
	} \
	t = tmp; \
} while (0)

/*	options for SC_free_params() */
#define STMT_FREE_PARAMS_ALL				0
#define STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY	1

/*	prepare state */
enum {
	  NON_PREPARE_STATEMENT = 0
	, PREPARE_STATEMENT = 1
	, PREPARE_BY_THE_DRIVER = (1L << 1)
	, NAMED_PARSE_REQUEST = (3L << 1)
	, PARSE_TO_EXEC_ONCE = (4L << 1)
	, PARSE_REQ_FOR_INFO = (5L << 1)
};

/*	prepared state */
enum
{
	NOT_YET_PREPARED = 0
	,PREPARING_PERMANENTLY
	,PREPARING_TEMPORARILY
	,PREPARED_PERMANENTLY
	,PREPARED_TEMPORARILY /* Is currently, or once was, prepared as unnamed
						   * statement. You must check
						   * connection->unnamed_prepared_stmt to see if it
						   * still is */
};

/*	misc info */
#define SC_set_fetchcursor(a)	((a)->miscinfo |= (1L << 1))
#define SC_no_fetchcursor(a)	((a)->miscinfo &= ~(1L << 1))
#define SC_is_fetchcursor(a)	(((a)->miscinfo & (1L << 1)) != 0)
#define SC_miscinfo_clear(a)	((a)->miscinfo = 0)
#define SC_set_with_hold(a)	((a)->execinfo |= 1L)
#define SC_set_without_hold(a)	((a)->execinfo &= (~1L))
#define SC_is_with_hold(a)	(((a)->execinfo & 1L) != 0)
#define SC_set_readonly(a)	((a)->execinfo |= (1L << 1))
#define SC_set_no_readonly(a)	((a)->execinfo &= ~(1L << 1))
#define SC_is_readonly(a)	(((a)->execinfo & (1L << 1)) != 0)
#define SC_execinfo_clear(a)	(((a)->execinfo = 0)
#define	STMT_HAS_OUTER_JOIN	1L
#define	STMT_HAS_INNER_JOIN	(1L << 1)
#define SC_has_join(a)		(0 != (a)->join_info)
#define SC_has_outer_join(a)	(0 != (STMT_HAS_OUTER_JOIN & (a)->join_info))
#define SC_has_inner_join(a)	(0 != (STMT_HAS_INNER_JOIN & (a)->join_info))
#define SC_set_outer_join(a)	((a)->join_info |= STMT_HAS_OUTER_JOIN)
#define SC_set_inner_join(a)	((a)->join_info |= STMT_HAS_INNER_JOIN)

#define SC_start_tc_stmt(a)	((a)->rb_or_tc = (1L << 1))
#define SC_is_tc_stmt(a)	(((a)->rb_or_tc & (1L << 1)) != 0)
#define SC_start_rb_stmt(a)	((a)->rb_or_tc = (1L << 2))
#define SC_is_rb_stmt(a)	(((a)->rb_or_tc & (1L << 2)) != 0)
#define SC_unref_CC_error(a)	(((a)->ref_CC_error) = FALSE)
#define SC_ref_CC_error(a)	(((a)->ref_CC_error) = TRUE)
#define SC_can_parse_statement(a) (STMT_TYPE_SELECT == (a)->statement_type)
/*
 * DECLARE CURSOR + FETCH can only be used with SELECT-type queries. And
 * it's not currently supported with array-bound parameters.
 */
#define SC_may_use_cursor(a) \
	(SC_get_APDF(a)->paramset_size <= 1 &&	\
	 (STMT_TYPE_SELECT == (a)->statement_type || STMT_TYPE_WITH == (a)->statement_type) )
#define SC_may_fetch_rows(a) (STMT_TYPE_SELECT == (a)->statement_type || STMT_TYPE_WITH == (a)->statement_type)


/* For Multi-thread */
#if defined(WIN_MULTITHREAD_SUPPORT)
#define INIT_STMT_CS(x)		InitializeCriticalSection(&((x)->cs))
#define ENTER_STMT_CS(x)	EnterCriticalSection(&((x)->cs))
#define TRY_ENTER_STMT_CS(x)	TryEnterCriticalSection(&((x)->cs))
#define LEAVE_STMT_CS(x)	LeaveCriticalSection(&((x)->cs))
#define DELETE_STMT_CS(x)	DeleteCriticalSection(&((x)->cs))
#elif defined(POSIX_THREADMUTEX_SUPPORT)
#define INIT_STMT_CS(x)		pthread_mutex_init(&((x)->cs),0)
#define ENTER_STMT_CS(x)	pthread_mutex_lock(&((x)->cs))
#define TRY_ENTER_STMT_CS(x)	(0 == pthread_mutex_trylock(&((x)->cs)))
#define LEAVE_STMT_CS(x)	pthread_mutex_unlock(&((x)->cs))
#define DELETE_STMT_CS(x)	pthread_mutex_destroy(&((x)->cs))
#else
#define INIT_STMT_CS(x)
#define ENTER_STMT_CS(x)
#define TRY_ENTER_STMT_CS(x)	(1)
#define LEAVE_STMT_CS(x)
#define DELETE_STMT_CS(x)
#endif /* WIN_MULTITHREAD_SUPPORT */
/*	Statement prototypes */
StatementClass *SC_Constructor(ConnectionClass *);
void		InitializeStatementOptions(StatementOptions *opt);
char		SC_Destructor(StatementClass *self);
BOOL		SC_opencheck(StatementClass *self, const char *func);
RETCODE		SC_initialize_and_recycle(StatementClass *self);
void		SC_initialize_cols_info(StatementClass *self, BOOL DCdestroy, BOOL parseReset);
void		SC_reset_result_for_rerun(StatementClass *self);
int		statement_type(const char *statement);
char		parse_statement(StatementClass *stmt, BOOL);
char		parse_sqlsvr(StatementClass *stmt);
SQLRETURN	SC_set_SS_columnkey(StatementClass *stmt);
Int4		SC_describe(StatementClass *self);
char		SC_unbind_cols(StatementClass *self);
char		SC_recycle_statement(StatementClass *self);

void		SC_clear_error(StatementClass *self);
void		SC_set_error(StatementClass *self, int errnum, const char *msg, const char *func);
void		SC_set_errormsg(StatementClass *self, const char *msg);
void		SC_error_copy(StatementClass *self, const StatementClass *from, BOOL);
void		SC_full_error_copy(StatementClass *self, const StatementClass *from, BOOL);
void		SC_replace_error_with_res(StatementClass *self, int errnum, const char *msg, const QResultClass*, BOOL);
void		SC_set_prepared(StatementClass *self, int);
void		SC_set_planname(StatementClass *self, const char *plan_name);
void		SC_set_rowset_start(StatementClass *self, SQLLEN, BOOL);
void		SC_inc_rowset_start(StatementClass *self, SQLLEN);
RETCODE		SC_initialize_stmts(StatementClass *self, BOOL);
RETCODE		SC_execute(StatementClass *self);
RETCODE		SC_fetch(StatementClass *self);
void		SC_free_params(StatementClass *self, char option);
void		SC_log_error(const char *func, const char *desc, const StatementClass *self);
time_t		SC_get_time(StatementClass *self);
struct tm	*SC_get_localtime(StatementClass *self);
SQLLEN		SC_get_int4_bookmark(StatementClass *self);
RETCODE		SC_pos_reload(StatementClass *self, SQLULEN index, UInt2 *, Int4);
RETCODE		SC_pos_update(StatementClass *self, SQLSETPOSIROW irow, SQLULEN index, const KeySet *keyset);
RETCODE		SC_pos_delete(StatementClass *self, SQLSETPOSIROW irow, SQLULEN index, const KeySet *keyset);
RETCODE		SC_pos_refresh(StatementClass *self, SQLSETPOSIROW irow, SQLULEN index);
RETCODE		SC_pos_fetch(StatementClass *self, const PG_BM *pg_bm);
RETCODE		SC_pos_add(StatementClass *self, SQLSETPOSIROW irow);
RETCODE		SC_fetch_by_bookmark(StatementClass *self);
int		SC_Create_bookmark(StatementClass *stmt, BindInfoClass *bookmark, Int4 row_pos, Int4 currTuple, const KeySet *keyset);
PG_BM		SC_Resolve_bookmark(const ARDFields *opts, Int4 idx);
int		SC_set_current_col(StatementClass *self, int col);
void		SC_setInsertedTable(StatementClass *, RETCODE);
void		SC_scanQueryAndCountParams(const char *, const ConnectionClass *,
			ssize_t *next_cmd, SQLSMALLINT *num_params,
			po_ind_t *multi, po_ind_t *proc_return);

BOOL	SC_IsExecuting(const StatementClass *self);
BOOL	SC_SetExecuting(StatementClass *self, BOOL on);
BOOL	SC_SetCancelRequest(StatementClass *self);
BOOL	SC_AcceptedCancelRequest(const StatementClass *self);

BOOL	SC_connection_lost_check(StatementClass *stmt, const char *funcname);

int		enqueueNeedDataCallback(StatementClass *self, NeedDataCallfunc, void *);
RETCODE		dequeueNeedDataCallback(RETCODE, StatementClass *self);
void		cancelNeedDataState(StatementClass *self);
int		StartRollbackState(StatementClass *self);
RETCODE		SetStatementSvp(StatementClass *self, unsigned int option);
RETCODE		DiscardStatementSvp(StatementClass *self, RETCODE, BOOL errorOnly);

QResultClass *ParseAndDescribeWithLibpq(StatementClass *stmt, const char *plan_name, const char *query_p, Int2 num_params, const char *comment, QResultClass *res);

/*
 *	Macros to convert global index <-> relative index in resultset/rowset
 */
/* a global index to the relative index in a rowset */
#define	SC_get_rowset_start(stmt) ((stmt)->rowset_start)
#define	GIdx2RowIdx(gidx, stmt)	(gidx - (stmt)->rowset_start)
/* a global index to the relative index in a resultset(not a rowset) */
#define	GIdx2CacheIdx(gidx, s, r)	(gidx - (QR_has_valid_base(r) ? ((s)->rowset_start - (r)->base) : 0))
#define	GIdx2KResIdx(gidx, s, r)	(gidx - (QR_has_valid_base(r) ? ((s)->rowset_start - (r)->key_base) : 0))
/* a relative index in a rowset to the global index */
#define	RowIdx2GIdx(ridx, stmt)	(ridx + (stmt)->rowset_start)
/* a relative index in a resultset to the global index */
#define	CacheIdx2GIdx(ridx, stmt, res)	(ridx - (res)->base + (stmt)->rowset_start)
#define	KResIdx2GIdx(ridx, stmt, res)	(ridx - (res)->key_base + (stmt)->rowset_start)

#define	BOOKMARK_SHIFT	1
#define	SC_make_int4_bookmark(b)	((b < 0) ? (b) : (b + BOOKMARK_SHIFT))
#define	SC_resolve_int4_bookmark(b)	((b < 0) ? (b) : (b - BOOKMARK_SHIFT))
#endif /* __STATEMENT_H__ */
