1 /* File:			qresult.h
2  *
3  * Description:		See "qresult.c"
4  *
5  * Comments:		See "readme.txt" for copyright and license information.
6  *
7  */
8 
9 #ifndef __QRESULT_H__
10 #define __QRESULT_H__
11 
12 #include "psqlodbc.h"
13 
14 #include "libpq-fe.h"
15 
16 #include "connection.h"
17 #include "columninfo.h"
18 #include "tuple.h"
19 
20 #ifdef	__cplusplus
21 extern	"C" {
22 #endif
23 
24 typedef
25 enum	QueryResultCode_
26 {
27 	PORES_EMPTY_QUERY = 0,
28 	PORES_COMMAND_OK,	/* a query command that doesn't return
29 				 * anything was executed properly by the backend */
30 	PORES_TUPLES_OK,	/* a query command that returns tuples
31 				 * was executed properly by the backend, PGresult
32 				 * contains the resulttuples */
33 	PORES_COPY_OUT,
34 	PORES_COPY_IN,
35 	PORES_BAD_RESPONSE,	/* an unexpected response was recv'd from
36 				 * the backend */
37 	PORES_NONFATAL_ERROR,
38 	PORES_FATAL_ERROR,
39 	PORES_NO_MEMORY_ERROR,
40 	PORES_FIELDS_OK = 100,	/* field information from a query was
41 				 * successful */
42 	/* PORES_END_TUPLES, */
43 	PORES_INTERNAL_ERROR
44 } QueryResultCode;
45 
46 enum
47 {
48 	FQR_REACHED_EOF = (1L << 1)	/* reached eof */
49 	,FQR_HAS_VALID_BASE = (1L << 2)
50 	,FQR_NEEDS_SURVIVAL_CHECK = (1L << 3) /* check if the cursor is open */
51 };
52 
53 struct QResultClass_
54 {
55 	ColumnInfoClass *fields;	/* the Column information */
56 	ConnectionClass *conn;		/* the connection this result is using
57 								 * (backend) */
58 	QResultClass	*lnext;		/* the following result class */
59 
60 	/* Stuff for declare/fetch tuples */
61 	SQLULEN		num_total_read;	/* the highest absolute position ever read in + 1 */
62 	SQLULEN		count_backend_allocated;/* m(re)alloced count */
63 	SQLULEN		num_cached_rows;	/* count of tuples kept in backend_tuples member */
64 	SQLLEN		fetch_number;	/* 0-based index to the tuple to read next */
65 	SQLLEN		cursTuple;	/* absolute current position in the servr's cursor used to retrieve tuples from the DB */
66 	SQLULEN		move_offset;
67 	SQLLEN		base;		/* relative position of rowset start in the current data cache(backend_tuples) */
68 
69 	UInt2		num_fields;	/* number of fields in the result */
70 	UInt2		num_key_fields;	/* number of key fields in the result */
71 	UInt4		rowset_size_include_ommitted; /* PG restriction */
72 	SQLLEN		recent_processed_row_count;
73 	SQLULEN		cache_size;
74 	SQLULEN		cmd_fetch_size;
75 
76 	QueryResultCode	rstatus;	/* result status */
77 
78 	char	sqlstate[8];
79 	char	*message;
80 	const char *messageref;
81 	char *cursor_name;		/* The name of the cursor for select statements */
82 	char	*command;
83 	char	*notice;
84 
85 	TupleField *backend_tuples;	/* data from the backend (the tuple cache) */
86 	TupleField *tupleField;		/* current backend tuple being retrieved */
87 
88 	char	pstatus;		/* processing status */
89 	char	aborted;		/* was aborted ? */
90 	char	flags;			/* this result contains keyset etc ? */
91 	po_ind_t	move_direction;	/* must move before fetching this
92 						result set */
93 	SQLULEN		count_keyset_allocated; /* m(re)alloced count */
94 	SQLULEN		num_cached_keys;	/* count of keys kept in backend_keys member */
95 	KeySet		*keyset;
96 	SQLLEN		key_base;	/* relative position of rowset start in the current keyset cache */
97 	UInt2		reload_count;
98 	UInt2		rb_alloc;	/* count of allocated rollback info */
99 	UInt2		rb_count;	/* count of rollback info */
100 	char		dataFilled;	/* Cache is filled with data ? */
101 	Rollback	*rollback;
102 	UInt4		ad_alloc;	/* count of allocated added info */
103 	UInt4		ad_count;	/* count of newly added rows */
104 	KeySet		*added_keyset;	/* added keyset info */
105 	TupleField	*added_tuples;	/* added data by myself */
106 	UInt2		dl_alloc;	/* count of allocated deleted info */
107 	UInt2		dl_count;	/* count of deleted info */
108 	SQLLEN		*deleted;	/* deleted index info */
109 	KeySet		*deleted_keyset;	/* deleted keyset info */
110 	UInt2		up_alloc;	/* count of allocated updated info */
111 	UInt2		up_count;	/* count of updated info */
112 	SQLLEN		*updated;	/* updated index info */
113 	KeySet		*updated_keyset;	/* uddated keyset info */
114 	TupleField	*updated_tuples;	/* uddated data by myself */
115 };
116 
117 enum {
118 	 FQR_HASKEYSET	= 1L
119 	,FQR_WITHHOLD	= (1L << 1)
120 	,FQR_HOLDPERMANENT = (1L << 2) /* the cursor is alive across transactions */
121 	,FQR_SYNCHRONIZEKEYS = (1L<<3) /* synchronize the keyset range with that of cthe tuples cache */
122 };
123 
124 #define	QR_haskeyset(self)		(0 != (self->flags & FQR_HASKEYSET))
125 #define	QR_is_withhold(self)		(0 != (self->flags & FQR_WITHHOLD))
126 #define	QR_is_permanent(self)		(0 != (self->flags & FQR_HOLDPERMANENT))
127 #define	QR_synchronize_keys(self)	(0 != (self->flags & FQR_SYNCHRONIZEKEYS))
128 #define QR_get_fields(self)		(self->fields)
129 
130 
131 /*	These functions are for retrieving data from the qresult */
132 #define QR_get_value_backend(self, fieldno)	(self->tupleField[fieldno].value)
133 #define QR_get_value_backend_row(self, tupleno, fieldno) ((self->backend_tuples + (tupleno * self->num_fields))[fieldno].value)
134 #define QR_get_value_backend_text(self, tupleno, fieldno) QR_get_value_backend_row(self, tupleno, fieldno)
135 #define QR_get_value_backend_int(self, tupleno, fieldno, isNull) atoi(QR_get_value_backend_row(self, tupleno, fieldno))
136 
137 /*	These functions are used by both manual and backend results */
138 #define QR_NumResultCols(self)		(CI_get_num_fields(self->fields))
139 #define QR_NumPublicResultCols(self)	(QR_haskeyset(self) ? (CI_get_num_fields(self->fields) - self->num_key_fields) : CI_get_num_fields(self->fields))
140 #define QR_get_fieldname(self, fieldno_)	(CI_get_fieldname(self->fields, fieldno_))
141 #define QR_get_fieldsize(self, fieldno_)	(CI_get_fieldsize(self->fields, fieldno_))
142 #define QR_get_display_size(self, fieldno_) (CI_get_display_size(self->fields, fieldno_))
143 #define QR_get_atttypmod(self, fieldno_)	(CI_get_atttypmod(self->fields, fieldno_))
144 #define QR_get_field_type(self, fieldno_)	(CI_get_oid(self->fields, fieldno_))
145 #define QR_get_relid(self, fieldno_)	(CI_get_relid(self->fields, fieldno_))
146 #define QR_get_attid(self, fieldno_)	(CI_get_attid(self->fields, fieldno_))
147 
148 /*	These functions are used only for manual result sets */
149 #define QR_get_num_total_tuples(self)		(QR_once_reached_eof(self) ? (self->num_total_read + self->ad_count) : self->num_total_read)
150 #define QR_get_num_total_read(self)		(self->num_total_read)
151 #define QR_get_num_cached_tuples(self)		(self->num_cached_rows)
152 #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))
153 #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))
154 
155 /* status macros */
156 #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))
157 #define QR_command_maybe_successful(self) (self && !(self->rstatus == PORES_BAD_RESPONSE || self->rstatus == PORES_FATAL_ERROR || self->rstatus == PORES_NO_MEMORY_ERROR))
158 #define QR_command_nonfatal(self)	( self->rstatus == PORES_NONFATAL_ERROR)
159 #define QR_set_conn(self, conn_)			( self->conn = conn_ )
160 #define QR_set_rstatus(self, condition)		( self->rstatus = condition )
161 #define QR_set_sqlstatus(self, status)		strcpy(self->sqlstatus, status)
162 #define QR_set_messageref(self, m)	((self)->messageref = m)
163 #define QR_set_aborted(self, aborted_)		( self->aborted = aborted_)
164 #define QR_set_haskeyset(self)		(self->flags |= FQR_HASKEYSET)
165 #define QR_set_synchronize_keys(self)	(self->flags |= FQR_SYNCHRONIZEKEYS)
166 #define QR_set_no_cursor(self)		((self)->flags &= ~(FQR_WITHHOLD | FQR_HOLDPERMANENT), (self)->pstatus &= ~FQR_NEEDS_SURVIVAL_CHECK)
167 #define QR_set_withhold(self)		(self->flags |= FQR_WITHHOLD)
168 #define QR_set_permanent(self)		(self->flags |= FQR_HOLDPERMANENT)
169 #define	QR_set_reached_eof(self)	(self->pstatus |= FQR_REACHED_EOF)
170 #define QR_set_has_valid_base(self)	(self->pstatus |= FQR_HAS_VALID_BASE)
171 #define QR_set_no_valid_base(self)	(self->pstatus &= ~FQR_HAS_VALID_BASE)
172 #define QR_set_survival_check(self)	(self->pstatus |= FQR_NEEDS_SURVIVAL_CHECK)
173 #define QR_set_no_survival_check(self)	(self->pstatus &= ~FQR_NEEDS_SURVIVAL_CHECK)
174 #define	QR_inc_num_cache(self) \
175 do { \
176 	self->num_cached_rows++; \
177 	if (QR_haskeyset(self)) \
178 		self->num_cached_keys++; \
179 } while (0)
180 #define	QR_set_next_in_cache(self, number) \
181 do { \
182 	MYLOG(1, "set the number to " FORMAT_LEN " to read next\n", number); \
183 	self->fetch_number = number; \
184 } while (0)
185 #define	QR_inc_next_in_cache(self) \
186 do { \
187 	MYLOG(1, "increased the number " FORMAT_LEN, self->fetch_number); \
188 	self->fetch_number++; \
189 	MYLOG(1, "to " FORMAT_LEN " to next read\n", self->fetch_number); \
190 } while (0)
191 
192 #define	QR_concat(self, a)	((self)->lnext=(a))
193 #define	QR_detach(self)	((self)->lnext=NULL)
194 #define	QR_nextr(self)	((self)->lnext)
195 
196 #define QR_get_message(self)		((self)->message ? (self)->message : (self)->messageref)
197 #define QR_get_command(self)				(self->command)
198 #define QR_get_notice(self)				(self->notice)
199 #define QR_get_rstatus(self)				(self->rstatus)
200 #define QR_get_aborted(self)				(self->aborted)
201 #define QR_get_conn(self)				(self->conn)
202 #define QR_get_cursor(self)				(self->cursor_name)
203 #define QR_get_rowstart_in_cache(self)			(self->base)
204 #define QR_once_reached_eof(self)	((self->pstatus & FQR_REACHED_EOF) != 0)
205 #define	QR_has_valid_base(self)		(0 != (self->pstatus & FQR_HAS_VALID_BASE))
206 #define	QR_needs_survival_check(self)		(0 != (self->pstatus & FQR_NEEDS_SURVIVAL_CHECK))
207 
208 #define QR_aborted(self)		(!self || self->aborted)
209 #define QR_get_reqsize(self)		(self->rowset_size_include_ommitted)
210 
211 #define QR_stop_movement(self)		(self->move_direction = 0)
212 #define QR_is_moving(self)		(0 != self->move_direction)
213 #define QR_is_not_moving(self)		(0 == self->move_direction)
214 #define QR_set_move_forward(self)	(self->move_direction = 1)
215 #define QR_is_moving_forward(self)	(1 == self->move_direction)
216 #define QR_set_move_backward(self)	(self->move_direction = -1)
217 #define QR_is_moving_backward(self)	(-1 == self->move_direction)
218 #define QR_set_move_from_the_last(self)	(self->move_direction = 2)
219 #define QR_is_moving_from_the_last(self)	(2 == self->move_direction)
220 #define QR_is_moving_not_backward(self)	(0 < self->move_direction)
221 
222 /*	Core Functions */
223 QResultClass	*QR_Constructor(void);
224 void		QR_Destructor(QResultClass *self);
225 TupleField	*QR_AddNew(QResultClass *self);
226 int		QR_next_tuple(QResultClass *self, StatementClass *);
227 int			QR_close(QResultClass *self);
228 void		QR_on_close_cursor(QResultClass *self);
229 void		QR_close_result(QResultClass *self, BOOL destroy);
230 void		QR_reset_for_re_execute(QResultClass *self);
231 BOOL		QR_from_PGresult(QResultClass *self, StatementClass *stmt, ConnectionClass *conn, const char *cursor, PGresult **pgres);
232 void		QR_free_memory(QResultClass *self);
233 void		QR_set_command(QResultClass *self, const char *msg);
234 void		QR_set_message(QResultClass *self, const char *msg);
235 void		QR_add_message(QResultClass *self, const char *msg);
236 void		QR_set_notice(QResultClass *self, const char *msg);
237 void		QR_add_notice(QResultClass *self, const char *msg);
238 
239 void		QR_set_num_fields(QResultClass *self, int new_num_fields); /* catalog functions' result only */
240 void		QR_set_fields(QResultClass *self, ColumnInfoClass *);
241 
242 void		QR_set_num_cached_rows(QResultClass *, SQLLEN);
243 void		QR_set_rowstart_in_cache(QResultClass *, SQLLEN);
244 void		QR_inc_rowstart_in_cache(QResultClass *self, SQLLEN base_inc);
245 void		QR_set_cache_size(QResultClass *self, SQLLEN cache_size);
246 void		QR_set_reqsize(QResultClass *self, Int4 reqsize);
247 void		QR_set_position(QResultClass *self, SQLLEN pos);
248 void		QR_set_cursor(QResultClass *self, const char *name);
249 SQLLEN		getNthValid(const QResultClass *self, SQLLEN sta, UWORD orientation, SQLULEN nth, SQLLEN *nearest);
250 SQLLEN		QR_move_cursor_to_last(QResultClass *self, StatementClass *stmt);
251 BOOL		QR_get_last_bookmark(const QResultClass *self, Int4 index, KeySet *keyset);
252 int			QR_search_by_fieldname(const QResultClass *self, const char *name);
253 
254 #define QR_MALLOC_return_with_error(t, tp, s, a, m, r) \
255 do { \
256 	if (t = (tp *) malloc(s), NULL == t) \
257 	{ \
258 		QR_set_rstatus(a, PORES_NO_MEMORY_ERROR); \
259 qlog("QR_MALLOC_error\n"); \
260 		QR_free_memory(a); \
261 		QR_set_messageref(a, m); \
262 		return r; \
263 	} \
264 } while (0)
265 #define QR_REALLOC_return_with_error(t, tp, s, a, m, r) \
266 do { \
267 	tp *tmp; \
268 	if (tmp = (tp *) realloc(t, s), NULL == tmp) \
269 	{ \
270 		QR_set_rstatus(a, PORES_NO_MEMORY_ERROR); \
271 qlog("QR_REALLOC_error\n"); \
272 		QR_free_memory(a); \
273 		QR_set_messageref(a, m); \
274 		return r; \
275 	} \
276 	t = tmp; \
277 } while (0)
278 #define	QR_REALLOC_gexit_with_error(t, tp, s, a, m, r) \
279 do { \
280 	tp *tmp; \
281 	if (tmp = (tp *) realloc(t, s), NULL == tmp) \
282 	{ \
283 		QR_set_rstatus(a, PORES_NO_MEMORY_ERROR); \
284 		QR_free_memory(a); \
285 		QR_set_messageref(a, m); \
286 		r; \
287 		goto cleanup; \
288 	} \
289 	t = tmp; \
290 } while (0)
291 
292 #ifdef	__cplusplus
293 }
294 #endif
295 #endif /* __QRESULT_H__ */
296