summaryrefslogtreecommitdiff
path: root/qresult.h
blob: a06b51767a07a37195dc980e8c04551094a007d4 (plain)
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
/* File:			qresult.h
 *
 * Description:		See "qresult.c"
 *
 * Comments:		See "readme.txt" for copyright and license information.
 *
 */

#ifndef __QRESULT_H__
#define __QRESULT_H__

#include "psqlodbc.h"

#include "libpq-fe.h"

#include "connection.h"
#include "columninfo.h"
#include "tuple.h"

#ifdef	__cplusplus
extern	"C" {
#endif

typedef
enum	QueryResultCode_
{
	PORES_EMPTY_QUERY = 0,
	PORES_COMMAND_OK,	/* a query command that doesn't return
				 * anything was executed properly by the backend */
	PORES_TUPLES_OK,	/* a query command that returns tuples
				 * was executed properly by the backend, PGresult
				 * contains the resulttuples */
	PORES_COPY_OUT,
	PORES_COPY_IN,
	PORES_BAD_RESPONSE,	/* an unexpected response was recv'd from
				 * the backend */
	PORES_NONFATAL_ERROR,
	PORES_FATAL_ERROR,
	PORES_NO_MEMORY_ERROR,
	PORES_FIELDS_OK = 100,	/* field information from a query was
				 * successful */
	/* PORES_END_TUPLES, */
	PORES_INTERNAL_ERROR
} QueryResultCode;

enum
{
	FQR_REACHED_EOF = (1L << 1)	/* reached eof */
	,FQR_HAS_VALID_BASE = (1L << 2)
	,FQR_NEEDS_SURVIVAL_CHECK = (1L << 3) /* check if the cursor is open */
};

struct QResultClass_
{
	ColumnInfoClass *fields;	/* the Column information */
	ConnectionClass *conn;		/* the connection this result is using
								 * (backend) */
	QResultClass	*lnext;		/* the following result class */

	/* Stuff for declare/fetch tuples */
	SQLULEN		num_total_read;	/* the highest absolute position ever read in + 1 */
	SQLULEN		count_backend_allocated;/* m(re)allocated count */
	SQLULEN		num_cached_rows;	/* count of tuples kept in backend_tuples member */
	SQLLEN		fetch_number;	/* 0-based index to the tuple to read next */
	SQLLEN		cursTuple;	/* absolute current position in the servr's cursor used to retrieve tuples from the DB */
	SQLULEN		move_offset;
	SQLLEN		base;		/* relative position of rowset start in the current data cache(backend_tuples) */

	UInt2		num_fields;	/* number of fields in the result */
	UInt2		num_key_fields;	/* number of key fields in the result */
	UInt4		rowset_size_include_ommitted; /* PG restriction */
	SQLLEN		recent_processed_row_count;
	SQLULEN		cache_size;
	SQLULEN		cmd_fetch_size;

	QueryResultCode	rstatus;	/* result status */

	char	sqlstate[8];
	char	*message;
	const char *messageref;
	char *cursor_name;		/* The name of the cursor for select statements */
	char	*command;
	char	*notice;

	TupleField *backend_tuples;	/* data from the backend (the tuple cache) */
	TupleField *tupleField;		/* current backend tuple being retrieved */

	char	pstatus;		/* processing status */
	char	aborted;		/* was aborted ? */
	char	flags;			/* this result contains keyset etc ? */
	po_ind_t	move_direction;	/* must move before fetching this
						result set */
	SQLULEN		count_keyset_allocated; /* m(re)allocated count */
	SQLULEN		num_cached_keys;	/* count of keys kept in backend_keys member */
	KeySet		*keyset;
	SQLLEN		key_base;	/* relative position of rowset start in the current keyset cache */
	UInt2		reload_count;
	UInt2		rb_alloc;	/* count of allocated rollback info */
	UInt2		rb_count;	/* count of rollback info */
	char		dataFilled;	/* Cache is filled with data ? */
	Rollback	*rollback;
	UInt4		ad_alloc;	/* count of allocated added info */
	UInt4		ad_count;	/* count of newly added rows */
	KeySet		*added_keyset;	/* added keyset info */
	TupleField	*added_tuples;	/* added data by myself */
	UInt2		dl_alloc;	/* count of allocated deleted info */
	UInt2		dl_count;	/* count of deleted info */
	SQLLEN		*deleted;	/* deleted index info */
	KeySet		*deleted_keyset;	/* deleted keyset info */
	UInt2		up_alloc;	/* count of allocated updated info */
	UInt2		up_count;	/* count of updated info */
	SQLLEN		*updated;	/* updated index info */
	KeySet		*updated_keyset;	/* uddated keyset info */
	TupleField	*updated_tuples;	/* uddated data by myself */
};

enum {
	 FQR_HASKEYSET	= 1L
	,FQR_WITHHOLD	= (1L << 1)
	,FQR_HOLDPERMANENT = (1L << 2) /* the cursor is alive across transactions */
	,FQR_SYNCHRONIZEKEYS = (1L<<3) /* synchronize the keyset range with that of cthe tuples cache */
};

#define	QR_haskeyset(self)		(0 != (self->flags & FQR_HASKEYSET))
#define	QR_is_withhold(self)		(0 != (self->flags & FQR_WITHHOLD))
#define	QR_is_permanent(self)		(0 != (self->flags & FQR_HOLDPERMANENT))
#define	QR_synchronize_keys(self)	(0 != (self->flags & FQR_SYNCHRONIZEKEYS))
#define QR_get_fields(self)		(self->fields)


/*	These functions are for retrieving data from the qresult */
#define QR_get_value_backend(self, fieldno)	(self->tupleField[fieldno].value)
#define QR_get_value_backend_row(self, tupleno, fieldno) ((self->backend_tuples + (tupleno * self->num_fields))[fieldno].value)
#define QR_get_value_backend_text(self, tupleno, fieldno) QR_get_value_backend_row(self, tupleno, fieldno)
#define QR_get_value_backend_int(self, tupleno, fieldno, isNull) atoi(QR_get_value_backend_row(self, tupleno, fieldno))

/*	These functions are used by both manual and backend results */
#define QR_NumResultCols(self)		(CI_get_num_fields(self->fields))
#define QR_NumPublicResultCols(self)	(QR_haskeyset(self) ? (CI_get_num_fields(self->fields) - self->num_key_fields) : CI_get_num_fields(self->fields))
#define QR_get_fieldname(self, fieldno_)	(CI_get_fieldname(self->fields, fieldno_))
#define QR_get_fieldsize(self, fieldno_)	(CI_get_fieldsize(self->fields, fieldno_))
#define QR_get_display_size(self, fieldno_) (CI_get_display_size(self->fields, fieldno_))
#define QR_get_atttypmod(self, fieldno_)	(CI_get_atttypmod(self->fields, fieldno_))
#define QR_get_field_type(self, fieldno_)	(CI_get_oid(self->fields, fieldno_))
#define QR_get_relid(self, fieldno_)	(CI_get_relid(self->fields, fieldno_))
#define QR_get_attid(self, fieldno_)	(CI_get_attid(self->fields, fieldno_))

/*	These functions are used only for manual result sets */
#define QR_get_num_total_tuples(self)		(QR_once_reached_eof(self) ? (self->num_total_read + self->ad_count) : self->num_total_read)
#define QR_get_num_total_read(self)		(self->num_total_read)
#define QR_get_num_cached_tuples(self)		(self->num_cached_rows)
#define QR_set_field_info(self, field_num, name, adtid, adtsize, relid, attid)  (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1, relid, attid))
#define QR_set_field_info_v(self, field_num, name, adtid, adtsize)  (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1, 0, 0))

/* status macros */
#define QR_command_successful(self)	(self && !(self->rstatus == PORES_BAD_RESPONSE || self->rstatus == PORES_NONFATAL_ERROR || self->rstatus == PORES_FATAL_ERROR || self->rstatus == PORES_NO_MEMORY_ERROR))
#define QR_command_maybe_successful(self) (self && !(self->rstatus == PORES_BAD_RESPONSE || self->rstatus == PORES_FATAL_ERROR || self->rstatus == PORES_NO_MEMORY_ERROR))
#define QR_command_nonfatal(self)	( self->rstatus == PORES_NONFATAL_ERROR)
#define QR_set_conn(self, conn_)			( self->conn = conn_ )
#define QR_set_rstatus(self, condition)		( self->rstatus = condition )
#define QR_set_sqlstatus(self, status)		strcpy(self->sqlstatus, status)
#define QR_set_messageref(self, m)	((self)->messageref = m)
#define QR_set_aborted(self, aborted_)		( self->aborted = aborted_)
#define QR_set_haskeyset(self)		(self->flags |= FQR_HASKEYSET)
#define QR_set_synchronize_keys(self)	(self->flags |= FQR_SYNCHRONIZEKEYS)
#define QR_set_no_cursor(self)		((self)->flags &= ~(FQR_WITHHOLD | FQR_HOLDPERMANENT), (self)->pstatus &= ~FQR_NEEDS_SURVIVAL_CHECK)
#define QR_set_withhold(self)		(self->flags |= FQR_WITHHOLD)
#define QR_set_permanent(self)		(self->flags |= FQR_HOLDPERMANENT)
#define	QR_set_reached_eof(self)	(self->pstatus |= FQR_REACHED_EOF)
#define QR_set_has_valid_base(self)	(self->pstatus |= FQR_HAS_VALID_BASE)
#define QR_set_no_valid_base(self)	(self->pstatus &= ~FQR_HAS_VALID_BASE)
#define QR_set_survival_check(self)	(self->pstatus |= FQR_NEEDS_SURVIVAL_CHECK)
#define QR_set_no_survival_check(self)	(self->pstatus &= ~FQR_NEEDS_SURVIVAL_CHECK)
#define	QR_inc_num_cache(self) \
do { \
	self->num_cached_rows++; \
	if (QR_haskeyset(self)) \
		self->num_cached_keys++; \
} while (0)
#define	QR_set_next_in_cache(self, number) \
do { \
	MYLOG(1, "set the number to " FORMAT_LEN " to read next\n", number); \
	self->fetch_number = number; \
} while (0)
#define	QR_inc_next_in_cache(self) \
do { \
	MYLOG(1, "increased the number " FORMAT_LEN, self->fetch_number); \
	self->fetch_number++; \
	MYLOG(1, "to " FORMAT_LEN " to next read\n", self->fetch_number); \
} while (0)

#define	QR_concat(self, a)	((self)->lnext=(a))
#define	QR_detach(self)	((self)->lnext=NULL)
#define	QR_nextr(self)	((self)->lnext)

#define QR_get_message(self)		((self)->message ? (self)->message : (self)->messageref)
#define QR_get_command(self)				(self->command)
#define QR_get_notice(self)				(self->notice)
#define QR_get_rstatus(self)				(self->rstatus)
#define QR_get_aborted(self)				(self->aborted)
#define QR_get_conn(self)				(self->conn)
#define QR_get_cursor(self)				(self->cursor_name)
#define QR_get_rowstart_in_cache(self)			(self->base)
#define QR_once_reached_eof(self)	((self->pstatus & FQR_REACHED_EOF) != 0)
#define	QR_has_valid_base(self)		(0 != (self->pstatus & FQR_HAS_VALID_BASE))
#define	QR_needs_survival_check(self)		(0 != (self->pstatus & FQR_NEEDS_SURVIVAL_CHECK))

#define QR_aborted(self)		(!self || self->aborted)
#define QR_get_reqsize(self)		(self->rowset_size_include_ommitted)

#define QR_stop_movement(self)		(self->move_direction = 0)
#define QR_is_moving(self)		(0 != self->move_direction)
#define QR_is_not_moving(self)		(0 == self->move_direction)
#define QR_set_move_forward(self)	(self->move_direction = 1)
#define QR_is_moving_forward(self)	(1 == self->move_direction)
#define QR_set_move_backward(self)	(self->move_direction = -1)
#define QR_is_moving_backward(self)	(-1 == self->move_direction)
#define QR_set_move_from_the_last(self)	(self->move_direction = 2)
#define QR_is_moving_from_the_last(self)	(2 == self->move_direction)
#define QR_is_moving_not_backward(self)	(0 < self->move_direction)

/*	Core Functions */
QResultClass	*QR_Constructor(void);
void		QR_Destructor(QResultClass *self);
TupleField	*QR_AddNew(QResultClass *self);
int		QR_next_tuple(QResultClass *self, StatementClass *);
int			QR_close(QResultClass *self);
void		QR_on_close_cursor(QResultClass *self);
void		QR_close_result(QResultClass *self, BOOL destroy);
void		QR_reset_for_re_execute(QResultClass *self);
BOOL		QR_from_PGresult(QResultClass *self, StatementClass *stmt, ConnectionClass *conn, const char *cursor, PGresult **pgres);
void		QR_free_memory(QResultClass *self);
void		QR_set_command(QResultClass *self, const char *msg);
void		QR_set_message(QResultClass *self, const char *msg);
void		QR_add_message(QResultClass *self, const char *msg);
void		QR_set_notice(QResultClass *self, const char *msg);
void		QR_add_notice(QResultClass *self, const char *msg);

void		QR_set_num_fields(QResultClass *self, int new_num_fields); /* catalog functions' result only */
void		QR_set_fields(QResultClass *self, ColumnInfoClass *);

void		QR_set_num_cached_rows(QResultClass *, SQLLEN);
void		QR_set_rowstart_in_cache(QResultClass *, SQLLEN);
void		QR_inc_rowstart_in_cache(QResultClass *self, SQLLEN base_inc);
void		QR_set_cache_size(QResultClass *self, SQLLEN cache_size);
void		QR_set_reqsize(QResultClass *self, Int4 reqsize);
void		QR_set_position(QResultClass *self, SQLLEN pos);
void		QR_set_cursor(QResultClass *self, const char *name);
SQLLEN		getNthValid(const QResultClass *self, SQLLEN sta, UWORD orientation, SQLULEN nth, SQLLEN *nearest);
SQLLEN		QR_move_cursor_to_last(QResultClass *self, StatementClass *stmt);
BOOL		QR_get_last_bookmark(const QResultClass *self, Int4 index, KeySet *keyset);
int			QR_search_by_fieldname(const QResultClass *self, const char *name);

#define QR_MALLOC_return_with_error(t, tp, s, a, m, r) \
do { \
	if (t = (tp *) malloc(s), NULL == t) \
	{ \
		QR_set_rstatus(a, PORES_NO_MEMORY_ERROR); \
qlog("QR_MALLOC_error\n"); \
		QR_free_memory(a); \
		QR_set_messageref(a, m); \
		return r; \
	} \
} while (0)
#define QR_REALLOC_return_with_error(t, tp, s, a, m, r) \
do { \
	tp *tmp; \
	if (tmp = (tp *) realloc(t, s), NULL == tmp) \
	{ \
		QR_set_rstatus(a, PORES_NO_MEMORY_ERROR); \
qlog("QR_REALLOC_error\n"); \
		QR_free_memory(a); \
		QR_set_messageref(a, m); \
		return r; \
	} \
	t = tmp; \
} while (0)
#define	QR_REALLOC_gexit_with_error(t, tp, s, a, m, r) \
do { \
	tp *tmp; \
	if (tmp = (tp *) realloc(t, s), NULL == tmp) \
	{ \
		QR_set_rstatus(a, PORES_NO_MEMORY_ERROR); \
		QR_free_memory(a); \
		QR_set_messageref(a, m); \
		r; \
		goto cleanup; \
	} \
	t = tmp; \
} while (0)

#ifdef	__cplusplus
}
#endif
#endif /* __QRESULT_H__ */