~ubuntu-branches/ubuntu/edgy/psqlodbc/edgy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/* File:			statement.h
 *
 * 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 "bind.h"
#include "descriptor.h"

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

#ifndef FALSE
#define FALSE	(BOOL)0
#endif
#ifndef TRUE
#define TRUE	(BOOL)1
#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_PREMATURE,				/* 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 simply execute the
								 * query _before_ the actual call to
								 * SQLExecute, so that statement is
								 * considered to be "premature". */
	STMT_FINISHED,				/* statement execution has finished */
	STMT_EXECUTING				/* statement execution is still going on */
} STMT_Status;

#define STMT_ROW_VERSION_CHANGED					(-4)
#define STMT_POS_BEFORE_RECORDSET					(-3)
#define STMT_TRUNCATED							(-2)
#define STMT_INFO_ONLY							(-1)	/* not an error message,
														 * just a notification
														 * to be returned by
														 * SQLError */
#define STMT_OK									0		/* will be interpreted
														 * as "no error pending" */
#define STMT_EXEC_ERROR							1
#define STMT_STATUS_ERROR						2
#define STMT_SEQUENCE_ERROR						3
#define STMT_NO_MEMORY_ERROR					4
#define STMT_COLNUM_ERROR						5
#define STMT_NO_STMTSTRING						6
#define STMT_ERROR_TAKEN_FROM_BACKEND			7
#define STMT_INTERNAL_ERROR						8
#define STMT_STILL_EXECUTING					9
#define STMT_NOT_IMPLEMENTED_ERROR				10
#define STMT_BAD_PARAMETER_NUMBER_ERROR			11
#define STMT_OPTION_OUT_OF_RANGE_ERROR			12
#define STMT_INVALID_COLUMN_NUMBER_ERROR		13
#define STMT_RESTRICTED_DATA_TYPE_ERROR			14
#define STMT_INVALID_CURSOR_STATE_ERROR			15
#define STMT_OPTION_VALUE_CHANGED				16
#define STMT_CREATE_TABLE_ERROR					17
#define STMT_NO_CURSOR_NAME						18
#define STMT_INVALID_CURSOR_NAME				19
#define STMT_INVALID_ARGUMENT_NO				20
#define STMT_ROW_OUT_OF_RANGE					21
#define STMT_OPERATION_CANCELLED				22
#define STMT_INVALID_CURSOR_POSITION			23
#define STMT_VALUE_OUT_OF_RANGE					24
#define STMT_OPERATION_INVALID					25
#define STMT_PROGRAM_TYPE_OUT_OF_RANGE			26
#define STMT_BAD_ERROR							27
#define STMT_INVALID_OPTION_IDENTIFIER					28
#define STMT_RETURN_NULL_WITHOUT_INDICATOR				29
#define STMT_ERROR_IN_ROW						30
#define STMT_INVALID_DESCRIPTOR_IDENTIFIER				31
#define STMT_OPTION_NOT_FOR_THE_DRIVER					32
#define STMT_FETCH_OUT_OF_RANGE						33
#define STMT_COUNT_FIELD_INCORRECT					34

/* statement types */
enum
{
	STMT_TYPE_UNKNOWN = -2,
	STMT_TYPE_OTHER = -1,
	STMT_TYPE_SELECT = 0,
	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_PROCCALL,
	STMT_TYPE_LOCK
};

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


/*	Parsing status */
enum
{
	STMT_PARSE_NONE = 0,
	STMT_PARSE_COMPLETE,
	STMT_PARSE_INCOMPLETE,
	STMT_PARSE_FATAL
};

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


/********	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 FAR  *phstmt;
	StatementOptions options;
	StatementOptions options_orig;
	ARDFields ardopts;
	IRDFields irdopts;
	APDFields apdopts;
	IPDFields ipdopts;

	STMT_Status status;
	char	   *__error_message;
	int			__error_number;

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

	char	   *statement;		/* if non--null pointer to the SQL
								 * statement that has been executed */

	TABLE_INFO **ti;
	int			ntab;

	int			parse_status;

	int			statement_type; /* According to the defines above */
	int			data_at_exec;	/* Number of params needing SQLPutData */
	int			current_exec_param;		/* The current parameter for
										 * SQLPutData */

	char		put_data;		/* Has SQLPutData been called yet? */

	char		errormsg_created;		/* has an informative error msg
										 * been created?  */
	char		manual_result;	/* Is the statement result manually built? */
	char		prepare;		/* is this statement a prepared statement ? */
	char		prepared;		/* is this statement already
						 * prepared at the server ? */
	char		internal;		/* Is this statement being called
								 * internally? */
	char		transition_status;	/* Transition status */
	char		cursor_name[MAX_CURSOR_LEN + 1];

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

	char		pre_executing;	/* This statement is prematurely executing */
	char		inaccurate_result;		/* Current status is PREMATURE but
										 * result is inaccurate */
	char		miscinfo;
	char		updatable;
	SWORD		errorpos;
	SWORD		error_recsize;
	Int4		diag_row_count;
	char		*load_statement; /* to (re)load updatable individual rows */
	char		*execute_statement; /* to execute the prepared plans */
	Int4		from_pos;	
	Int4		where_pos;
	Int4		last_fetch_count_include_ommitted;
	time_t		stmt_time;
#if defined(WIN_MULTITHREAD_SUPPORT)
	CRITICAL_SECTION	cs;
#elif defined(POSIX_MULTITHREAD_SUPPORT)
    pthread_mutex_t     cs;
#endif /* WIN_MULTITHREAD_SUPPORT */

};

#define SC_get_conn(a)	  (a->hdbc)
#define SC_set_Result(a, b)  (a->result = a->curres = b)
#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->ardopts))
#define SC_get_APD(a)  (&(a->apdopts))
#define SC_get_IRD(a)  (&(a->irdopts))
#define SC_get_IPD(a)  (&(a->ipdopts))

#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)
#if (ODBCVER >= 0x0300)
#define	SC_is_lower_case(a, b) (a->options.metadata_id || b->connInfo.lower_case_identifier)
#else
#define	SC_is_lower_case(a, b) (b->connInfo.lower_case_identifier)
#endif /* ODBCVER */

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

/*	misc info */
#define SC_set_pre_executable(a) (a->miscinfo |= 1L)
#define SC_no_pre_executable(a) (a->miscinfo &= ~1L)
#define SC_is_pre_executable(a) ((a->miscinfo & 1L) != 0)
#define SC_set_fetchcursor(a)	(a->miscinfo |= 2L)
#define SC_no_fetchcursor(a)	(a->miscinfo &= ~2L)
#define SC_is_fetchcursor(a)	((a->miscinfo & 2L) != 0)
#define SC_set_prepare_before_exec(a)	(a->miscinfo |= 4L)
#define SC_no_prepare_before_exec(a)	(a->miscinfo &= ~4L)
#define SC_is_prepare_before_exec(a)	((a->miscinfo & 4L) != 0)

/* 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 LEAVE_STMT_CS(x)	LeaveCriticalSection(&((x)->cs))
#define DELETE_STMT_CS(x)	DeleteCriticalSection(&((x)->cs))
#elif defined(POSIX_MULTITHREAD_SUPPORT)
#define INIT_STMT_CS(x)		pthread_mutex_init(&((x)->cs),0)
#define ENTER_STMT_CS(x)	pthread_mutex_lock(&((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 LEAVE_STMT_CS(x)
#define DELETE_STMT_CS(x)
#endif /* WIN_MULTITHREAD_SUPPORT */
/*	Statement prototypes */
StatementClass *SC_Constructor(void);
void		InitializeStatementOptions(StatementOptions *opt);
char		SC_Destructor(StatementClass *self);
int		statement_type(const char *statement);
char		parse_statement(StatementClass *stmt);
void		SC_pre_execute(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);
void		SC_set_errormsg(StatementClass *self, const char *msg);
void		SC_error_copy(StatementClass *self, const StatementClass *from);
void		SC_full_error_copy(StatementClass *self, const StatementClass *from);
char		SC_get_error(StatementClass *self, int *number, char **message);
char		*SC_create_errormsg(const StatementClass *self);
void		SC_set_prepared(StatementClass *self, BOOL);
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);
unsigned long SC_get_bookmark(StatementClass *self);
RETCODE		SC_pos_update(StatementClass *self, UWORD irow, UDWORD index);
RETCODE		SC_pos_delete(StatementClass *self, UWORD irow, UDWORD index);
RETCODE		SC_pos_refresh(StatementClass *self, UWORD irow, UDWORD index);
RETCODE		SC_pos_add(StatementClass *self, UWORD irow);

/*
 *	Macros to convert global index <-> relative index in resultset/rowset
 */
/* a global index to the relative index in a rowset */
#define	GIdx2RowIdx(gidx, stmt)	(gidx - stmt->rowset_start)
/* a global index to the relative index in a resultset(not a rowset) */
#define	GIdx2ResultIdx(gidx, stmt, res)	((stmt->rowset_start < 0) ? res->base : gidx - stmt->rowset_start + res->base)
/* 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	ResultIdx2GIdx(ridx, stmt, res)	(ridx - res->base + stmt->rowset_start)
#endif