1 /* File:			connection.h
2  *
3  * Description:		See "connection.c"
4  *
5  * Comments:		See "readme.txt" for copyright and license information.
6  *
7  */
8 
9 #ifndef __CONNECTION_H__
10 #define __CONNECTION_H__
11 
12 #include "psqlodbc.h"
13 #include <libpq-fe.h>
14 #include "pqexpbuffer.h"
15 
16 #include <time.h>
17 
18 #include <stdlib.h>
19 #include <string.h>
20 #include "descriptor.h"
21 
22 #if defined (POSIX_MULTITHREAD_SUPPORT)
23 #include <pthread.h>
24 #endif
25 
26 #ifdef	__cplusplus
27 extern "C" {
28 #endif
29 typedef enum
30 {
31 	CONN_NOT_CONNECTED,	/* Connection has not been established */
32 	CONN_CONNECTED,		/* Connection is up and has been established */
33 	CONN_DOWN,		/* Connection is broken */
34 	CONN_EXECUTING		/* the connection is currently executing a
35 				 * statement */
36 } CONN_Status;
37 
38 /*	These errors have general sql error state */
39 #define CONNECTION_SERVER_NOT_REACHED				101
40 #define CONNECTION_MSG_TOO_LONG					103
41 #define CONNECTION_COULD_NOT_SEND				104
42 #define CONNECTION_NO_SUCH_DATABASE				105
43 #define CONNECTION_BACKEND_CRAZY				106
44 #define CONNECTION_NO_RESPONSE					107
45 #define CONNECTION_SERVER_REPORTED_SEVERITY_FATAL		108
46 #define CONNECTION_COULD_NOT_RECEIVE				109
47 #define CONNECTION_SERVER_REPORTED_SEVERITY_ERROR		110
48 #define CONNECTION_NEED_PASSWORD				112
49 #define CONNECTION_COMMUNICATION_ERROR				113
50 
51 #define CONN_ERROR_IGNORED						(-3)
52 #define CONN_TRUNCATED							(-2)
53 #define CONN_OPTION_VALUE_CHANGED					(-1)
54 /*	These errors correspond to specific SQL states */
55 #define CONN_INIREAD_ERROR						201
56 #define CONN_OPENDB_ERROR						202
57 #define CONN_STMT_ALLOC_ERROR						203
58 #define CONN_IN_USE							204
59 #define CONN_UNSUPPORTED_OPTION						205
60 /* Used by SetConnectoption to indicate unsupported options */
61 #define CONN_INVALID_ARGUMENT_NO					206
62 /* SetConnectOption: corresponds to ODBC--"S1009" */
63 #define CONN_TRANSACT_IN_PROGRES					207
64 #define CONN_NO_MEMORY_ERROR						208
65 #define CONN_NOT_IMPLEMENTED_ERROR					209
66 #define CONN_INVALID_AUTHENTICATION					210
67 #define CONN_AUTH_TYPE_UNSUPPORTED					211
68 #define CONN_UNABLE_TO_LOAD_DLL						212
69 #define CONN_ILLEGAL_TRANSACT_STATE					213
70 #define CONN_VALUE_OUT_OF_RANGE						214
71 
72 #define CONN_OPTION_NOT_FOR_THE_DRIVER					216
73 #define CONN_EXEC_ERROR							217
74 
75 /* Conn_status defines */
76 #define CONN_IN_AUTOCOMMIT		1L
77 #define CONN_IN_TRANSACTION		(1L<<1)
78 #define CONN_IN_MANUAL_TRANSACTION	(1L<<2)
79 #define CONN_IN_ERROR_BEFORE_IDLE	(1L<<3)
80 
81 /* not connected yet || already disconnected */
82 #define	CC_not_connected(x)	(!(x) || CONN_DOWN == (x)->status || CONN_NOT_CONNECTED == (x)->status)
83 
84 /* AutoCommit functions */
85 #define CC_is_in_autocommit(x)		(x->transact_status & CONN_IN_AUTOCOMMIT)
86 #define CC_does_autocommit(x) (CONN_IN_AUTOCOMMIT == ((x)->transact_status & (CONN_IN_AUTOCOMMIT | CONN_IN_MANUAL_TRANSACTION)))
87 #define CC_loves_visible_trans(x) ((0 == ((x)->transact_status & CONN_IN_AUTOCOMMIT)) || (0 != ((x)->transact_status & CONN_IN_MANUAL_TRANSACTION)))
88 
89 /* Transaction in/not functions */
90 #define CC_set_in_trans(x)	(x->transact_status |= CONN_IN_TRANSACTION)
91 #define CC_set_no_trans(x)	(x->transact_status &= ~(CONN_IN_TRANSACTION | CONN_IN_ERROR_BEFORE_IDLE))
92 #define CC_is_in_trans(x)	(0 != (x->transact_status & CONN_IN_TRANSACTION))
93 
94 /* Manual transaction in/not functions */
95 #define CC_set_in_manual_trans(x) (x->transact_status |= CONN_IN_MANUAL_TRANSACTION)
96 #define CC_set_no_manual_trans(x) (x->transact_status &= ~CONN_IN_MANUAL_TRANSACTION)
97 #define CC_is_in_manual_trans(x) (0 != (x->transact_status & CONN_IN_MANUAL_TRANSACTION))
98 
99 /* Error waiting for ROLLBACK */
100 #define CC_set_in_error_trans(x) (x->transact_status |= CONN_IN_ERROR_BEFORE_IDLE)
101 #define CC_set_no_error_trans(x) (x->transact_status &= ~CONN_IN_ERROR_BEFORE_IDLE)
102 #define CC_is_in_error_trans(x) (x->transact_status & CONN_IN_ERROR_BEFORE_IDLE)
103 
104 #define CC_get_errornumber(x)	(x->__error_number)
105 #define CC_get_errormsg(x)	(x->__error_message)
106 #define CC_set_errornumber(x, n)	(x->__error_number = n)
107 
108 /* Unicode handling */
109 #define	CONN_UNICODE_DRIVER	(1L)
110 #define	CONN_ANSI_APP		(1L << 1)
111 #define	CONN_DISALLOW_WCHAR	(1L << 2)
112 #define	CC_set_in_unicode_driver(x)	(x->unicode |= CONN_UNICODE_DRIVER)
113 #define	CC_set_in_ansi_app(x)	(x->unicode |= CONN_ANSI_APP)
114 #define	CC_is_in_unicode_driver(x)	(0 != (x->unicode & CONN_UNICODE_DRIVER))
115 #define	CC_is_in_ansi_app(x)	(0 != (x->unicode & CONN_ANSI_APP))
116 #define	CC_is_in_global_trans(x)	(NULL != (x)->asdum)
117 #define	ALLOW_WCHAR(x)	(0 != (x->unicode & CONN_UNICODE_DRIVER) && 0 == (x->unicode & CONN_DISALLOW_WCHAR))
118 
119 #define CC_MALLOC_return_with_error(t, tp, s, x, m, ret) \
120 do { \
121 	if (t = malloc(s), NULL == t) \
122 	{ \
123 		CC_set_error(x, CONN_NO_MEMORY_ERROR, m, ""); \
124 		return ret; \
125 	} \
126 } while (0)
127 #define CC_REALLOC_return_with_error(t, tp, s, x, m, ret) \
128 do { \
129 	tp *tmp; \
130 	if (tmp = (tp *) realloc(t, s), NULL == tmp) \
131 	{ \
132 		CC_set_error(x, CONN_NO_MEMORY_ERROR, m, ""); \
133 		return ret; \
134 	} \
135 	t = tmp; \
136 } while (0)
137 
138 /* For Multi-thread */
139 #if defined(WIN_MULTITHREAD_SUPPORT)
140 #define INIT_CONN_CS(x)		InitializeCriticalSection(&((x)->cs))
141 #define INIT_CONNLOCK(x)	InitializeCriticalSection(&((x)->slock))
142 #define ENTER_CONN_CS(x)	EnterCriticalSection(&((x)->cs))
143 #define CONNLOCK_ACQUIRE(x)	EnterCriticalSection(&((x)->slock))
144 #define TRY_ENTER_CONN_CS(x)	TryEnterCriticalSection(&((x)->cs))
145 #define ENTER_INNER_CONN_CS(x, entered) \
146 do { \
147 	EnterCriticalSection(&((x)->cs)); \
148 	entered++; \
149 } while (0)
150 #define LEAVE_CONN_CS(x)	LeaveCriticalSection(&((x)->cs))
151 #define CONNLOCK_RELEASE(x)	LeaveCriticalSection(&((x)->slock))
152 #define DELETE_CONN_CS(x)	DeleteCriticalSection(&((x)->cs))
153 #define DELETE_CONNLOCK(x)	DeleteCriticalSection(&((x)->slock))
154 #elif defined(POSIX_THREADMUTEX_SUPPORT)
155 #define INIT_CONN_CS(x)		pthread_mutex_init(&((x)->cs), getMutexAttr())
156 #define INIT_CONNLOCK(x)	pthread_mutex_init(&((x)->slock), getMutexAttr())
157 #define ENTER_CONN_CS(x)	pthread_mutex_lock(&((x)->cs))
158 #define CONNLOCK_ACQUIRE(x)		pthread_mutex_lock(&((x)->slock))
159 #define TRY_ENTER_CONN_CS(x)	(0 == pthread_mutex_trylock(&((x)->cs)))
160 #define ENTER_INNER_CONN_CS(x, entered) \
161 do { \
162 	if (getMutexAttr()) \
163 	{ \
164 		if (pthread_mutex_lock(&((x)->cs)) == 0) \
165 			entered++; \
166 	} \
167 } while (0)
168 #define LEAVE_CONN_CS(x)	pthread_mutex_unlock(&((x)->cs))
169 #define CONNLOCK_RELEASE(x) 	pthread_mutex_unlock(&((x)->slock))
170 #define DELETE_CONN_CS(x)	pthread_mutex_destroy(&((x)->cs))
171 #define DELETE_CONNLOCK(x)	pthread_mutex_destroy(&((x)->slock))
172 #else
173 #define INIT_CONN_CS(x)
174 #define INIT_CONNLOCK(x)
175 #define TRY_ENTER_CONN_CS(x)	(1)
176 #define ENTER_CONN_CS(x)
177 #define CONNLOCK_ACQUIRE(x)
178 #define ENTER_INNER_CONN_CS(x, entered)
179 #define LEAVE_CONN_CS(x)
180 #define CONNLOCK_RELEASE(x)
181 #define DELETE_CONN_CS(x)
182 #define DELETE_CONNLOCK(x)
183 #endif /* WIN_MULTITHREAD_SUPPORT */
184 
185 #define	LEAVE_INNER_CONN_CS(entered, conn) \
186 do { \
187 	if (entered > 0) \
188 	{ \
189 		LEAVE_CONN_CS(conn); \
190 		entered--; \
191 	} \
192 } while (0)
193 #define CLEANUP_FUNC_CONN_CS(entered, conn) \
194 do { \
195 	while (entered > 0) \
196 	{ \
197 		LEAVE_CONN_CS(conn); \
198 		entered--; \
199 	} \
200 } while (0)
201 
202 /*
203  *	Macros to compare the server's version with a specified version
204  *		1st parameter: pointer to a ConnectionClass object
205  *		2nd parameter: major version number
206  *		3rd parameter: minor version number
207  */
208 #define SERVER_VERSION_GT(conn, major, minor) \
209 	((conn)->pg_version_major > major || \
210 	((conn)->pg_version_major == major && (conn)->pg_version_minor > minor))
211 #define SERVER_VERSION_GE(conn, major, minor) \
212 	((conn)->pg_version_major > major || \
213 	((conn)->pg_version_major == major && (conn)->pg_version_minor >= minor))
214 #define SERVER_VERSION_EQ(conn, major, minor) \
215 	((conn)->pg_version_major == major && (conn)->pg_version_minor == minor)
216 #define STRING_AFTER_DOT(string)	(strchr(#string, '.') + 1)
217 
218 /*
219  *	Simplified macros to compare the server's version with a
220  *		specified version
221  *	Note: Never pass a variable as the second parameter.
222  *		  It must be a decimal constant of the form %d.%d .
223  */
224 #define PG_VERSION_GT(conn, ver) \
225  (SERVER_VERSION_GT(conn, (int) ver, atoi(STRING_AFTER_DOT(ver))))
226 #define PG_VERSION_GE(conn, ver) \
227  (SERVER_VERSION_GE(conn, (int) ver, atoi(STRING_AFTER_DOT(ver))))
228 #define PG_VERSION_EQ(conn, ver) \
229  (SERVER_VERSION_EQ(conn, (int) ver, atoi(STRING_AFTER_DOT(ver))))
230 #define PG_VERSION_LE(conn, ver) (! PG_VERSION_GT(conn, ver))
231 #define PG_VERSION_LT(conn, ver) (! PG_VERSION_GE(conn, ver))
232 
233 /*	This is used to store cached table information in the connection */
234 struct col_info
235 {
236 	Int2		refcnt;
237 	QResultClass	*result;
238 	pgNAME		schema_name;
239 	pgNAME		table_name;
240 	OID		table_oid;
241 	int		table_info;
242 	time_t		acc_time;
243 };
244 enum {
245 	TBINFO_HASOIDS	 = 1L
246 	,TBINFO_HASSUBCLASS = (1L << 1)
247 };
248 #define free_col_info_contents(coli) \
249 { \
250 	if (NULL != coli->result) \
251 		QR_Destructor(coli->result); \
252 	coli->result = NULL; \
253 	NULL_THE_NAME(coli->schema_name); \
254 	NULL_THE_NAME(coli->table_name); \
255 	coli->table_oid = 0; \
256 	coli->refcnt = 0; \
257 	coli->acc_time = 0; \
258 }
259 #define col_info_initialize(coli) (memset(coli, 0, sizeof(COL_INFO)))
260 
261  /* Translation DLL entry points */
262 #ifdef WIN32
263 #define DLLHANDLE HINSTANCE
264 #else
265 #define WINAPI CALLBACK
266 #define DLLHANDLE void *
267 #define HINSTANCE void *
268 #endif
269 
270 typedef BOOL (WINAPI * DataSourceToDriverProc) (UDWORD, SWORD, PTR,
271 		SDWORD, PTR, SDWORD, SDWORD *, UCHAR *, SWORD,
272 		SWORD *);
273 typedef BOOL (WINAPI * DriverToDataSourceProc) (UDWORD, SWORD, PTR,
274 		SDWORD, PTR, SDWORD, SDWORD *, UCHAR *, SWORD,
275 		SWORD *);
276 
277 /*******	The Connection handle	************/
278 struct ConnectionClass_
279 {
280 	HENV		henv;		/* environment this connection was
281 					 * created on */
282 	SQLUINTEGER	login_timeout;
283 	signed char	autocommit_public;
284 	StatementOptions stmtOptions;
285 	ARDFields	ardOptions;
286 	APDFields	apdOptions;
287 	char		*__error_message;
288 	int		__error_number;
289 	char		sqlstate[8];
290 	CONN_Status	status;
291 	ConnInfo	connInfo;
292 	StatementClass	**stmts;
293 	Int2		num_stmts;
294 	Int2		ncursors;
295 	PGconn	   *pqconn;
296 	Int4		lobj_type;
297 	Int2		coli_allocated;
298 	Int2		ntables;
299 	COL_INFO	**col_info;
300 	long		translation_option;
301 	HINSTANCE	translation_handle;
302 	DataSourceToDriverProc DataSourceToDriver;
303 	DriverToDataSourceProc DriverToDataSource;
304 	char		transact_status;	/* Is a transaction is currently
305 						 * in progress */
306 	char		pg_version[MAX_INFO_STRING];	/* Version of PostgreSQL
307 							 * we're connected to -
308 							 * DJP 25-1-2001 */
309 	Int2		pg_version_major;
310 	Int2		pg_version_minor;
311 	char		ms_jet;
312 	char		unicode;
313 	char		result_uncommitted;
314 	char		lo_is_domain;
315 	char		current_schema_valid;	/* is current_schema valid? TRUE when
316 						 * current_schema == NULL means it's
317 						 * really NULL, while FALSE means it's
318 						 * unknown */
319 	unsigned char	on_commit_in_progress;
320 	/* for per statement rollback */
321 	char		internal_svp;		/* is set? */
322 	char		internal_op;		/* operation being executed as to internal savepoint */
323 	unsigned char	rbonerr;
324 	unsigned char	opt_in_progress;
325 	unsigned char	opt_previous;
326 
327 	char		*original_client_encoding;
328 	char		*locale_encoding;
329 	char		*server_encoding;
330 	Int2		ccsc;
331 	Int2		mb_maxbyte_per_char;
332 	SQLUINTEGER	isolation;		/* isolation level initially unknown */
333 	SQLUINTEGER	server_isolation;	/* isolation at server initially unknown */
334 	char		*current_schema;
335 	StatementClass *unnamed_prepared_stmt;
336 	Int2		max_identifier_length;
337 	Int2		num_discardp;
338 	char		**discardp;
339 	int		num_descs;
340 	SQLUINTEGER	default_isolation;	/* server's default isolation initially unkown */
341 	DescriptorClass	**descs;
342 	pgNAME		schemaIns;
343 	pgNAME		tableIns;
344 	SQLULEN		stmt_timeout_in_effect;
345 #if defined(WIN_MULTITHREAD_SUPPORT)
346 	CRITICAL_SECTION	cs;
347 	CRITICAL_SECTION	slock;
348 #elif defined(POSIX_THREADMUTEX_SUPPORT)
349 	pthread_mutex_t		cs;
350 	pthread_mutex_t		slock;
351 #endif /* WIN_MULTITHREAD_SUPPORT */
352 #ifdef	_HANDLE_ENLIST_IN_DTC_
353 	UInt4		gTranInfo;
354 	void		*asdum;
355 #endif /* _HANDLE_ENLIST_IN_DTC_ */
356 };
357 
358 
359 /* Accessor functions */
360 #define CC_get_env(x)				((x)->henv)
361 #define CC_get_database(x)			(x->connInfo.database)
362 #define CC_get_server(x)			(x->connInfo.server)
363 #define CC_get_DSN(x)				(x->connInfo.dsn)
364 #define CC_get_username(x)			(x->connInfo.username)
365 #define CC_is_onlyread(x)			(x->connInfo.onlyread[0] == '1')
366 #define CC_fake_mss(x)	(/* 0 != (x)->ms_jet && */ 0 < (x)->connInfo.fake_mss)
367 #define CC_accessible_only(x)	(0 < (x)->connInfo.accessible_only)
368 #define CC_default_is_c(x)	(CC_is_in_ansi_app(x) || x->ms_jet /* not only */ || TRUE /* but for any other ? */)
369 
370 #ifdef	_HANDLE_ENLIST_IN_DTC_
371 enum {
372 	DTC_IN_PROGRESS	= 1L
373 	,DTC_ENLISTED	= (1L << 1)
374 	,DTC_REQUEST_EXECUTING	= (1L << 2)
375 	,DTC_ISOLATED	= (1L << 3)
376 	,DTC_PREPARE_REQUESTED	= (1L << 4)
377 };
378 #define	CC_set_dtc_clear(x)	((x)->gTranInfo = 0)
379 #define	CC_set_dtc_enlisted(x)	((x)->gTranInfo |= (DTC_IN_PROGRESS | DTC_ENLISTED))
380 #define	CC_no_dtc_enlisted(x)	((x)->gTranInfo &= (~DTC_ENLISTED))
381 #define	CC_is_dtc_enlisted(x)	(0 != ((x)->gTranInfo & DTC_ENLISTED))
382 #define	CC_set_dtc_executing(x)	((x)->gTranInfo |= DTC_REQUEST_EXECUTING)
383 #define	CC_no_dtc_executing(x)	((x)->gTranInfo &= (~DTC_REQUEST_EXECUTING))
384 #define	CC_is_dtc_executing(x)	(0 != ((x)->gTranInfo & DTC_REQUEST_EXECUTING))
385 #define	CC_set_dtc_prepareRequested(x)	((x)->gTranInfo |= (DTC_PREPARE_REQUESTED))
386 #define	CC_no_dtc_prepareRequested(x)	((x)->gTranInfo &= (~DTC_PREPARE_REQUESTED))
387 #define	CC_is_dtc_prepareRequested(x)	(0 != ((x)->gTranInfo & DTC_PREPARE_REQUESTED))
388 #define	CC_is_dtc_executing(x)	(0 != ((x)->gTranInfo & DTC_REQUEST_EXECUTING))
389 #define	CC_set_dtc_isolated(x)	((x)->gTranInfo |= DTC_ISOLATED)
390 #define	CC_is_idle_in_global_transaction(x)	(0 != ((x)->gTranInfo & DTC_PREPARE_REQUESTED) || (x)->gTranInfo == DTC_IN_PROGRESS)
391 #endif /* _HANDLE_ENLIST_IN_DTC_ */
392 /* statement callback */
393 #define CC_start_stmt(a)        ((a)->rbonerr = 0)
394 #define CC_start_tc_stmt(a)     ((a)->rbonerr = (1L << 1))
395 #define CC_is_tc_stmt(a)        (((a)->rbonerr & (1L << 1)) != 0)
396 #define CC_start_rb_stmt(a)     ((a)->rbonerr = (1L << 2))
397 #define CC_is_rb_stmt(a)        (((a)->rbonerr & (1L << 2)) != 0)
398 #define CC_set_accessed_db(a)   ((a)->rbonerr |= (1L << 3))
399 #define CC_accessed_db(a)       (((a)->rbonerr & (1L << 3)) != 0)
400 #define CC_start_rbpoint(a)     ((a)->rbonerr |= (1L << 4), (a)->internal_svp = 1)
401 #define CC_started_rbpoint(a)   (((a)->rbonerr & (1L << 4)) != 0)
402 
403 /*	prototypes */
404 ConnectionClass *CC_Constructor(void);
405 char		CC_Destructor(ConnectionClass *self);
406 int		CC_cursor_count(ConnectionClass *self);
407 char		CC_cleanup(ConnectionClass *self, BOOL keepCommunication);
408 char		CC_begin(ConnectionClass *self);
409 char		CC_commit(ConnectionClass *self);
410 char		CC_abort(ConnectionClass *self);
411 char		CC_set_autocommit(ConnectionClass *self, BOOL on);
412 int		CC_set_translation(ConnectionClass *self);
413 char		CC_connect(ConnectionClass *self, char *salt);
414 char		CC_add_statement(ConnectionClass *self, StatementClass *stmt);
415 char		CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
416 ;
417 char		CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc);
418 char		CC_remove_descriptor(ConnectionClass *self, DescriptorClass *desc);
419 void		CC_set_error(ConnectionClass *self, int number, const char *message, const char *func);
420 void		CC_set_errormsg(ConnectionClass *self, const char *message);
421 char		CC_get_error(ConnectionClass *self, int *number, char **message);
422 QResultHold CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt, const char *appendq);
423 #define CC_send_query(self, query, qi, flag, stmt) CC_send_query_append(self, query, qi, flag, stmt, NULL).first
424 void		handle_pgres_error(ConnectionClass *self, const PGresult *pgres,
425 				   const char *comment,
426 				   QResultClass *res, BOOL error_not_a_notice);
427 void		CC_clear_error(ConnectionClass *self);
428 int		CC_send_function(ConnectionClass *conn, const char *fn_name, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
429 char		CC_send_settings(ConnectionClass *self, const char *set_query);
430 void		CC_initialize_pg_version(ConnectionClass *conn);
431 void		CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
432 int			CC_send_cancel_request(const ConnectionClass *conn);
433 void		CC_on_commit(ConnectionClass *conn);
434 void		CC_on_abort(ConnectionClass *conn, unsigned int opt);
435 void		CC_on_abort_partial(ConnectionClass *conn);
436 void		ProcessRollback(ConnectionClass *conn, BOOL undo, BOOL partial);
437 const char	*CC_get_current_schema(ConnectionClass *conn);
438 int             CC_mark_a_object_to_discard(ConnectionClass *conn, int type, const char *plan);
439 int             CC_discard_marked_objects(ConnectionClass *conn);
440 
441 int		CC_get_max_idlen(ConnectionClass *self);
442 char	CC_get_escape(const ConnectionClass *self);
443 char *		identifierEscape(const SQLCHAR *src, SQLLEN srclen, const ConnectionClass *conn, char *buf, size_t bufsize, BOOL double_quote);
444 int		findIdentifier(const UCHAR *str, int ccsc, const UCHAR **next_token);
445 int		eatTableIdentifiers(const UCHAR *str, int ccsc, pgNAME *table, pgNAME *schema);
446 
447 
448 const		char *CurrCat(const ConnectionClass *self);
449 const		char *CurrCatString(const ConnectionClass *self);
450 SQLUINTEGER	CC_get_isolation(ConnectionClass *self);
451 
452 SQLCHAR	*make_lstring_ifneeded(ConnectionClass *, const SQLCHAR *s, ssize_t len, BOOL);
453 
454 #define	TABLE_IS_VALID(tbname, tblen)	((tbname) && (tblen > 0 || SQL_NTS == tblen))
455 int	schema_str(char *buf, int buflen, const SQLCHAR *s, SQLLEN len, BOOL table_is_valid, ConnectionClass *conn);
456 char	*schema_strcat(char *buf, int buflen, const char *fmt, const SQLCHAR *s, SQLLEN len,
457 		BOOL table_is_valid, ConnectionClass *conn);
458 char	*schema_strcat1(char *buf, int buflen, const char *fmt, const char *s1,
459 				const char *s,
460 				const SQLCHAR *, int, ConnectionClass *conn);
461 
462 void	schema_appendPQExpBuffer(PQExpBufferData *buf, const char *fmt, const SQLCHAR *s, SQLLEN len,
463 		BOOL table_is_valid, ConnectionClass *conn);
464 void	schema_appendPQExpBuffer1(PQExpBufferData *buf, const char *fmt, const char *s1, const char *s,
465 				BOOL table_is_valid, ConnectionClass *conn);
466 
467 void	CC_examine_global_transaction(ConnectionClass *self);
468 
469 
470 BOOL CC_set_transact(ConnectionClass *self, UInt4 isolation);
471 int CC_send_client_encoding(ConnectionClass *self, const char *encoding);
472 
473 /* CC_send_query options */
474 enum {
475 	IGNORE_ABORT_ON_CONN	= 1L /* not set the error result even when  */
476 	,CREATE_KEYSET		= (1L << 1) /* create keyset for updatable cursors */
477 	,GO_INTO_TRANSACTION	= (1L << 2) /* issue BEGIN in advance */
478 	,ROLLBACK_ON_ERROR	= (1L << 3) /* rollback the query when an error occurs */
479 	,END_WITH_COMMIT	= (1L << 4) /* the query ends with COMMIT command */
480 	,READ_ONLY_QUERY	= (1L << 5) /* the query is read-only */
481 };
482 /* CC_on_abort options */
483 #define	NO_TRANS		1L
484 #define	CONN_DEAD		(1L << 1) /* connection is no longer valid */
485 
486 /*
487  * This is a libpq notice receiver callback, for handling incoming NOTICE
488  * messages while processing a query.
489  */
490 typedef struct
491 {
492 	ConnectionClass *conn;
493 	const char *comment;
494 	QResultClass *res;
495 	StatementClass *stmt;
496 } notice_receiver_arg;
497 
498 void receive_libpq_notice(void *arg, const PGresult *pgres);
499 
500 /*
501  *	internal savepoint related
502  */
503 
504 #define	_RELEASE_INTERNAL_SAVEPOINT
505 
506 /*      Internal rollback */
507 enum {
508 	PER_STATEMENT_ROLLBACK = 1
509 	,PER_QUERY_ROLLBACK
510 };
511 int CC_internal_rollback(ConnectionClass *, int rollback_type, BOOL ignore_abort);
512 
513 /*     Commands generated */
514 enum {
515 	INTERNAL_SAVEPOINT_OPERATION = 1
516 	,INTERNAL_ROLLBACK_OPERATION
517 };
518 int	GenerateSvpCommand(ConnectionClass *conn, int type, char *cmd, int bufsize);
519 
520 /*      Operations in progress */
521 enum {
522         SAVEPOINT_IN_PROGRESS = 1
523         ,PREPEND_IN_PROGRESS
524 };
525 /*      StatementSvp entry option */
526 enum {
527         SVPOPT_RDONLY = 1L
528         ,SVPOPT_REDUCE_ROUNDTRIP = (1L << 1)
529 };
530 #define	INIT_SVPOPT	(SVPOPT_RDONLY)
531 #define CC_svp_init(a) ((a)->internal_svp = (a)->internal_op = 0, (a)->opt_in_progress = (a)->opt_previous = INIT_SVPOPT)
532 #define CC_init_opt_in_progress(a) ((a)->opt_in_progress = INIT_SVPOPT)
533 #define CC_init_opt_previous(a) ((a)->opt_previous = INIT_SVPOPT)
534 
535 #ifdef	__cplusplus
536 }
537 #endif
538 #endif /* __CONNECTION_H__ */
539