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
|