1 /*------
2  * Module:			connection.c
3  *
4  * Description:		This module contains routines related to
5  *					connecting to and disconnecting from the Postgres DBMS.
6  *
7  * Classes:			ConnectionClass (Functions prefix: "CC_")
8  *
9  * API functions:	SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect,
10  *					SQLBrowseConnect(NI)
11  *
12  * Comments:		See "readme.txt" for copyright and license information.
13  *-------
14  */
15 /* Multibyte support	Eiji Tokuya 2001-03-15 */
16 
17 /*	TryEnterCritiaclSection needs the following #define */
18 #ifndef	_WIN32_WINNT
19 #define	_WIN32_WINNT	0x0400
20 #endif /* _WIN32_WINNT */
21 
22 #include "connection.h"
23 
24 #include "misc.h"
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 
30 /* for htonl */
31 #ifdef WIN32
32 #include <Winsock2.h>
33 #else
34 #include <arpa/inet.h>
35 #endif
36 
37 #include "environ.h"
38 #include "statement.h"
39 #include "qresult.h"
40 #include "lobj.h"
41 #include "dlg_specific.h"
42 #include "loadlib.h"
43 
44 #include "multibyte.h"
45 
46 #include "pgapifunc.h"
47 
48 #define	SAFE_STR(s)	(NULL != (s) ? (s) : "(null)")
49 
50 #define STMT_INCREMENT 16		/* how many statement holders to allocate
51 								 * at a time */
52 
53 static SQLRETURN CC_lookup_lo(ConnectionClass *self);
54 static int  CC_close_eof_cursors(ConnectionClass *self);
55 
56 static void LIBPQ_update_transaction_status(ConnectionClass *self);
57 
58 
CC_set_error_if_not_set(ConnectionClass * self,int errornumber,const char * errormsg,const char * func)59 static void CC_set_error_if_not_set(ConnectionClass *self, int errornumber, const char *errormsg, const char *func)
60 {
61 	int	errornum = CC_get_errornumber(self);
62 	const char *errmsg = CC_get_errormsg(self);
63 
64 	if (errornumber == 0)
65 		return;
66 	if (errornumber > 0)
67 	{
68 		if (errornum <= 0)
69 			CC_set_error(self, errornumber, errormsg, func);
70 		else if (!errmsg)
71 			CC_set_errormsg(self, errormsg);
72 	}
73 	else if (errornum == 0)
74 		CC_set_error(self, errornumber, errormsg, func);
75 	else if (errornum < 0 && !errmsg)
76 		CC_set_errormsg(self, errormsg);
77 }
78 
79 RETCODE		SQL_API
PGAPI_AllocConnect(HENV henv,HDBC * phdbc)80 PGAPI_AllocConnect(HENV henv,
81 				   HDBC * phdbc)
82 {
83 	EnvironmentClass *env = (EnvironmentClass *) henv;
84 	ConnectionClass *conn;
85 	CSTR func = "PGAPI_AllocConnect";
86 
87 	MYLOG(0, "entering...\n");
88 
89 	conn = CC_Constructor();
90 	MYLOG(0, "**** henv = %p, conn = %p\n", henv, conn);
91 
92 	if (!conn)
93 	{
94 		env->errormsg = "Couldn't allocate memory for Connection object.";
95 		env->errornumber = ENV_ALLOC_ERROR;
96 		*phdbc = SQL_NULL_HDBC;
97 		EN_log_error(func, "", env);
98 		return SQL_ERROR;
99 	}
100 
101 	if (!EN_add_connection(env, conn))
102 	{
103 		env->errormsg = "Maximum number of connections exceeded.";
104 		env->errornumber = ENV_ALLOC_ERROR;
105 		CC_Destructor(conn);
106 		*phdbc = SQL_NULL_HDBC;
107 		EN_log_error(func, "", env);
108 		return SQL_ERROR;
109 	}
110 
111 	if (phdbc)
112 		*phdbc = (HDBC) conn;
113 
114 	return SQL_SUCCESS;
115 }
116 
117 
118 RETCODE		SQL_API
PGAPI_Connect(HDBC hdbc,const SQLCHAR * szDSN,SQLSMALLINT cbDSN,const SQLCHAR * szUID,SQLSMALLINT cbUID,const SQLCHAR * szAuthStr,SQLSMALLINT cbAuthStr)119 PGAPI_Connect(HDBC hdbc,
120 			  const SQLCHAR * szDSN,
121 			  SQLSMALLINT cbDSN,
122 			  const SQLCHAR * szUID,
123 			  SQLSMALLINT cbUID,
124 			  const SQLCHAR * szAuthStr,
125 			  SQLSMALLINT cbAuthStr)
126 {
127 	ConnectionClass *conn = (ConnectionClass *) hdbc;
128 	ConnInfo   *ci;
129 	CSTR func = "PGAPI_Connect";
130 	RETCODE	ret = SQL_SUCCESS;
131 	char	fchar, *tmpstr;
132 
133 	MYLOG(0, "entering..cbDSN=%hi.\n", cbDSN);
134 
135 	if (!conn)
136 	{
137 		CC_log_error(func, "", NULL);
138 		return SQL_INVALID_HANDLE;
139 	}
140 
141 	ci = &conn->connInfo;
142 	CC_conninfo_init(ci, INIT_GLOBALS);
143 
144 	make_string(szDSN, cbDSN, ci->dsn, sizeof(ci->dsn));
145 
146 	/* get the values for the DSN from the registry */
147 	getDSNinfo(ci, NULL);
148 
149 	logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
150 	/* initialize pg_version from connInfo.protocol    */
151 	CC_initialize_pg_version(conn);
152 
153 	/*
154 	 * override values from DSN info with UID and authStr(pwd) This only
155 	 * occurs if the values are actually there.
156 	 */
157 	fchar = ci->username[0]; /* save the first byte */
158 	make_string(szUID, cbUID, ci->username, sizeof(ci->username));
159 	if ('\0' == ci->username[0]) /* an empty string is specified */
160 		ci->username[0] = fchar; /* restore the original username */
161 	tmpstr = make_string(szAuthStr, cbAuthStr, NULL, 0);
162 	if (tmpstr)
163 	{
164 		if (tmpstr[0]) /* non-empty string is specified */
165 			STR_TO_NAME(ci->password, tmpstr);
166 		free(tmpstr);
167 	}
168 
169 	MYLOG(0, "conn = %p (DSN='%s', UID='%s', PWD='%s')\n", conn, ci->dsn, ci->username, NAME_IS_VALID(ci->password) ? "xxxxx" : "");
170 
171 	if ((fchar = CC_connect(conn, NULL)) <= 0)
172 	{
173 		/* Error messages are filled in */
174 		CC_log_error(func, "Error on CC_connect", conn);
175 		ret = SQL_ERROR;
176 	}
177 	if (SQL_SUCCESS == ret && 2 == fchar)
178 		ret = SQL_SUCCESS_WITH_INFO;
179 
180 	MYLOG(0, "leaving..%d.\n", ret);
181 
182 	return ret;
183 }
184 
185 
186 RETCODE		SQL_API
PGAPI_BrowseConnect(HDBC hdbc,const SQLCHAR * szConnStrIn,SQLSMALLINT cbConnStrIn,SQLCHAR * szConnStrOut,SQLSMALLINT cbConnStrOutMax,SQLSMALLINT * pcbConnStrOut)187 PGAPI_BrowseConnect(HDBC hdbc,
188 					const SQLCHAR * szConnStrIn,
189 					SQLSMALLINT cbConnStrIn,
190 					SQLCHAR * szConnStrOut,
191 					SQLSMALLINT cbConnStrOutMax,
192 					SQLSMALLINT * pcbConnStrOut)
193 {
194 	CSTR func = "PGAPI_BrowseConnect";
195 	ConnectionClass *conn = (ConnectionClass *) hdbc;
196 
197 	MYLOG(0, "entering...\n");
198 
199 	CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Function not implemented", func);
200 	return SQL_ERROR;
201 }
202 
203 
204 /* Drop any hstmts open on hdbc and disconnect from database */
205 RETCODE		SQL_API
PGAPI_Disconnect(HDBC hdbc)206 PGAPI_Disconnect(HDBC hdbc)
207 {
208 	ConnectionClass *conn = (ConnectionClass *) hdbc;
209 	CSTR func = "PGAPI_Disconnect";
210 
211 
212 	MYLOG(0, "entering...\n");
213 
214 	if (!conn)
215 	{
216 		CC_log_error(func, "", NULL);
217 		return SQL_INVALID_HANDLE;
218 	}
219 
220 	if (conn->status == CONN_EXECUTING)
221 	{
222 		CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func);
223 		return SQL_ERROR;
224 	}
225 
226 	logs_on_off(-1, conn->connInfo.drivers.debug, conn->connInfo.drivers.commlog);
227 	MYLOG(0, "about to CC_cleanup\n");
228 
229 	/* Close the connection and free statements */
230 	CC_cleanup(conn, FALSE);
231 
232 	MYLOG(0, "done CC_cleanup\n");
233 	MYLOG(0, "leaving...\n");
234 
235 	return SQL_SUCCESS;
236 }
237 
238 
239 RETCODE		SQL_API
PGAPI_FreeConnect(HDBC hdbc)240 PGAPI_FreeConnect(HDBC hdbc)
241 {
242 	ConnectionClass *conn = (ConnectionClass *) hdbc;
243 	CSTR func = "PGAPI_FreeConnect";
244 	EnvironmentClass *env;
245 
246 	MYLOG(0, "entering...hdbc=%p\n", hdbc);
247 
248 	if (!conn)
249 	{
250 		CC_log_error(func, "", NULL);
251 		return SQL_INVALID_HANDLE;
252 	}
253 
254 	/* Remove the connection from the environment */
255 	if (NULL != (env = CC_get_env(conn)) &&
256 	    !EN_remove_connection(env, conn))
257 	{
258 		CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func);
259 		return SQL_ERROR;
260 	}
261 
262 	CC_Destructor(conn);
263 
264 	MYLOG(0, "leaving...\n");
265 
266 	return SQL_SUCCESS;
267 }
268 
269 /*
270  *		IMPLEMENTATION CONNECTION CLASS
271  */
272 
273 static void
reset_current_schema(ConnectionClass * self)274 reset_current_schema(ConnectionClass *self)
275 {
276 	if (self->current_schema)
277 	{
278 		free(self->current_schema);
279 		self->current_schema = NULL;
280 	}
281 	self->current_schema_valid = FALSE;
282 }
283 
284 static ConnectionClass *
CC_alloc(void)285 CC_alloc(void)
286 {
287 	return (ConnectionClass *) calloc(sizeof(ConnectionClass), 1);
288 }
289 
290 static void
CC_lockinit(ConnectionClass * self)291 CC_lockinit(ConnectionClass *self)
292 {
293 	INIT_CONNLOCK(self);
294 	INIT_CONN_CS(self);
295 }
296 
297 static ConnectionClass *
CC_initialize(ConnectionClass * rv,BOOL lockinit)298 CC_initialize(ConnectionClass *rv, BOOL lockinit)
299 {
300 	size_t		clear_size;
301 
302 #if defined(WIN_MULTITHREAD_SUPPORT) || defined(POSIX_THREADMUTEX_SUPPORT)
303 	clear_size = (char *)&(rv->cs) - (char *)rv;
304 #else
305 	clear_size = sizeof(ConnectionClass);
306 #endif /* WIN_MULTITHREAD_SUPPORT */
307 
308 	memset(rv, 0, clear_size);
309 	rv->status = CONN_NOT_CONNECTED;
310 	rv->transact_status = CONN_IN_AUTOCOMMIT;		/* autocommit by default */
311 	rv->unnamed_prepared_stmt = NULL;
312 
313 	rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT);
314 	if (!rv->stmts)
315 		goto cleanup;
316 	memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
317 
318 	rv->num_stmts = STMT_INCREMENT;
319 	rv->descs = (DescriptorClass **) malloc(sizeof(DescriptorClass *) * STMT_INCREMENT);
320 	if (!rv->descs)
321 		goto cleanup;
322 	memset(rv->descs, 0, sizeof(DescriptorClass *) * STMT_INCREMENT);
323 
324 	rv->num_descs = STMT_INCREMENT;
325 
326 	rv->lobj_type = PG_TYPE_LO_UNDEFINED;
327 	if (isMsAccess())
328 		rv->ms_jet = 1;
329 	rv->isolation = 0; // means initially unknown server's default isolation
330 	rv->mb_maxbyte_per_char = 1;
331 	rv->max_identifier_length = -1;
332 	rv->autocommit_public = SQL_AUTOCOMMIT_ON;
333 
334 	/* Initialize statement options to defaults */
335 	/* Statements under this conn will inherit these options */
336 
337 	InitializeStatementOptions(&rv->stmtOptions);
338 	InitializeARDFields(&rv->ardOptions);
339 	InitializeAPDFields(&rv->apdOptions);
340 #ifdef	_HANDLE_ENLIST_IN_DTC_
341 	rv->asdum = NULL;
342 	rv->gTranInfo = 0;
343 #endif /* _HANDLE_ENLIST_IN_DTC_ */
344 	if (lockinit)
345 		CC_lockinit(rv);
346 
347 	return rv;
348 
349 cleanup:
350 	CC_Destructor(rv);
351 	return NULL;
352 }
353 
354 ConnectionClass *
CC_Constructor()355 CC_Constructor()
356 {
357 	ConnectionClass *rv, *retrv = NULL;
358 
359 	if (rv = CC_alloc(), NULL != rv)
360 		retrv = CC_initialize(rv, TRUE);
361 	return retrv;
362 }
363 
364 char
CC_Destructor(ConnectionClass * self)365 CC_Destructor(ConnectionClass *self)
366 {
367 	MYLOG(0, "entering self=%p\n", self);
368 
369 	if (self->status == CONN_EXECUTING)
370 		return 0;
371 
372 	CC_cleanup(self, FALSE);			/* cleanup socket and statements */
373 
374 	MYLOG(0, "after CC_Cleanup\n");
375 
376 	/* Free up statement holders */
377 	if (self->stmts)
378 	{
379 		free(self->stmts);
380 		self->stmts = NULL;
381 	}
382 	if (self->descs)
383 	{
384 		free(self->descs);
385 		self->descs = NULL;
386 	}
387 	MYLOG(0, "after free statement holders\n");
388 
389 	NULL_THE_NAME(self->schemaIns);
390 	NULL_THE_NAME(self->tableIns);
391 	CC_conninfo_release(&self->connInfo);
392 	if (self->__error_message)
393 		free(self->__error_message);
394 	DELETE_CONN_CS(self);
395 	DELETE_CONNLOCK(self);
396 	free(self);
397 
398 	MYLOG(0, "leaving\n");
399 
400 	return 1;
401 }
402 
403 
404 /*	Return how many cursors are opened on this connection */
405 int
CC_cursor_count(ConnectionClass * self)406 CC_cursor_count(ConnectionClass *self)
407 {
408 	StatementClass *stmt;
409 	int			i,
410 				count = 0;
411 	QResultClass		*res;
412 
413 	MYLOG(0, "self=%p, num_stmts=%d\n", self, self->num_stmts);
414 
415 	CONNLOCK_ACQUIRE(self);
416 	for (i = 0; i < self->num_stmts; i++)
417 	{
418 		stmt = self->stmts[i];
419 		if (stmt && (res = SC_get_Result(stmt)) && QR_get_cursor(res))
420 			count++;
421 	}
422 	CONNLOCK_RELEASE(self);
423 
424 	MYLOG(0, "leaving %d\n", count);
425 
426 	return count;
427 }
428 
429 
430 void
CC_clear_error(ConnectionClass * self)431 CC_clear_error(ConnectionClass *self)
432 {
433 	if (!self)	return;
434 	CONNLOCK_ACQUIRE(self);
435 	self->__error_number = 0;
436 	if (self->__error_message)
437 	{
438 		free(self->__error_message);
439 		self->__error_message = NULL;
440 	}
441 	self->sqlstate[0] = '\0';
442 	CONNLOCK_RELEASE(self);
443 }
444 
445 void
CC_examine_global_transaction(ConnectionClass * self)446 CC_examine_global_transaction(ConnectionClass *self)
447 {
448 	if (!self)	return;
449 #ifdef	_HANDLE_ENLIST_IN_DTC_
450 	if (CC_is_in_global_trans(self))
451 		CALL_IsolateDtcConn(self, TRUE);
452 #endif /* _HANDLE_ENLIST_IN_DTC_ */
453 }
454 
455 
456 CSTR	bgncmd = "BEGIN";
457 CSTR	cmtcmd = "COMMIT";
458 CSTR	rbkcmd = "ROLLBACK";
459 CSTR	svpcmd = "SAVEPOINT";
460 CSTR	per_query_svp = "_per_query_svp_";
461 CSTR	rlscmd = "RELEASE";
462 
463 /*
464  *	Used to begin a transaction.
465  */
466 char
CC_begin(ConnectionClass * self)467 CC_begin(ConnectionClass *self)
468 {
469 	char	ret = TRUE;
470 	if (!CC_is_in_trans(self))
471 	{
472 		QResultClass *res = CC_send_query(self, bgncmd, NULL, 0, NULL);
473 		MYLOG(0, "  sending BEGIN!\n");
474 
475 		ret = QR_command_maybe_successful(res);
476 		QR_Destructor(res);
477 	}
478 
479 	return ret;
480 }
481 
482 /*
483  *	Used to commit a transaction.
484  *	We are almost always in the middle of a transaction.
485  */
486 char
CC_commit(ConnectionClass * self)487 CC_commit(ConnectionClass *self)
488 {
489 	char	ret = TRUE;
490 	if (CC_is_in_trans(self))
491 	{
492 		if (!CC_is_in_error_trans(self))
493 			CC_close_eof_cursors(self);
494 		if (CC_is_in_trans(self))
495 		{
496 			QResultClass *res = CC_send_query(self, cmtcmd, NULL, 0, NULL);
497 			MYLOG(0, "  sending COMMIT!\n");
498 			ret = QR_command_maybe_successful(res);
499 			QR_Destructor(res);
500 		}
501 	}
502 
503 	return ret;
504 }
505 
506 /*
507  *	Used to cancel a transaction.
508  *	We are almost always in the middle of a transaction.
509  */
510 char
CC_abort(ConnectionClass * self)511 CC_abort(ConnectionClass *self)
512 {
513 	char	ret = TRUE;
514 	if (CC_is_in_trans(self))
515 	{
516 		QResultClass *res = CC_send_query(self, rbkcmd, NULL, 0, NULL);
517 		MYLOG(0, "  sending ABORT!\n");
518 		ret = QR_command_maybe_successful(res);
519 		QR_Destructor(res);
520 	}
521 
522 	return ret;
523 }
524 
525 /* This is called by SQLSetConnectOption etc also */
526 char
CC_set_autocommit(ConnectionClass * self,BOOL on)527 CC_set_autocommit(ConnectionClass *self, BOOL on)
528 {
529 	BOOL currsts = CC_is_in_autocommit(self);
530 
531 	if ((on && currsts) ||
532 	    (!on && !currsts))
533 		return on;
534 	MYLOG(0, " %d->%d\n", currsts, on);
535 	if (CC_is_in_trans(self))
536 		CC_commit(self);
537 	if (on)
538 		self->transact_status |= CONN_IN_AUTOCOMMIT;
539 	else
540 		self->transact_status &= ~CONN_IN_AUTOCOMMIT;
541 
542 	return on;
543 }
544 
545 /* Clear cached table info */
546 static void
CC_clear_col_info(ConnectionClass * self,BOOL destroy)547 CC_clear_col_info(ConnectionClass *self, BOOL destroy)
548 {
549 	if (self->col_info)
550 	{
551 		int	i;
552 		COL_INFO	*coli;
553 
554 		for (i = 0; i < self->ntables; i++)
555 		{
556 			if (coli = self->col_info[i], NULL != coli)
557 			{
558 				if (destroy || coli->refcnt == 0)
559 				{
560 					free_col_info_contents(coli);
561 					free(coli);
562 					self->col_info[i] = NULL;
563 				}
564 				else
565 					coli->acc_time = 0;
566 			}
567 		}
568 		self->ntables = 0;
569 		if (destroy)
570 		{
571 			free(self->col_info);
572 			self->col_info = NULL;
573 			self->coli_allocated = 0;
574 		}
575 	}
576 }
577 
578 static void
CC_set_locale_encoding(ConnectionClass * self,const char * encoding)579 CC_set_locale_encoding(ConnectionClass *self, const char * encoding)
580 {
581 	char	*currenc = self->locale_encoding;
582 
583 	if (encoding)
584 		self->locale_encoding = strdup(encoding);
585 	else
586 		self->locale_encoding = NULL;
587 	if (currenc)
588 		free(currenc);
589 }
590 
591 static void
CC_determine_locale_encoding(ConnectionClass * self)592 CC_determine_locale_encoding(ConnectionClass *self)
593 {
594 	const char *dbencoding = PQparameterStatus(self->pqconn, "client_encoding");
595 	const char *encoding;
596 
597 	QLOG(0, "PQparameterStatus(%p, \"client_encoding\")=%s\n", self->pqconn, SAFE_STR(dbencoding));
598 	if (self->locale_encoding) /* already set */
599                 return;
600 	encoding = derive_locale_encoding(dbencoding);
601 	if (!encoding)
602 		encoding = "SQL_ASCII";
603 	CC_set_locale_encoding(self, encoding);
604 }
605 
606 static void
CC_set_client_encoding(ConnectionClass * self,const char * encoding)607 CC_set_client_encoding(ConnectionClass *self, const char * encoding)
608 {
609 	char	*currenc = self->original_client_encoding;
610 
611 	if (encoding)
612 	{
613 		self->original_client_encoding = strdup(encoding);
614 		self->ccsc = pg_CS_code(encoding);
615 	}
616 	else
617 	{
618 		self->original_client_encoding = NULL;
619 		self->ccsc = SQL_ASCII;
620 	}
621 	self->mb_maxbyte_per_char = pg_mb_maxlen(self->ccsc);
622 	if (currenc)
623 		free(currenc);
624 }
625 
626 int
CC_send_client_encoding(ConnectionClass * self,const char * encoding)627 CC_send_client_encoding(ConnectionClass *self, const char * encoding)
628 {
629 	const char *dbencoding = PQparameterStatus(self->pqconn, "client_encoding");
630 
631 	if (encoding && (!dbencoding || stricmp(encoding, dbencoding)))
632 	{
633                 char	query[64];
634 		QResultClass	*res;
635 		BOOL	cmd_success;
636 
637 		SPRINTF_FIXED(query, "set client_encoding to '%s'", encoding);
638 		res = CC_send_query(self, query, NULL, 0, NULL);
639 		cmd_success = QR_command_maybe_successful(res);
640 		QR_Destructor(res);
641 
642 		if (!cmd_success)
643 			return SQL_ERROR;
644 	}
645 	CC_set_client_encoding(self, encoding);
646 
647 	return SQL_SUCCESS;
648 }
649 
650 /* This is called by SQLDisconnect also */
651 char
CC_cleanup(ConnectionClass * self,BOOL keepCommunication)652 CC_cleanup(ConnectionClass *self, BOOL keepCommunication)
653 {
654 	int			i;
655 	StatementClass *stmt;
656 	DescriptorClass *desc;
657 
658 	if (self->status == CONN_EXECUTING)
659 		return FALSE;
660 
661 	MYLOG(0, "entering self=%p\n", self);
662 
663 	ENTER_CONN_CS(self);
664 	/* Cancel an ongoing transaction */
665 	/* We are always in the middle of a transaction, */
666 	/* even if we are in auto commit. */
667 	if (self->pqconn)
668 	{
669 		QLOG(0, "PQfinish: %p\n", self->pqconn);
670 		PQfinish(self->pqconn);
671 		self->pqconn = NULL;
672 	}
673 
674 	MYLOG(0, "after PQfinish\n");
675 
676 	/* Free all the stmts on this connection */
677 	for (i = 0; i < self->num_stmts; i++)
678 	{
679 		stmt = self->stmts[i];
680 		if (stmt)
681 		{
682 			stmt->hdbc = NULL;	/* prevent any more dbase interactions */
683 
684 			SC_Destructor(stmt);
685 
686 			self->stmts[i] = NULL;
687 		}
688 	}
689 	/* Free all the descs on this connection */
690 	for (i = 0; i < self->num_descs; i++)
691 	{
692 		desc = self->descs[i];
693 		if (desc)
694 		{
695 			DC_get_conn(desc) = NULL;	/* prevent any more dbase interactions */
696 			DC_Destructor(desc);
697 			free(desc);
698 			self->descs[i] = NULL;
699 		}
700 	}
701 
702 	/* Check for translation dll */
703 #ifdef WIN32
704 	if (!keepCommunication && self->translation_handle)
705 	{
706 		FreeLibrary(self->translation_handle);
707 		self->translation_handle = NULL;
708 	}
709 #endif
710 
711 	if (!keepCommunication)
712 	{
713 		self->status = CONN_NOT_CONNECTED;
714 		self->transact_status = CONN_IN_AUTOCOMMIT;
715 		self->unnamed_prepared_stmt = NULL;
716 	}
717 	if (!keepCommunication)
718 	{
719 		CC_conninfo_init(&(self->connInfo), CLEANUP_FOR_REUSE);
720 		if (self->original_client_encoding)
721 		{
722 			free(self->original_client_encoding);
723 			self->original_client_encoding = NULL;
724 		}
725 		if (self->locale_encoding)
726 		{
727 			free(self->locale_encoding);
728 			self->locale_encoding = NULL;
729 		}
730 		if (self->server_encoding)
731 		{
732 			free(self->server_encoding);
733 			self->server_encoding = NULL;
734 		}
735 		reset_current_schema(self);
736 	}
737 	/* Free cached table info */
738 	CC_clear_col_info(self, TRUE);
739 	if (self->num_discardp > 0 && self->discardp)
740 	{
741 		for (i = 0; i < self->num_discardp; i++)
742 			free(self->discardp[i]);
743 		self->num_discardp = 0;
744 	}
745 	if (self->discardp)
746 	{
747 		free(self->discardp);
748 		self->discardp = NULL;
749 	}
750 
751 	LEAVE_CONN_CS(self);
752 	MYLOG(0, "leaving\n");
753 	return TRUE;
754 }
755 
756 
757 int
CC_set_translation(ConnectionClass * self)758 CC_set_translation(ConnectionClass *self)
759 {
760 
761 #ifdef WIN32
762 	CSTR	func = "CC_set_translation";
763 
764 	if (self->translation_handle != NULL)
765 	{
766 		FreeLibrary(self->translation_handle);
767 		self->translation_handle = NULL;
768 	}
769 
770 	if (self->connInfo.translation_dll[0] == 0)
771 		return TRUE;
772 
773 	self->translation_option = atoi(self->connInfo.translation_option);
774 	self->translation_handle = LoadLibrary(self->connInfo.translation_dll);
775 
776 	if (self->translation_handle == NULL)
777 	{
778 		CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not load the translation DLL.", func);
779 		return FALSE;
780 	}
781 
782 	self->DataSourceToDriver
783 		= (DataSourceToDriverProc) GetProcAddress(self->translation_handle,
784 												"SQLDataSourceToDriver");
785 
786 	self->DriverToDataSource
787 		= (DriverToDataSourceProc) GetProcAddress(self->translation_handle,
788 												"SQLDriverToDataSource");
789 
790 	if (self->DataSourceToDriver == NULL || self->DriverToDataSource == NULL)
791 	{
792 		CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not find translation DLL functions.", func);
793 		return FALSE;
794 	}
795 #endif
796 	return TRUE;
797 }
798 
799 #ifndef PG_DIAG_SEVERITY_NONLOCALIZED
800 #define PG_DIAG_SEVERITY_NONLOCALIZED 'V'
801 #endif
802 
803 void
handle_pgres_error(ConnectionClass * self,const PGresult * pgres,const char * comment,QResultClass * res,BOOL error_not_a_notice)804 handle_pgres_error(ConnectionClass *self, const PGresult *pgres,
805 				   const char *comment,
806 				   QResultClass *res, BOOL error_not_a_notice)
807 {
808 	char	   *errseverity;
809 	char	   *errseverity_nonloc = NULL;
810 	char	   *errprimary = NULL;
811 
812 	char	   *errdetail = NULL;
813 	char	   *errhint = NULL;
814 	char	   *errstatementposition = NULL;
815 	char	   *errinternalquery = NULL;
816 	char	   *errcontext = NULL;
817 	char	   *errschemaname = NULL;
818 	char	   *errtablename = NULL;
819 	char	   *errcolumnname = NULL;
820 	char	   *errdatatypename = NULL;
821 
822 	char	   *errmsg = NULL;
823 	char	*sqlstate = NULL;
824 	int	level = MIN_LOG_LEVEL;
825 
826 	int	display_error_level = (self->connInfo).optional_errors ? 3 : 1;
827 	PQExpBufferData	errbuf = {0};
828 
829 	MYLOG(DETAIL_LOG_LEVEL, "entering\n");
830 
831 	sqlstate = PQresultErrorField(pgres, PG_DIAG_SQLSTATE);
832 	if (res && pgres)
833 	{
834 		if (sqlstate)
835 			STRCPY_FIXED(res->sqlstate, sqlstate);
836 	}
837 
838 	if (NULL == pgres &&
839 	    NULL == self->pqconn)
840 	{
841 		const char *errmsg = "The connection has been lost";
842 
843 		MYLOG(0, "setting error message=%s\n", errmsg);
844 		QLOG(0, "\t%ssetting error message=%s\n", __FUNCTION__, errmsg);
845 		if (CC_get_errornumber(self) <= 0)
846 			CC_set_error(self, CONNECTION_COMMUNICATION_ERROR, errmsg, comment);
847 		if (res)
848 		{
849 			QR_set_rstatus(res, PORES_FATAL_ERROR);
850 			QR_set_message(res, errmsg);
851 		}
852 		goto cleanup;
853 	}
854 	/*
855 	 * The full message with details and context and everything could
856 	 * be obtained with PQresultErrorMessage(). I think that would be
857 	 * more user-friendly, but for now, construct a message with
858 	 * severity and primary message, which is backwards compatible.
859 	 */
860 	errseverity = PQresultErrorField(pgres, PG_DIAG_SEVERITY);
861 	if (PG_VERSION_GE(self, 9.6))
862 	{
863 		errseverity_nonloc = PQresultErrorField(pgres, PG_DIAG_SEVERITY_NONLOCALIZED);
864 		MYLOG(0, "PG_DIAG_SEVERITY_NONLOCALIZED=%s\n", SAFE_STR(errseverity_nonloc));
865 	}
866 	if (!error_not_a_notice)
867 	{
868 		if (errseverity_nonloc)
869 		{
870 			if (stricmp(errseverity_nonloc, "NOTICE") != 0)
871 				level = 1;
872 		}
873 		else if (errseverity)
874 		{
875 			if (stricmp(errseverity, "NOTICE") != 0)
876 				level = 1;
877 		}
878 	}
879 	errprimary = PQresultErrorField(pgres, PG_DIAG_MESSAGE_PRIMARY);
880 	if (errseverity_nonloc)
881 		QLOG(level, "\t%s(%s) %s '%s'\n", errseverity_nonloc, SAFE_STR(errseverity), SAFE_STR(sqlstate), SAFE_STR(errprimary));
882 	else
883 		QLOG(level, "\t(%s) %s '%s'\n", SAFE_STR(errseverity), SAFE_STR(sqlstate), SAFE_STR(errprimary));
884 	if (errprimary == NULL)
885 	{
886 		/* Hmm. got no primary message. Check if there's a connection error */
887 		if (self->pqconn)
888 			errprimary = PQerrorMessage(self->pqconn);
889 
890 		if (errprimary == NULL)
891 			errprimary = "no error information";
892 	}
893 	else if (display_error_level > 0)
894 	{
895 		errdetail = PQresultErrorField(pgres, PG_DIAG_MESSAGE_DETAIL);
896 		errhint = PQresultErrorField(pgres, PG_DIAG_MESSAGE_HINT);
897 		errstatementposition = PQresultErrorField(pgres, PG_DIAG_STATEMENT_POSITION);
898 		errinternalquery = PQresultErrorField(pgres, PG_DIAG_INTERNAL_POSITION);
899 		errcontext = PQresultErrorField(pgres, PG_DIAG_CONTEXT);
900 		errschemaname = PQresultErrorField(pgres, PG_DIAG_SCHEMA_NAME);
901 		errtablename = PQresultErrorField(pgres, PG_DIAG_TABLE_NAME);
902 		errcolumnname = PQresultErrorField(pgres, PG_DIAG_COLUMN_NAME);
903 		errdatatypename = PQresultErrorField(pgres, PG_DIAG_DATATYPE_NAME);
904 	}
905 	initPQExpBuffer(&errbuf);
906 	if (errseverity && errprimary)
907 	{
908 		printfPQExpBuffer(&errbuf, "%s: %s", errseverity, errprimary);
909 		if (display_error_level > 0 && errdetail)
910 			appendPQExpBuffer(&errbuf, "\nDETAIL: %s", errdetail);
911 		if (display_error_level > 1)
912 		{
913 			if (errhint)
914 				appendPQExpBuffer(&errbuf, "\nHINT: %s", errhint);
915 		}
916 		if (display_error_level > 2)
917 		{
918 			if (errstatementposition)
919 				appendPQExpBuffer(&errbuf, "\nSTATEMENT_POSITION: %s", errstatementposition);
920 			if (errinternalquery)
921 				appendPQExpBuffer(&errbuf, "\nINTERNAL_QUERY: %s", errinternalquery);
922 			if (errcontext)
923 				appendPQExpBuffer(&errbuf, "\nCONTEXT: %s", errcontext);
924 			if (errschemaname)
925 				appendPQExpBuffer(&errbuf, "\nSCHEMA_NAME: %s", errschemaname);
926 			if (errtablename)
927 				appendPQExpBuffer(&errbuf, "\nTABLE_NAME: %s", errtablename);
928 			if (errcolumnname)
929 				appendPQExpBuffer(&errbuf, "\nCOLUMN_NAME: %s", errcolumnname);
930 			if (errdatatypename)
931 				appendPQExpBuffer(&errbuf, "\nDATATYPE_NAME :%s", errdatatypename);
932 		}
933 		errmsg = errbuf.data;
934 	}
935 	if (errmsg == NULL)
936 		errmsg = errprimary;
937 
938 	if (!error_not_a_notice) /* warning, notice, log etc */
939 	{
940 		MYLOG(0, "notice message %s\n", errmsg);
941 		if (res)
942 		{
943 			if (QR_command_successful(res))
944 				QR_set_rstatus(res, PORES_NONFATAL_ERROR); /* notice or warning */
945 			QR_add_notice(res, errmsg);  /* will dup this string */
946 		}
947 		goto cleanup;
948 	}
949 
950 	MYLOG(0, "error message=%s(" FORMAT_SIZE_T ")\n", errmsg, strlen(errmsg));
951 
952 	if (res)
953 	{
954 		QR_set_rstatus(res, PORES_FATAL_ERROR); /* error or fatal */
955 		if (errmsg[0])
956 			QR_set_message(res, errmsg);
957 		QR_set_aborted(res, TRUE);
958 	}
959 
960 	/*
961 	 *	If the error is continuable after rollback?
962 	 */
963 	if (PQstatus(self->pqconn) == CONNECTION_BAD)
964 	{
965 		CC_set_errornumber(self, CONNECTION_COMMUNICATION_ERROR);
966 		CC_on_abort(self, CONN_DEAD); /* give up the connection */
967 	}
968 	else if ((errseverity_nonloc && strcmp(errseverity_nonloc, "FATAL") == 0) ||
969 		(NULL == errseverity_nonloc && errseverity && strcmp(errseverity, "FATAL") == 0)) /* no */
970 	{
971 		CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_SEVERITY_FATAL);
972 		CC_on_abort(self, CONN_DEAD); /* give up the connection */
973 	}
974 	else /* yes */
975 	{
976 		CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_SEVERITY_ERROR);
977 		if (CC_is_in_trans(self))
978 			CC_set_in_error_trans(self);
979 	}
980 
981 cleanup:
982 	if (!PQExpBufferDataBroken(errbuf))
983 		termPQExpBuffer(&errbuf);
984 	LIBPQ_update_transaction_status(self);
985 }
986 
987 void
receive_libpq_notice(void * arg,const PGresult * pgres)988 receive_libpq_notice(void *arg, const PGresult *pgres)
989 {
990 	if (arg != NULL)
991 	{
992 		notice_receiver_arg *nrarg = (notice_receiver_arg *) arg;
993 
994 		if (NULL != nrarg->stmt)
995 			nrarg->stmt->has_notice = 1;
996 		handle_pgres_error(nrarg->conn, pgres, nrarg->comment, nrarg->res, FALSE);
997 	}
998 }
999 
CC_initial_log(ConnectionClass * self,const char * func)1000 static char CC_initial_log(ConnectionClass *self, const char *func)
1001 {
1002 	const ConnInfo	*ci = &self->connInfo;
1003 	char	*encoding, vermsg[128];
1004 
1005 	snprintf(vermsg, sizeof(vermsg), "Driver Version='%s,%s'"
1006 #ifdef	WIN32
1007 		" linking %d"
1008 #ifdef	_MT
1009 #ifdef	_DLL
1010 		" dynamic"
1011 #else
1012 		" static"
1013 #endif /* _DLL */
1014 		" Multithread"
1015 #else
1016 		" Singlethread"
1017 #endif /* _MT */
1018 #ifdef	_DEBUG
1019 		" Debug"
1020 #endif /* DEBUG */
1021 		" library"
1022 #endif /* WIN32 */
1023 		"\n", POSTGRESDRIVERVERSION, __DATE__
1024 #ifdef	_MSC_VER
1025 		, _MSC_VER
1026 #endif /* _MSC_VER */
1027 		);
1028 	QLOG(0, "%s", vermsg);
1029 	MYLOG(DETAIL_LOG_LEVEL, "Global Options: fetch=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
1030 		 ci->drivers.fetch_max,
1031 		 ci->drivers.unknown_sizes,
1032 		 ci->drivers.max_varchar_size,
1033 		 ci->drivers.max_longvarchar_size);
1034 	MYLOG(DETAIL_LOG_LEVEL, "                unique_index=%d, use_declarefetch=%d\n",
1035 		 ci->drivers.unique_index,
1036 		 ci->drivers.use_declarefetch);
1037 	MYLOG(DETAIL_LOG_LEVEL, "                text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d NAMEDATALEN=%d\n",
1038 		 ci->drivers.text_as_longvarchar,
1039 		 ci->drivers.unknowns_as_longvarchar,
1040 		 ci->drivers.bools_as_char,
1041 		 TABLE_NAME_STORAGE_LEN);
1042 
1043 	if (NULL == self->locale_encoding)
1044 	{
1045 		encoding = check_client_encoding(ci->conn_settings);
1046 		CC_set_locale_encoding(self, encoding);
1047 		MYLOG(DETAIL_LOG_LEVEL, "                extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
1048 			ci->drivers.extra_systable_prefixes,
1049 			PRINT_NAME(ci->conn_settings),
1050 			encoding ? encoding : "");
1051 	}
1052 	if (self->status == CONN_DOWN)
1053 	{
1054 		CC_set_error_if_not_set(self, CONN_OPENDB_ERROR, "Connection broken.", func);
1055 		return 0;
1056 	}
1057 	else if (self->status != CONN_NOT_CONNECTED)
1058 	{
1059 		CC_set_error_if_not_set(self, CONN_OPENDB_ERROR, "Already connected.", func);
1060 		return 0;
1061 	}
1062 
1063 	MYLOG(0, "DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", ci->dsn, ci->server, ci->port, ci->database, ci->username, NAME_IS_VALID(ci->password) ? "xxxxx" : "");
1064 
1065 	return 1;
1066 }
1067 
1068 static int handle_show_results(const QResultClass *res);
1069 #define	TRANSACTION_ISOLATION "transaction_isolation"
1070 #define	ISOLATION_SHOW_QUERY "show " TRANSACTION_ISOLATION
1071 
1072 static int LIBPQ_connect(ConnectionClass *self);
1073 static char
LIBPQ_CC_connect(ConnectionClass * self,char * salt_para)1074 LIBPQ_CC_connect(ConnectionClass *self, char *salt_para)
1075 {
1076 	int		ret;
1077 	CSTR		func = "LIBPQ_CC_connect";
1078 	QResultClass	*res;
1079 
1080 	MYLOG(0, "entering...\n");
1081 
1082 	if (0 == CC_initial_log(self, func))
1083 		return 0;
1084 
1085 	if (ret = LIBPQ_connect(self), ret <= 0)
1086 		return ret;
1087 	res = CC_send_query(self, "SET DateStyle = 'ISO';SET extra_float_digits = 2;" ISOLATION_SHOW_QUERY, NULL, READ_ONLY_QUERY, NULL);
1088 	if (QR_command_maybe_successful(res))
1089 	{
1090 		handle_show_results(res);
1091 		ret = 1;
1092 	}
1093 	else
1094 		ret = 0;
1095 	QR_Destructor(res);
1096 
1097 	return ret;
1098 }
1099 
1100 char
CC_connect(ConnectionClass * self,char * salt_para)1101 CC_connect(ConnectionClass *self, char *salt_para)
1102 {
1103 	ConnInfo *ci = &(self->connInfo);
1104 	CSTR	func = "CC_connect";
1105 	char		ret, *saverr = NULL, retsend;
1106 	const char	*errmsg = NULL;
1107 
1108 	MYLOG(0, "entering...sslmode=%s\n", self->connInfo.sslmode);
1109 
1110 	ret = LIBPQ_CC_connect(self, salt_para);
1111 	if (ret <= 0)
1112 		return ret;
1113 
1114 	CC_set_translation(self);
1115 
1116 	/*
1117 	 * Send any initial settings
1118 	 */
1119 
1120 	/*
1121 	 * Since these functions allocate statements, and since the connection
1122 	 * is not established yet, it would violate odbc state transition
1123 	 * rules.  Therefore, these functions call the corresponding local
1124 	 * function instead.
1125 	 */
1126 
1127 	/* Per Datasource settings */
1128 	retsend = CC_send_settings(self, GET_NAME(self->connInfo.conn_settings));
1129 	if (CONN_DOWN == self->status)
1130 	{
1131 		ret = 0;
1132 		goto cleanup;
1133 	}
1134 
1135 	if (CC_get_errornumber(self) > 0 &&
1136 	    NULL != (errmsg = CC_get_errormsg(self)))
1137 		saverr = strdup(errmsg);
1138 	CC_clear_error(self);			/* clear any error */
1139 
1140 	if (!SQL_SUCCEEDED(CC_lookup_lo(self)))	/* a hack to get the oid of our large object oid type */
1141 	{
1142 		ret = 0;
1143 		goto cleanup;
1144 	}
1145 
1146 	/*
1147 	 *		Multibyte handling
1148 	 *
1149 	 *	Send 'UTF8' when required Unicode behavior, otherwise send
1150 	 *	locale encodings.
1151 	 */
1152 	CC_clear_error(self);
1153 	CC_determine_locale_encoding(self); /* determine the locale_encoding */
1154 #ifdef UNICODE_SUPPORT
1155 	if (CC_is_in_unicode_driver(self))
1156 	{
1157 		if (!SQL_SUCCEEDED(CC_send_client_encoding(self, "UTF8")))
1158 		{
1159 			ret = 0;
1160 			goto cleanup;
1161 		}
1162 	}
1163 	else	/* for unicode drivers require ANSI behavior */
1164 #endif /* UNICODE_SUPPORT */
1165 	{
1166 		if (!SQL_SUCCEEDED(CC_send_client_encoding(self, self->locale_encoding)))
1167 		{
1168 			ret = 0;
1169 			goto cleanup;
1170 		}
1171 	}
1172 
1173 	CC_clear_error(self);
1174 	if (self->server_isolation != self->isolation)
1175 		if (!CC_set_transact(self, self->isolation))
1176 		{
1177 			ret = 0;
1178 			goto cleanup;
1179 		}
1180 
1181 	ci_updatable_cursors_set(ci);
1182 
1183 	if (CC_get_errornumber(self) > 0)
1184 		CC_clear_error(self);		/* clear any initial command errors */
1185 	self->status = CONN_CONNECTED;
1186 	if (CC_is_in_unicode_driver(self)
1187 	    && (CC_is_in_ansi_app(self) || 0 < ci->bde_environment))
1188 		self->unicode |= CONN_DISALLOW_WCHAR;
1189 MYLOG(0, "conn->unicode=%d Client Encoding='%s' (Code %d)\n", self->unicode, self->original_client_encoding, self->ccsc);
1190 	ret = 1;
1191 
1192 cleanup:
1193 	MYLOG(0, "leaving...%d\n", ret);
1194 	if (NULL != saverr)
1195 	{
1196 		if (ret > 0 && CC_get_errornumber(self) <= 0)
1197 			CC_set_error(self, -1, saverr, func);
1198 		free(saverr);
1199 	}
1200 	if (1 == ret && FALSE == retsend)
1201 		ret = 2;
1202 
1203 	return ret;
1204 }
1205 
1206 
1207 char
CC_add_statement(ConnectionClass * self,StatementClass * stmt)1208 CC_add_statement(ConnectionClass *self, StatementClass *stmt)
1209 {
1210 	int	i;
1211 	char	ret = TRUE;
1212 
1213 	MYLOG(0, "self=%p, stmt=%p\n", self, stmt);
1214 
1215 	CONNLOCK_ACQUIRE(self);
1216 	for (i = 0; i < self->num_stmts; i++)
1217 	{
1218 		if (!self->stmts[i])
1219 		{
1220 			stmt->hdbc = self;
1221 			self->stmts[i] = stmt;
1222 			break;
1223 		}
1224 	}
1225 
1226 	if (i >= self->num_stmts) /* no more room -- allocate more memory */
1227 	{
1228 		StatementClass **newstmts;
1229 		Int2 new_num_stmts;
1230 
1231 		new_num_stmts = STMT_INCREMENT + self->num_stmts;
1232 
1233 		if (new_num_stmts > 0)
1234 			newstmts = (StatementClass **)
1235 				realloc(self->stmts, sizeof(StatementClass *) * new_num_stmts);
1236 		else
1237 			newstmts = NULL; /* num_stmts overflowed */
1238 		if (!newstmts)
1239 			ret = FALSE;
1240 		else
1241 		{
1242 			self->stmts = newstmts;
1243 			memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT);
1244 
1245 			stmt->hdbc = self;
1246 			self->stmts[self->num_stmts] = stmt;
1247 
1248 			self->num_stmts = new_num_stmts;
1249 		}
1250 	}
1251 	CONNLOCK_RELEASE(self);
1252 
1253 	return ret;
1254 }
1255 
1256 static void
CC_set_error_statements(ConnectionClass * self)1257 CC_set_error_statements(ConnectionClass *self)
1258 {
1259 	int	i;
1260 
1261 	MYLOG(0, "entering self=%p\n", self);
1262 
1263 	for (i = 0; i < self->num_stmts; i++)
1264 	{
1265 		if (NULL != self->stmts[i])
1266 			SC_ref_CC_error(self->stmts[i]);
1267 	}
1268 }
1269 
1270 
1271 char
CC_remove_statement(ConnectionClass * self,StatementClass * stmt)1272 CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
1273 {
1274 	int	i;
1275 	char	ret = FALSE;
1276 
1277 	CONNLOCK_ACQUIRE(self);
1278 	for (i = 0; i < self->num_stmts; i++)
1279 	{
1280 		if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING)
1281 		{
1282 			self->stmts[i] = NULL;
1283 			ret = TRUE;
1284 			break;
1285 		}
1286 	}
1287 	CONNLOCK_RELEASE(self);
1288 
1289 	return ret;
1290 }
1291 
CC_get_escape(const ConnectionClass * self)1292 char CC_get_escape(const ConnectionClass *self)
1293 {
1294 	const char	   *scf;
1295 	static const ConnectionClass *conn = NULL;
1296 
1297 	scf = PQparameterStatus(self->pqconn, "standard_conforming_strings");
1298 	if (self != conn)
1299 	{
1300 		QLOG(0, "PQparameterStatus(%p, \"standard_conforming_strings\")=%s\n", self->pqconn, SAFE_STR(scf));
1301 		conn = self;
1302 	}
1303 	if (scf == NULL)
1304 	{
1305 		/* we're connected to a pre-8.1 server, and E'' is not supported */
1306 		return '\0';
1307 	}
1308 	if (strcmp(scf, "on") != 0)
1309 		return ESCAPE_IN_LITERAL;
1310 	else
1311 		return '\0';
1312 }
1313 
1314 
CC_get_max_idlen(ConnectionClass * self)1315 int	CC_get_max_idlen(ConnectionClass *self)
1316 {
1317 	int	len = self->max_identifier_length;
1318 
1319 	if  (len < 0)
1320 	{
1321 		QResultClass	*res;
1322 
1323 		res = CC_send_query(self, "show max_identifier_length", NULL, READ_ONLY_QUERY, NULL);
1324 		if (QR_command_maybe_successful(res))
1325 			len = self->max_identifier_length = QR_get_value_backend_int(res, 0, 0, FALSE);
1326 		QR_Destructor(res);
1327 	}
1328 MYLOG(0, "max_identifier_length=%d\n", len);
1329 	return len < 0 ? 0 : len;
1330 }
1331 
1332 static SQLINTEGER
isolation_str_to_enum(const char * str_isolation)1333 isolation_str_to_enum(const char *str_isolation)
1334 {
1335 	SQLINTEGER	isolation = 0;
1336 
1337 	if (strnicmp(str_isolation, "seri", 4) == 0)
1338 		isolation = SQL_TXN_SERIALIZABLE;
1339 	else if (strnicmp(str_isolation, "repe", 4) == 0)
1340 		isolation = SQL_TXN_REPEATABLE_READ;
1341 	else if (strnicmp(str_isolation, "read com", 8) == 0)
1342 		isolation = SQL_TXN_READ_COMMITTED;
1343 	else if (strnicmp(str_isolation, "read unc", 8) == 0)
1344 		isolation = SQL_TXN_READ_UNCOMMITTED;
1345 
1346 	return isolation;
1347 }
1348 
handle_show_results(const QResultClass * res)1349 static int handle_show_results(const QResultClass *res)
1350 {
1351 	int			count = 0;
1352 	const QResultClass	*qres;
1353 	ConnectionClass		*conn = QR_get_conn(res);
1354 
1355 	for (qres = res; qres; qres = QR_nextr(qres))
1356 	{
1357 		if (!qres->command ||
1358 		    stricmp(qres->command, "SHOW") != 0)
1359 			continue;
1360 		if (strcmp(QR_get_fieldname(qres, 0), TRANSACTION_ISOLATION) == 0)
1361 		{
1362 			conn->server_isolation = isolation_str_to_enum(QR_get_value_backend_text(qres, 0, 0));
1363 			MYLOG(0, "isolation " FORMAT_UINTEGER " to be " FORMAT_UINTEGER "\n", conn->server_isolation, conn->isolation);
1364 			if (0 == conn->isolation)
1365 				conn->isolation = conn->server_isolation;
1366 			if (0 == conn->default_isolation)
1367 				conn->default_isolation = conn->server_isolation;
1368 			count++;
1369 		}
1370 	}
1371 
1372 	return count;
1373 }
1374 /*
1375  *	This function may not be called as long as ISOLATION_SHOW_QUERY is
1376  *	issued in LIBPQ_CC_connect.
1377  */
CC_get_isolation(ConnectionClass * self)1378 SQLUINTEGER	CC_get_isolation(ConnectionClass *self)
1379 {
1380 	SQLUINTEGER	isolation = 0;
1381 	QResultClass	*res;
1382 
1383 	res = CC_send_query(self, ISOLATION_SHOW_QUERY, NULL, READ_ONLY_QUERY, NULL);
1384 	if (QR_command_maybe_successful(res))
1385 	{
1386 		handle_show_results(res);
1387 		isolation = self->server_isolation;
1388 	}
1389 	QR_Destructor(res);
1390 MYLOG(0, "isolation=" FORMAT_UINTEGER "\n", isolation);
1391 	return isolation;
1392 }
1393 
1394 void
CC_set_error(ConnectionClass * self,int number,const char * message,const char * func)1395 CC_set_error(ConnectionClass *self, int number, const char *message, const char *func)
1396 {
1397 	CONNLOCK_ACQUIRE(self);
1398 	if (self->__error_message)
1399 		free(self->__error_message);
1400 	self->__error_number = number;
1401 	self->__error_message = message ? strdup(message) : NULL;
1402 	if (0 != number)
1403 		CC_set_error_statements(self);
1404 	if (func && number != 0)
1405 		CC_log_error(func, "", self);
1406 	CONNLOCK_RELEASE(self);
1407 }
1408 
1409 
1410 void
CC_set_errormsg(ConnectionClass * self,const char * message)1411 CC_set_errormsg(ConnectionClass *self, const char *message)
1412 {
1413 	CONNLOCK_ACQUIRE(self);
1414 	if (self->__error_message)
1415 		free(self->__error_message);
1416 	self->__error_message = message ? strdup(message) : NULL;
1417 	CONNLOCK_RELEASE(self);
1418 }
1419 
1420 
1421 char
CC_get_error(ConnectionClass * self,int * number,char ** message)1422 CC_get_error(ConnectionClass *self, int *number, char **message)
1423 {
1424 	int			rv;
1425 
1426 	MYLOG(0, "entering\n");
1427 
1428 	CONNLOCK_ACQUIRE(self);
1429 
1430 	if (CC_get_errornumber(self))
1431 	{
1432 		*number = CC_get_errornumber(self);
1433 		*message = CC_get_errormsg(self);
1434 	}
1435 	rv = (CC_get_errornumber(self) != 0);
1436 
1437 	CONNLOCK_RELEASE(self);
1438 
1439 	MYLOG(0, "leaving\n");
1440 
1441 	return rv;
1442 }
1443 
1444 
CC_close_eof_cursors(ConnectionClass * self)1445 static int CC_close_eof_cursors(ConnectionClass *self)
1446 {
1447 	int	i, ccount = 0;
1448 	StatementClass	*stmt;
1449 	QResultClass	*res;
1450 
1451 	if (!self->ncursors)
1452 		return ccount;
1453 	CONNLOCK_ACQUIRE(self);
1454 	for (i = 0; i < self->num_stmts; i++)
1455 	{
1456 		if (stmt = self->stmts[i], NULL == stmt)
1457 			continue;
1458 		if (res = SC_get_Result(stmt), NULL == res)
1459 			continue;
1460 		if (NULL != QR_get_cursor(res) &&
1461 		    QR_is_withhold(res) &&
1462 		    QR_once_reached_eof(res))
1463 		{
1464 			if (QR_get_num_cached_tuples(res) >= QR_get_num_total_tuples(res) ||
1465 				SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type)
1466 			{
1467 				QR_close(res);
1468 				ccount++;
1469 			}
1470 		}
1471 	}
1472 	CONNLOCK_RELEASE(self);
1473 	return ccount;
1474 }
1475 
CC_clear_cursors(ConnectionClass * self,BOOL on_abort)1476 static void CC_clear_cursors(ConnectionClass *self, BOOL on_abort)
1477 {
1478 	int	i;
1479 	StatementClass	*stmt;
1480 	QResultClass	*res;
1481 
1482 	if (!self->ncursors)
1483 		return;
1484 	CONNLOCK_ACQUIRE(self);
1485 	for (i = 0; i < self->num_stmts; i++)
1486 	{
1487 		stmt = self->stmts[i];
1488 		if (stmt && (res = SC_get_Result(stmt)) &&
1489 			 (NULL != QR_get_cursor(res)))
1490 		{
1491 			/*
1492 			 * non-holdable cursors are automatically closed
1493 			 * at commit time.
1494 			 * all non-permanent cursors are automatically closed
1495 			 * at rollback time.
1496 			 */
1497 			if ((on_abort && !QR_is_permanent(res)) ||
1498 				!QR_is_withhold(res))
1499 			{
1500 				QR_on_close_cursor(res);
1501 			}
1502 			else if (!QR_is_permanent(res))
1503 			{
1504 				QResultClass	*wres;
1505 				char	cmd[64];
1506 
1507 				if (QR_needs_survival_check(res))
1508 				{
1509 					SPRINTF_FIXED(cmd, "MOVE 0 in \"%s\"", QR_get_cursor(res));
1510 					CONNLOCK_RELEASE(self);
1511 					wres = CC_send_query(self, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN | READ_ONLY_QUERY, NULL);
1512 					QR_set_no_survival_check(res);
1513 					if (QR_command_maybe_successful(wres) &&
1514 					    CONN_ERROR_IGNORED != CC_get_errornumber(self))
1515 						QR_set_permanent(res);
1516 					else
1517 						QR_set_cursor(res, NULL);
1518 					QR_Destructor(wres);
1519 					CONNLOCK_ACQUIRE(self);
1520 MYLOG(DETAIL_LOG_LEVEL, "%p->permanent -> %d %p\n", res, QR_is_permanent(res), QR_get_cursor(res));
1521 				}
1522 				else
1523 					QR_set_permanent(res);
1524 			}
1525 		}
1526 	}
1527 	CONNLOCK_RELEASE(self);
1528 }
1529 
CC_mark_cursors_doubtful(ConnectionClass * self)1530 static void CC_mark_cursors_doubtful(ConnectionClass *self)
1531 {
1532 	int	i;
1533 	StatementClass	*stmt;
1534 	QResultClass	*res;
1535 
1536 	if (!self->ncursors)
1537 		return;
1538 	CONNLOCK_ACQUIRE(self);
1539 	for (i = 0; i < self->num_stmts; i++)
1540 	{
1541 		stmt = self->stmts[i];
1542 		if (NULL != stmt &&
1543 		    NULL != (res = SC_get_Result(stmt)) &&
1544 		    NULL != QR_get_cursor(res) &&
1545 		    !QR_is_permanent(res))
1546 			QR_set_survival_check(res);
1547 	}
1548 	CONNLOCK_RELEASE(self);
1549 }
1550 
CC_on_commit(ConnectionClass * conn)1551 void	CC_on_commit(ConnectionClass *conn)
1552 {
1553 	if (conn->on_commit_in_progress)
1554 		return;
1555 	conn->on_commit_in_progress = 1;
1556 	CONNLOCK_ACQUIRE(conn);
1557 	if (CC_is_in_trans(conn))
1558 	{
1559 		CC_set_no_trans(conn);
1560 		CC_set_no_manual_trans(conn);
1561 	}
1562 	CC_svp_init(conn);
1563 	CC_start_stmt(conn);
1564 	CC_clear_cursors(conn, FALSE);
1565 	CONNLOCK_RELEASE(conn);
1566 	CC_discard_marked_objects(conn);
1567 	CONNLOCK_ACQUIRE(conn);
1568 	if (conn->result_uncommitted)
1569 	{
1570 		CONNLOCK_RELEASE(conn);
1571 		ProcessRollback(conn, FALSE, FALSE);
1572 		CONNLOCK_ACQUIRE(conn);
1573 		conn->result_uncommitted = 0;
1574 	}
1575 	CONNLOCK_RELEASE(conn);
1576 	conn->on_commit_in_progress = 0;
1577 }
CC_on_abort(ConnectionClass * conn,unsigned int opt)1578 void	CC_on_abort(ConnectionClass *conn, unsigned int opt)
1579 {
1580 	BOOL	set_no_trans = FALSE;
1581 
1582 MYLOG(0, "entering opt=%x\n", opt);
1583 	CONNLOCK_ACQUIRE(conn);
1584 	if (0 != (opt & CONN_DEAD)) /* CONN_DEAD implies NO_TRANS also */
1585 		opt |= NO_TRANS;
1586 	if (CC_is_in_trans(conn))
1587 	{
1588 		if (0 != (opt & NO_TRANS))
1589 		{
1590 			CC_set_no_trans(conn);
1591 			CC_set_no_manual_trans(conn);
1592 			set_no_trans = TRUE;
1593 		}
1594 	}
1595 	CC_svp_init(conn);
1596 	CC_start_stmt(conn);
1597 	CC_clear_cursors(conn, TRUE);
1598 	if (0 != (opt & CONN_DEAD))
1599 	{
1600 		conn->status = CONN_DOWN;
1601 		if (conn->pqconn)
1602 		{
1603 			CONNLOCK_RELEASE(conn);
1604 			QLOG(0, "PQfinish: %p\n", conn->pqconn);
1605 			PQfinish(conn->pqconn);
1606 			CONNLOCK_ACQUIRE(conn);
1607 			conn->pqconn = NULL;
1608 		}
1609 	}
1610 	else if (set_no_trans)
1611 	{
1612 		CONNLOCK_RELEASE(conn);
1613 		CC_discard_marked_objects(conn);
1614 		CONNLOCK_ACQUIRE(conn);
1615 	}
1616 	if (conn->result_uncommitted)
1617 	{
1618 		CONNLOCK_RELEASE(conn);
1619 		ProcessRollback(conn, TRUE, FALSE);
1620 		CONNLOCK_ACQUIRE(conn);
1621 		conn->result_uncommitted = 0;
1622 	}
1623 	CONNLOCK_RELEASE(conn);
1624 }
1625 
CC_on_abort_partial(ConnectionClass * conn)1626 void	CC_on_abort_partial(ConnectionClass *conn)
1627 {
1628 MYLOG(0, "entering\n");
1629 	CONNLOCK_ACQUIRE(conn);
1630 	ProcessRollback(conn, TRUE, TRUE);
1631 	CC_discard_marked_objects(conn);
1632 	CONNLOCK_RELEASE(conn);
1633 }
1634 
1635 static BOOL
is_setting_search_path(const char * query)1636 is_setting_search_path(const char *query)
1637 {
1638 	const char *q = query;
1639 	if (strnicmp(q, "set", 3) != 0)
1640 		return FALSE;
1641 	q += 3;
1642 	while (isspace(*q)) q++;
1643 	for (; *q;)
1644 	{
1645 		if (IS_NOT_SPACE(*q))
1646 		{
1647 			if (strnicmp(q, "search_path", 11) == 0)
1648 				return TRUE;
1649 			q++;
1650 			while (IS_NOT_SPACE(*q))
1651 				q++;
1652 		}
1653 		else
1654 			q++;
1655 	}
1656 	return FALSE;
1657 }
1658 
1659 static BOOL
CC_from_PGresult(QResultClass * res,StatementClass * stmt,ConnectionClass * conn,const char * cursor,PGresult ** pgres)1660 CC_from_PGresult(QResultClass *res, StatementClass *stmt,
1661 				 ConnectionClass *conn, const char *cursor, PGresult **pgres)
1662 {
1663 	BOOL	success = TRUE;
1664 
1665 	if (!QR_from_PGresult(res, stmt, conn, cursor, pgres))
1666 	{
1667 		QLOG(0, "\tGetting result from PGresult failed\n");
1668 		success = FALSE;
1669 		if (0 >= CC_get_errornumber(conn))
1670 		{
1671 			switch (QR_get_rstatus(res))
1672 			{
1673 				case PORES_NO_MEMORY_ERROR:
1674 					CC_set_error(conn, CONN_NO_MEMORY_ERROR, NULL, __FUNCTION__);
1675 					break;
1676 				case PORES_BAD_RESPONSE:
1677 					CC_set_error(conn, CONNECTION_COMMUNICATION_ERROR, "communication error occured", __FUNCTION__);
1678 					break;
1679 				default:
1680 					CC_set_error(conn, CONN_EXEC_ERROR, QR_get_message(res), __FUNCTION__);
1681 					break;
1682 			}
1683 		}
1684 	}
1685 	return success;
1686 }
1687 
1688 int
CC_internal_rollback(ConnectionClass * self,int rollback_type,BOOL ignore_abort)1689 CC_internal_rollback(ConnectionClass *self, int rollback_type, BOOL ignore_abort)
1690 {
1691 	int	ret = 0;
1692 	char		cmd[128];
1693 	PGresult   *pgres = NULL;
1694 
1695 	if (!CC_is_in_error_trans(self))
1696 		return 1;
1697 	switch (rollback_type)
1698 	{
1699 		case PER_STATEMENT_ROLLBACK:
1700 			GenerateSvpCommand(self, INTERNAL_ROLLBACK_OPERATION, cmd, sizeof(cmd));
1701 			QLOG(0, "PQexec: %p '%s'\n", self->pqconn, cmd);
1702 			pgres = PQexec(self->pqconn, cmd);
1703 			switch (PQresultStatus(pgres))
1704 			{
1705 				case PGRES_COMMAND_OK:
1706 					QLOG(0, "\tok: - 'C' - %s\n", PQcmdStatus(pgres));
1707 				case PGRES_NONFATAL_ERROR:
1708 					ret = 1;
1709 					if (ignore_abort)
1710 						CC_set_no_error_trans(self);
1711 					LIBPQ_update_transaction_status(self);
1712 					break;
1713 				default:
1714 					handle_pgres_error(self, pgres, __FUNCTION__, NULL, TRUE);
1715 					break;
1716 			}
1717 			break;
1718 		case PER_QUERY_ROLLBACK:
1719 			SPRINTF_FIXED(cmd, "%s TO %s;%s %s"
1720 				, rbkcmd, per_query_svp , rlscmd, per_query_svp);
1721 			QLOG(0, "PQsendQuery: %p '%s'\n", self->pqconn, cmd);
1722 			PQsendQuery(self->pqconn, cmd);
1723 			ret = 0;
1724 			while (self->pqconn && (pgres = PQgetResult(self->pqconn)) != NULL)
1725 			{
1726 				switch (PQresultStatus(pgres))
1727 				{
1728 					case PGRES_COMMAND_OK:
1729 						QLOG(0, "\tok: - 'C' - %s\n", PQcmdTuples(pgres));
1730 						ret = 1;
1731 						break;
1732 					case PGRES_NONFATAL_ERROR:
1733 						ret = 1;
1734 					default:
1735 						handle_pgres_error(self, pgres, __FUNCTION__, NULL, !ret);
1736 				}
1737 			}
1738 			if (!ret)
1739 			{
1740 				if (ignore_abort)
1741 					CC_set_no_error_trans(self);
1742 				else
1743 					MYLOG(0, " return error\n");
1744 			}
1745 			LIBPQ_update_transaction_status(self);
1746 			break;
1747 	}
1748 	if (pgres)
1749 		PQclear(pgres);
1750 
1751 	return ret;
1752 }
1753 
1754 /*
1755  *	The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
1756  *	the same existing QResultClass (this occurs when the tuple cache is depleted and
1757  *	needs to be re-filled).
1758  *
1759  *	The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
1760  *	(i.e., C3326857) for SQL select statements.  This cursor is then used in future
1761  *	'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
1762  *
1763  * * If issue_begin, send "BEGIN"
1764  * * if needed, send "SAVEPOINT ..."
1765  * * Send "query", read result
1766  * * Send appendq, read result.
1767  *
1768  */
1769 QResultHold
CC_send_query_append(ConnectionClass * self,const char * query,QueryInfo * qi,UDWORD flag,StatementClass * stmt,const char * appendq)1770 CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt, const char *appendq)
1771 {
1772 	CSTR	func = "CC_send_query";
1773 	QResultHold	rhold = {0};
1774 	QResultClass *cmdres = NULL,
1775 			   *retres = NULL,
1776 			   *res = NULL;
1777 	BOOL	ignore_abort_on_conn = ((flag & IGNORE_ABORT_ON_CONN) != 0),
1778 		create_keyset = ((flag & CREATE_KEYSET) != 0),
1779 		issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self)),
1780 		rollback_on_error, query_rollback, end_with_commit,
1781 		read_only, prepend_savepoint = FALSE,
1782 		ignore_roundtrip_time = ((self->connInfo.extra_opts & BIT_IGNORE_ROUND_TRIP_TIME) != 0);
1783 
1784 	char		*ptr;
1785 	BOOL		ReadyToReturn = FALSE,
1786 				query_completed = FALSE,
1787 				aborted = FALSE,
1788 				used_passed_result_object = FALSE,
1789 			discard_next_begin = FALSE,
1790 			discard_next_savepoint = FALSE,
1791 			discard_next_release = FALSE,
1792 			consider_rollback;
1793 	BOOL	discardTheRest = FALSE;
1794 	int		func_cs_count = 0;
1795 	PQExpBufferData		query_buf = {0};
1796 	size_t		query_len;
1797 
1798 	/* QR_set_command() dups this string so doesn't need static */
1799 	char	   *cmdbuffer;
1800 	PGresult   *pgres = NULL;
1801 	notice_receiver_arg nrarg;
1802 
1803 	if (appendq)
1804 	{
1805 		MYLOG(0, "conn=%p, query='%s'+'%s'\n", self, query, appendq);
1806 	}
1807 	else
1808 	{
1809 		MYLOG(0, "conn=%p, query='%s'\n", self, query);
1810 	}
1811 
1812 	if (!self->pqconn)
1813 	{
1814 		PQExpBufferData	pbuf = {0};
1815 		initPQExpBuffer(&pbuf);
1816 		appendPQExpBuffer(&pbuf, "The connection is down\nFailed to send '%s'", query);
1817 		CC_set_error(self, CONNECTION_COULD_NOT_SEND, pbuf.data, func);
1818 		termPQExpBuffer(&pbuf);
1819 		return rhold;
1820 	}
1821 
1822 	ENTER_INNER_CONN_CS(self, func_cs_count);
1823 /* Indicate that we are sending a query to the backend */
1824 	if ((NULL == query) || (query[0] == '\0'))
1825 	{
1826 		CLEANUP_FUNC_CONN_CS(func_cs_count, self);
1827 		return rhold;
1828 	}
1829 
1830 	/*
1831 	 *	In case the round trip time can be ignored, the query
1832 	 *	and the appeneded query would be issued separately.
1833 	 *	Otherwise a multiple command query would be issued.
1834 	 */
1835 	if (appendq && ignore_roundtrip_time)
1836 	{
1837 		QResultHold rholda;
1838 
1839 		rhold = CC_send_query_append(self, query, qi, flag, stmt, NULL);
1840 		if (QR_command_maybe_successful(rhold.first))
1841 		{
1842 			rholda = CC_send_query_append(self, appendq, qi, flag & (~(GO_INTO_TRANSACTION)), stmt, NULL);
1843 			if (QR_command_maybe_successful(rholda.first))
1844 				QR_concat(rhold.last, rholda.first);
1845 			else
1846 			{
1847 				QR_Destructor(rhold.first);
1848 				rhold = rholda;
1849 			}
1850 		}
1851 		CLEANUP_FUNC_CONN_CS(func_cs_count, self);
1852 		return rhold;
1853 	}
1854 
1855 	rollback_on_error = (flag & ROLLBACK_ON_ERROR) != 0;
1856 	end_with_commit = (flag & END_WITH_COMMIT) != 0;
1857 	read_only = (flag & READ_ONLY_QUERY) != 0;
1858 #define	return DONT_CALL_RETURN_FROM_HERE???
1859 	consider_rollback = (issue_begin || (CC_is_in_trans(self) && !CC_is_in_error_trans(self)) || strnicmp(query, "begin", 5) == 0);
1860 	if (rollback_on_error)
1861 		rollback_on_error = consider_rollback;
1862 	query_rollback = (rollback_on_error && !end_with_commit && PG_VERSION_GE(self, 8.0));
1863 	if (!query_rollback && consider_rollback && !end_with_commit)
1864 	{
1865 		if (stmt)
1866 		{
1867 			StatementClass	*astmt = SC_get_ancestor(stmt);
1868 			unsigned int svpopt = 0;
1869 
1870 			if (read_only)
1871 				svpopt |= SVPOPT_RDONLY;
1872 			if (!ignore_roundtrip_time)
1873 				svpopt |= SVPOPT_REDUCE_ROUNDTRIP;
1874 			if (!CC_started_rbpoint(self))
1875 			{
1876 				if (SQL_ERROR == SetStatementSvp(astmt, svpopt))
1877 				{
1878 					SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error", func);
1879 					goto cleanup;
1880 				}
1881 			}
1882 		}
1883 	}
1884 
1885 	/* prepend internal savepoint command ? */
1886 	if (PREPEND_IN_PROGRESS == self->internal_op)
1887 		prepend_savepoint = TRUE;
1888 
1889 	/* append all these together, to avoid round-trips */
1890 	query_len = strlen(query);
1891 	MYLOG(0, "query_len=" FORMAT_SIZE_T "\n", query_len);
1892 
1893 	initPQExpBuffer(&query_buf);
1894 	/* issue_begin, query_rollback and prepend_savepoint are exclusive */
1895 	if (issue_begin)
1896 	{
1897 		appendPQExpBuffer(&query_buf, "%s;", bgncmd);
1898 		discard_next_begin = TRUE;
1899 	}
1900 	else if (query_rollback)
1901 	{
1902 		appendPQExpBuffer(&query_buf, "%s %s;", svpcmd, per_query_svp);
1903 		discard_next_savepoint = TRUE;
1904 	}
1905 	else if (prepend_savepoint)
1906 	{
1907 		char   	prepend_cmd[128];
1908 
1909 		GenerateSvpCommand(self, INTERNAL_SAVEPOINT_OPERATION, prepend_cmd, sizeof(prepend_cmd));
1910 		appendPQExpBuffer(&query_buf, "%s;", prepend_cmd);
1911 		self->internal_op = SAVEPOINT_IN_PROGRESS;
1912 	}
1913 	appendPQExpBufferStr(&query_buf, query);
1914 	if (appendq)
1915 	{
1916 		appendPQExpBuffer(&query_buf, ";%s", appendq);
1917 	}
1918 	if (query_rollback)
1919 	{
1920 		appendPQExpBuffer(&query_buf, ";%s %s", rlscmd, per_query_svp);
1921 	}
1922 	if (PQExpBufferDataBroken(query_buf))
1923 	{
1924 		CC_set_error(self, CONN_NO_MEMORY_ERROR, "Couldn't alloc buffer for query.", "");
1925 		goto cleanup;
1926 	}
1927 
1928 	/* Set up notice receiver */
1929 	nrarg.conn = self;
1930 	nrarg.comment = func;
1931 	nrarg.res = NULL;
1932 	nrarg.stmt = stmt;
1933 	PQsetNoticeReceiver(self->pqconn, receive_libpq_notice, &nrarg);
1934 
1935 	QLOG(0, "PQsendQuery: %p '%s'\n", self->pqconn, query_buf.data);
1936 	if (!PQsendQuery(self->pqconn, query_buf.data))
1937 	{
1938 		char *errmsg = PQerrorMessage(self->pqconn);
1939 		QLOG(0, "\nCommunication Error: %s\n", SAFE_STR(errmsg));
1940 		CC_set_error(self, CONNECTION_COMMUNICATION_ERROR, errmsg, func);
1941 		goto cleanup;
1942 	}
1943 	PQsetSingleRowMode(self->pqconn);
1944 
1945 	cmdres = qi ? qi->result_in : NULL;
1946 	if (cmdres)
1947 		used_passed_result_object = TRUE;
1948 	else
1949 	{
1950 		cmdres = QR_Constructor();
1951 		if (!cmdres)
1952 		{
1953 			CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
1954 			goto cleanup;
1955 		}
1956 	}
1957 	res = cmdres;
1958 	if (qi)
1959 	{
1960 		res->cmd_fetch_size = qi->fetch_size;
1961 		res->cache_size = qi->row_size;
1962 	}
1963 	nrarg.res = res;
1964 
1965 	while (self->pqconn && (pgres = PQgetResult(self->pqconn)) != NULL)
1966 	{
1967 		int status = PQresultStatus(pgres);
1968 
1969 		if (discardTheRest)
1970 			continue;
1971 		switch (status)
1972 		{
1973 			case PGRES_COMMAND_OK:
1974 				/* portal query command, no tuples returned */
1975 				/* read in the return message from the backend */
1976 				cmdbuffer = PQcmdStatus(pgres);
1977 				QLOG(0, "\tok: - 'C' - %s\n", cmdbuffer);
1978 
1979 				if (query_completed)	/* allow for "show" style notices */
1980 				{
1981 					QR_concat(res, QR_Constructor());
1982 					if (!QR_nextr(res))
1983 					{
1984 						CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
1985 						ReadyToReturn = TRUE;
1986 						retres = NULL;
1987 						break;
1988 					}
1989 					res = QR_nextr(res);
1990 					nrarg.res = res;
1991 				}
1992 
1993 				MYLOG(0, " setting cmdbuffer = '%s'\n", cmdbuffer);
1994 
1995 				my_trim(cmdbuffer); /* get rid of trailing space */
1996 				if (strnicmp(cmdbuffer, bgncmd, strlen(bgncmd)) == 0)
1997 				{
1998 					CC_set_in_trans(self);
1999 					if (discard_next_begin) /* discard the automatically issued BEGIN */
2000 					{
2001 						discard_next_begin = FALSE;
2002 						break; /* discard the result */
2003 					}
2004 				}
2005 				/*
2006 				 * There are 2 risks to RELEASE an internal savepoint.
2007 				 * One is to RELEASE the savepoint invalitated
2008 				 * due to manually issued ROLLBACK or RELEASE.
2009 				 * Another is to invalitate manual SAVEPOINTs unexpectedly
2010 				 * by RELEASing the internal savepoint.
2011 				 */
2012 				else if (strnicmp(cmdbuffer, svpcmd, strlen(svpcmd)) == 0)
2013 				{
2014 					if (discard_next_savepoint)
2015 					{
2016 						discard_next_savepoint = FALSE;
2017 						discard_next_release = TRUE;
2018 MYLOG(DETAIL_LOG_LEVEL, "Discarded a SAVEPOINT result\n");
2019 						break; /* discard the result */
2020 					}
2021 					if (SAVEPOINT_IN_PROGRESS == self->internal_op)
2022 					{
2023 						CC_start_rbpoint(self);
2024 						self->internal_op = 0;
2025 						break; /* discard the result */
2026 					}
2027 					/* Don't release the internal savepoint */
2028 					self->internal_svp = 0;
2029 				}
2030 				else if (strnicmp(cmdbuffer, rbkcmd, strlen(rbkcmd)) == 0)
2031 				{
2032 					CC_mark_cursors_doubtful(self);
2033 					CC_set_in_error_trans(self); /* mark the transaction error in case of manual rollback */
2034 					self->internal_svp = 0; /* possibly an internal savepoint is invalid */
2035 					self->opt_previous = 0; /* unknown */
2036 					CC_init_opt_in_progress(self);
2037 				}
2038 				else if (strnicmp(cmdbuffer, rlscmd, strlen(rlscmd)) == 0)
2039 				{
2040 					if (discard_next_release)
2041 					{
2042 MYLOG(DETAIL_LOG_LEVEL, "Discarded a RELEASE result\n");
2043 						discard_next_release = FALSE;
2044 						break; /* discard the result */
2045 					}
2046 					self->internal_svp = 0;
2047 					if (SAVEPOINT_IN_PROGRESS == self->internal_op)
2048 						break; /* discard the result */
2049 				}
2050 				/*
2051 				 *	DROP TABLE or ALTER TABLE may change
2052 				 *	the table definition. So clear the
2053 				 *	col_info cache though it may be too simple.
2054 				 */
2055 				else if (strnicmp(cmdbuffer, "DROP TABLE", 10) == 0 ||
2056 						 strnicmp(cmdbuffer, "ALTER TABLE", 11) == 0)
2057 					CC_clear_col_info(self, FALSE);
2058 				else
2059 				{
2060 					ptr = strrchr(cmdbuffer, ' ');
2061 					if (ptr)
2062 						res->recent_processed_row_count = atoi(ptr + 1);
2063 					else
2064 						res->recent_processed_row_count = -1;
2065 					if (self->current_schema_valid &&
2066 						strnicmp(cmdbuffer, "SET", 3) == 0)
2067 					{
2068 						if (is_setting_search_path(query))
2069 							reset_current_schema(self);
2070 					}
2071 				}
2072 
2073 				if (QR_command_successful(res))
2074 					QR_set_rstatus(res, PORES_COMMAND_OK);
2075 				QR_set_command(res, cmdbuffer);
2076 				query_completed = TRUE;
2077 				MYLOG(0, " returning res = %p\n", res);
2078 				break;
2079 
2080 			case PGRES_EMPTY_QUERY:
2081 				/* We return the empty query */
2082 				QR_set_rstatus(res, PORES_EMPTY_QUERY);
2083 				break;
2084 			case PGRES_NONFATAL_ERROR:
2085 				handle_pgres_error(self, pgres, "send_query", res, FALSE);
2086 				if (stmt)
2087 					stmt->has_notice = 1;
2088 				break;
2089 
2090 			case PGRES_BAD_RESPONSE:
2091 			case PGRES_FATAL_ERROR:
2092 				handle_pgres_error(self, pgres, "send_query", res, TRUE);
2093 
2094 				/* We should report that an error occured. Zoltan */
2095 				aborted = TRUE;
2096 
2097 				query_completed = TRUE;
2098 				break;
2099 			case PGRES_TUPLES_OK:
2100 				QLOG(0, "\tok: - 'T' - %s\n", PQcmdStatus(pgres));
2101 			case PGRES_SINGLE_TUPLE:
2102 				if (query_completed)
2103 				{
2104 					QR_concat(res, QR_Constructor());
2105 					if (!QR_nextr(res))
2106 					{
2107 						CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
2108 						ReadyToReturn = TRUE;
2109 						retres = NULL;
2110 						break;
2111 					}
2112 					if (create_keyset)
2113 					{
2114 						QR_set_haskeyset(QR_nextr(res));
2115 						if (stmt)
2116 						{
2117 							if (stmt->num_key_fields < 0) /* for safety */
2118 								CheckPgClassInfo(stmt);
2119 							QR_nextr(res)->num_key_fields = stmt->num_key_fields;
2120 						}
2121 					}
2122 					MYLOG(0, " 'T' no result_in: res = %p\n", QR_nextr(res));
2123 					res = QR_nextr(res);
2124 					nrarg.res = res;
2125 
2126 					if (qi)
2127 					{
2128 						QR_set_cache_size(res, qi->row_size);
2129 						res->cmd_fetch_size = qi->fetch_size;
2130 					}
2131 				}
2132 				if (!used_passed_result_object)
2133 				{
2134 					const char *cursor = qi ? qi->cursor : NULL;
2135 					if (create_keyset)
2136 					{
2137 						QR_set_haskeyset(res);
2138 						if (stmt)
2139 						{
2140 							if (stmt->num_key_fields < 0) /* for safety */
2141 								CheckPgClassInfo(stmt);
2142 							res->num_key_fields = stmt->num_key_fields;
2143 						}
2144 						if (cursor && cursor[0])
2145 							QR_set_synchronize_keys(res);
2146 					}
2147 					if (CC_from_PGresult(res, stmt, self, cursor, &pgres))
2148 						query_completed = TRUE;
2149 					else
2150 					{
2151 						aborted = TRUE;
2152 						if (QR_command_maybe_successful(res))
2153 							retres = NULL;
2154 						else
2155 							retres = cmdres;
2156 					}
2157 				}
2158 				else
2159 				{				/* next fetch, so reuse an existing result */
2160 					const char *cursor = res->cursor_name;
2161 
2162 					/*
2163 					 * called from QR_next_tuple and must return
2164 					 * immediately.
2165 					 */
2166 					if (!CC_from_PGresult(res, stmt, NULL, cursor, &pgres))
2167 					{
2168 						retres = NULL;
2169 						break;
2170 					}
2171 					retres = cmdres;
2172 				}
2173 				if (res->rstatus == PORES_TUPLES_OK && res->notice)
2174 				{
2175 					QR_set_rstatus(res, PORES_NONFATAL_ERROR);
2176 				}
2177 				else if (PORES_NO_MEMORY_ERROR == QR_get_rstatus(res))
2178 				{
2179 					PGcancel *cancel;
2180 					char	dummy[8];
2181 
2182 					discardTheRest = TRUE;
2183 					if (NULL != (cancel = PQgetCancel(self->pqconn)))
2184 					{
2185 						PQcancel(cancel, dummy, sizeof(dummy));
2186 						PQfreeCancel(cancel);
2187 					}
2188 					else
2189 						goto cleanup;
2190 				}
2191 				break;
2192 			case PGRES_COPY_OUT:
2193 				/* XXX: We used to read from stdin here. Does that make any sense? */
2194 			case PGRES_COPY_IN:
2195 				if (query_completed)
2196 				{
2197 					QR_concat(res, QR_Constructor());
2198 					if (!QR_nextr(res))
2199 					{
2200 						CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
2201 						ReadyToReturn = TRUE;
2202 						retres = NULL;
2203 						break;
2204 					}
2205 					res = QR_nextr(res);
2206 					nrarg.res = res;
2207 				}
2208 				QR_set_rstatus(res, PORES_COPY_IN);
2209 				ReadyToReturn = TRUE;
2210 				retres = cmdres;
2211 				break;
2212 			case PGRES_COPY_BOTH:
2213 			default:
2214 				/* skip the unexpected response if possible */
2215 				CC_set_error(self, CONNECTION_BACKEND_CRAZY, "Unexpected result status (send_query)", func);
2216 				handle_pgres_error(self, pgres, "send_query", res, TRUE);
2217 				CC_on_abort(self, CONN_DEAD);
2218 
2219 				MYLOG(0, " error - %s\n", CC_get_errormsg(self));
2220 				ReadyToReturn = TRUE;
2221 				retres = NULL;
2222 				break;
2223 		}
2224 
2225 		if (pgres)
2226 		{
2227 			PQclear(pgres);
2228 			pgres = NULL;
2229 		}
2230 	}
2231 
2232 cleanup:
2233 	if (self->pqconn)
2234 		PQsetNoticeReceiver(self->pqconn, receive_libpq_notice, NULL);
2235 	if (pgres != NULL)
2236 	{
2237 		PQclear(pgres);
2238 		pgres = NULL;
2239 	}
2240 MYLOG(DETAIL_LOG_LEVEL, " rollback_on_error=%d CC_is_in_trans=%d discard_next_savepoint=%d query_rollback=%d\n", rollback_on_error, CC_is_in_trans(self), discard_next_savepoint, query_rollback);
2241 	if (rollback_on_error && CC_is_in_trans(self) && !discard_next_savepoint)
2242 	{
2243 		if (query_rollback)
2244 		{
2245 			if (!CC_internal_rollback(self, PER_QUERY_ROLLBACK, ignore_abort_on_conn))
2246 				ignore_abort_on_conn = FALSE;
2247 		}
2248 		else if (CC_is_in_error_trans(self))
2249 		{
2250 			QLOG(0, "PQexec: %p '%s'\n", self->pqconn, rbkcmd);
2251 			pgres = PQexec(self->pqconn, rbkcmd);
2252 		}
2253 		/*
2254 		 * XXX: we don't check the result here. Should we? We're rolling back,
2255 		 * so it's not clear what else we can do on error. Giving an error
2256 		 * message to the application would be nice though.
2257 		 */
2258 		if (pgres != NULL)
2259 		{
2260 			PQclear(pgres);
2261 			pgres = NULL;
2262 		}
2263 	}
2264 
2265 	CLEANUP_FUNC_CONN_CS(func_cs_count, self);
2266 #undef	return
2267 	/*
2268 	 * Break before being ready to return.
2269 	 */
2270 	if (!ReadyToReturn)
2271 		retres = cmdres;
2272 
2273 	if (!PQExpBufferDataBroken(query_buf))
2274 		termPQExpBuffer(&query_buf);
2275 
2276 	/*
2277 	 * Cleanup garbage results before returning.
2278 	 */
2279 	if (cmdres && retres != cmdres && !used_passed_result_object)
2280 		QR_Destructor(cmdres);
2281 	/*
2282 	 * Cleanup the aborted result if specified
2283 	 */
2284 	if (retres)
2285 	{
2286 		if (aborted)
2287 		{
2288 			/** if (ignore_abort_on_conn)
2289 			{
2290 				if (!used_passed_result_object)
2291 				{
2292 					QR_Destructor(retres);
2293 					retres = NULL;
2294 				}
2295 			} **/
2296 			if (retres)
2297 			{
2298 				/*
2299 				 *	discard results other than errors.
2300 				 */
2301 				QResultClass	*qres;
2302 				for (qres = retres; QR_nextr(qres); qres = retres)
2303 				{
2304 					if (QR_get_aborted(qres))
2305 						break;
2306 					retres = QR_nextr(qres);
2307 					QR_detach(qres);
2308 					QR_Destructor(qres);
2309 				}
2310 				/*
2311 				 *	If error message isn't set
2312 				 */
2313 				if (ignore_abort_on_conn)
2314 				{
2315 					CC_set_errornumber(self, CONN_ERROR_IGNORED);
2316 					if (retres)
2317 						QR_set_rstatus(retres, PORES_NONFATAL_ERROR);
2318 MYLOG(DETAIL_LOG_LEVEL, " ignored abort_on_conn\n");
2319 				}
2320 				else if (retres)
2321 				{
2322 					if (NULL == CC_get_errormsg(self) ||
2323 					    !CC_get_errormsg(self)[0])
2324 						CC_set_errormsg(self, QR_get_message(retres));
2325 					if (!self->sqlstate[0])
2326 						STRCPY_FIXED(self->sqlstate, retres->sqlstate);
2327 				}
2328 			}
2329 		}
2330 	}
2331 
2332 	/*
2333 	 * Update our copy of the transaction status.
2334 	 *
2335 	 * XXX: Once we stop using the socket directly, and do everything with
2336 	 * libpq, we can get rid of the transaction_status field altogether
2337 	 * and always ask libpq for it.
2338 	 */
2339 	LIBPQ_update_transaction_status(self);
2340 
2341 	if (retres)
2342 		QR_set_conn(retres, self);
2343 	rhold.first = retres;
2344 	rhold.last = res;
2345 	return rhold;
2346 }
2347 
2348 #define MAX_SEND_FUNC_ARGS	3
2349 static const char *func_param_str[MAX_SEND_FUNC_ARGS + 1] =
2350 {
2351 	"()",
2352 	"($1)",
2353 	"($1, $2)",
2354 	"($1, $2, $3)"
2355 };
2356 
2357 static
odbc_hton64(Int8 h64)2358 Int8 odbc_hton64(Int8 h64)
2359 {
2360 	union {
2361 		Int8	n64;
2362 		UInt4	i32[2];
2363 	} u;
2364 
2365 	u.i32[0] = htonl((UInt4) (h64 >> 32));
2366 	u.i32[1] = htonl((UInt4) h64);
2367 
2368 	return u.n64;
2369 }
2370 
2371 static
odbc_ntoh64(Int8 n64)2372 Int8 odbc_ntoh64(Int8 n64)
2373 {
2374 	union {
2375 		Int8	h64;
2376 		UInt4	i32[2];
2377 	} u;
2378 	Int8 result;
2379 
2380 	u.h64 = n64;
2381 	result = ntohl(u.i32[0]);
2382 	result <<= 32;
2383 	result |= ntohl(u.i32[1]);
2384 
2385 	return result;
2386 }
2387 
2388 
2389 int
CC_send_function(ConnectionClass * self,const char * fn_name,void * result_buf,int * actual_result_len,int result_is_int,LO_ARG * args,int nargs)2390 CC_send_function(ConnectionClass *self, const char *fn_name, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
2391 {
2392 	int			i;
2393 	int			ret = FALSE;
2394 	int			func_cs_count = 0;
2395 	char		sqlbuffer[1000];
2396 	PGresult   *pgres = NULL;
2397 	Oid			paramTypes[MAX_SEND_FUNC_ARGS];
2398 	char	   *paramValues[MAX_SEND_FUNC_ARGS];
2399 	int			paramLengths[MAX_SEND_FUNC_ARGS];
2400 	int			paramFormats[MAX_SEND_FUNC_ARGS];
2401 	Int4		intParamBufs[MAX_SEND_FUNC_ARGS];
2402 	Int8		int8ParamBufs[MAX_SEND_FUNC_ARGS];
2403 
2404 	MYLOG(0, "conn=%p, fn_name=%s, result_is_int=%d, nargs=%d\n", self, fn_name, result_is_int, nargs);
2405 
2406 	/* Finish the pending extended query first */
2407 #define	return DONT_CALL_RETURN_FROM_HERE???
2408 	ENTER_INNER_CONN_CS(self, func_cs_count);
2409 
2410 	SPRINTF_FIXED(sqlbuffer, "SELECT pg_catalog.%s%s", fn_name,
2411 			 func_param_str[nargs]);
2412 	for (i = 0; i < nargs; ++i)
2413 	{
2414 		MYLOG(0, "  arg[%d]: len = %d, isint = %d, integer = " FORMATI64 ", ptr = %p\n", i, args[i].len, args[i].isint, args[i].isint == 2 ? args[i].u.integer64 : args[i].u.integer, args[i].u.ptr);
2415 		/* integers are sent as binary, others as text */
2416 		if (args[i].isint == 2)
2417 		{
2418 			paramTypes[i] = PG_TYPE_INT8;
2419 			int8ParamBufs[i] = odbc_hton64(args[i].u.integer64);
2420 			paramValues[i] = (char *) &int8ParamBufs[i];
2421 			paramLengths[i] = 8;
2422 			paramFormats[i] = 1;
2423 		}
2424 		else if (args[i].isint)
2425 		{
2426 			paramTypes[i] = PG_TYPE_INT4;
2427 			intParamBufs[i] = htonl(args[i].u.integer);
2428 			paramValues[i] = (char *) &intParamBufs[i];
2429 			paramLengths[i] = 4;
2430 			paramFormats[i] = 1;
2431 		}
2432 		else
2433 		{
2434 			paramTypes[i] = 0;
2435 			paramValues[i] = args[i].u.ptr;
2436 			paramLengths[i] = args[i].len;
2437 			paramFormats[i] = 1;
2438 		}
2439 	}
2440 
2441 	QLOG(0, "PQexecParams: %p '%s' nargs=%d\n", self->pqconn, sqlbuffer, nargs);
2442 	pgres = PQexecParams(self->pqconn, sqlbuffer, nargs,
2443 						 paramTypes, (const char * const *) paramValues,
2444 						 paramLengths, paramFormats, 1);
2445 
2446 	MYLOG(0, "done sending function\n");
2447 
2448 	if (PQresultStatus(pgres) == PGRES_TUPLES_OK)
2449 		QLOG(0, "\tok: - 'T' - %s\n", PQcmdStatus(pgres));
2450 	else
2451 	{
2452 		handle_pgres_error(self, pgres, "send_query", NULL, TRUE);
2453 		goto cleanup;
2454 	}
2455 
2456 	if (PQnfields(pgres) != 1 || PQntuples(pgres) != 1)
2457 	{
2458 		CC_set_errormsg(self, "unexpected result set from large_object function");
2459 		goto cleanup;
2460 	}
2461 
2462 	*actual_result_len = PQgetlength(pgres, 0, 0);
2463 
2464 	QLOG(0, "\tgot result with length: %d\n", *actual_result_len);
2465 
2466 	if (*actual_result_len > 0)
2467 	{
2468 		char *value = PQgetvalue(pgres, 0, 0);
2469 		if (result_is_int == 2)
2470 		{
2471 			Int8 int8val;
2472 			memcpy(&int8val, value, sizeof(Int8));
2473 			int8val = odbc_ntoh64(int8val);
2474 			memcpy(result_buf, &int8val, sizeof(Int8));
2475 MYLOG(0, "int8 result=" FORMATI64 "\n", int8val);
2476 		}
2477 		else if (result_is_int)
2478 		{
2479 			Int4 int4val;
2480 			memcpy(&int4val, value, sizeof(Int4));
2481 			int4val = ntohl(int4val);
2482 			memcpy(result_buf, &int4val, sizeof(Int4));
2483 		}
2484 		else
2485 			memcpy(result_buf, value, *actual_result_len);
2486 	}
2487 
2488 	ret = TRUE;
2489 
2490 cleanup:
2491 #undef	return
2492 	CLEANUP_FUNC_CONN_CS(func_cs_count, self);
2493 	if (pgres)
2494 		PQclear(pgres);
2495 	return ret;
2496 }
2497 
2498 
2499 char
CC_send_settings(ConnectionClass * self,const char * set_query)2500 CC_send_settings(ConnectionClass *self, const char *set_query)
2501 {
2502 	HSTMT		hstmt;
2503 	RETCODE		result;
2504 	char		status = TRUE;
2505 	char	   *cs,
2506 			   *ptr;
2507 #ifdef	HAVE_STRTOK_R
2508 	char	*last;
2509 #endif /* HAVE_STRTOK_R */
2510 	CSTR func = "CC_send_settings";
2511 
2512 
2513 	MYLOG(0, "entering...\n");
2514 
2515 	if (set_query == NULL) return TRUE;
2516 
2517 /*
2518  *	This function must use the local odbc API functions since the odbc state
2519  *	has not transitioned to "connected" yet.
2520  */
2521 
2522 	result = PGAPI_AllocStmt(self, &hstmt, 0);
2523 	if (!SQL_SUCCEEDED(result))
2524 		return FALSE;
2525 
2526 	/* non-external handle ensures no BEGIN/COMMIT/ABORT stuff */
2527 
2528 	cs = strdup(set_query);
2529 	if (cs == NULL)
2530 	{
2531 		CC_set_error(self, CONN_NO_MEMORY_ERROR, "Couldn't alloc buffer for query.", func);
2532 		return FALSE;
2533 	}
2534 
2535 #ifdef	HAVE_STRTOK_R
2536 	ptr = strtok_r(cs, ";", &last);
2537 #else
2538 	ptr = strtok(cs, ";");
2539 #endif /* HAVE_STRTOK_R */
2540 	while (ptr)
2541 	{
2542 		result = PGAPI_ExecDirect(hstmt, (SQLCHAR *) ptr, SQL_NTS, 0);
2543 		if (!SQL_SUCCEEDED(result))
2544 			status = FALSE;
2545 
2546 		MYLOG(0, "result %d, status %d from '%s'\n", result, status, ptr);
2547 
2548 #ifdef	HAVE_STRTOK_R
2549 		ptr = strtok_r(NULL, ";", &last);
2550 #else
2551 		ptr = strtok(NULL, ";");
2552 #endif /* HAVE_STRTOK_R */
2553 	}
2554 	free(cs);
2555 
2556 	PGAPI_FreeStmt(hstmt, SQL_DROP);
2557 
2558 	return status;
2559 }
2560 
2561 
2562 /*
2563  *	This function is just a hack to get the oid of our Large Object oid type.
2564  *	If a real Large Object oid type is made part of Postgres, this function
2565  *	will go away and the define 'PG_TYPE_LO' will be updated.
2566  */
2567 static SQLRETURN
CC_lookup_lo(ConnectionClass * self)2568 CC_lookup_lo(ConnectionClass *self)
2569 {
2570 	SQLRETURN	ret = SQL_SUCCESS;
2571 	QResultClass	*res;
2572 
2573 	MYLOG(0, "entering...\n");
2574 
2575 	res = CC_send_query(self, "select oid, typbasetype from pg_type where typname = '"  PG_TYPE_LO_NAME "'",
2576 		NULL, READ_ONLY_QUERY, NULL);
2577 
2578 	if (!QR_command_maybe_successful(res))
2579 		ret = SQL_ERROR;
2580 	else if (QR_command_maybe_successful(res) && QR_get_num_cached_tuples(res) > 0)
2581 	{
2582 		OID	basetype;
2583 
2584 		self->lobj_type = QR_get_value_backend_int(res, 0, 0, NULL);
2585 		basetype = QR_get_value_backend_int(res, 0, 1, NULL);
2586 		if (PG_TYPE_OID == basetype)
2587 			self->lo_is_domain = 1;
2588 		else if (0 != basetype)
2589 			self->lobj_type = 0;
2590 	}
2591 	QR_Destructor(res);
2592 	MYLOG(0, "Got the large object oid: %d\n", self->lobj_type);
2593 	return ret;
2594 }
2595 
2596 
2597 /*
2598  *	This function initializes the version of PostgreSQL from
2599  *	connInfo.protocol that we're connected to.
2600  *	h-inoue 01-2-2001
2601  */
2602 void
CC_initialize_pg_version(ConnectionClass * self)2603 CC_initialize_pg_version(ConnectionClass *self)
2604 {
2605 	STRCPY_FIXED(self->pg_version, "7.4");
2606 	self->pg_version_major = 7;
2607 	self->pg_version_minor = 4;
2608 }
2609 
2610 
2611 void
CC_log_error(const char * func,const char * desc,const ConnectionClass * self)2612 CC_log_error(const char *func, const char *desc, const ConnectionClass *self)
2613 {
2614 #define NULLCHECK(a) (a ? a : "(NULL)")
2615 
2616 	if (self)
2617 	{
2618 		MYLOG(0, "CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, NULLCHECK(self->__error_message));
2619 		MYLOG(DETAIL_LOG_LEVEL, "            ------------------------------------------------------------\n");
2620 		MYLOG(DETAIL_LOG_LEVEL, "            henv=%p, conn=%p, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
2621 		MYLOG(DETAIL_LOG_LEVEL, "            pqconn=%p, stmts=%p, lobj_type=%d\n", self->pqconn, self->stmts, self->lobj_type);
2622 	}
2623 	else
2624 	{
2625 		MYLOG(0, "INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
2626 	}
2627 }
2628 
2629 /*
2630  *	This doesn't really return the CURRENT SCHEMA
2631  *	but there's no alternative.
2632  */
2633 const char *
CC_get_current_schema(ConnectionClass * conn)2634 CC_get_current_schema(ConnectionClass *conn)
2635 {
2636 	if (!conn->current_schema_valid)
2637 	{
2638 		QResultClass	*res;
2639 
2640 		if (res = CC_send_query(conn, "select current_schema()", NULL, READ_ONLY_QUERY, NULL), QR_command_maybe_successful(res))
2641 		{
2642 			if (QR_get_num_total_tuples(res) == 1)
2643 			{
2644 				char *curschema = QR_get_value_backend_text(res, 0, 0);
2645 				if (curschema)
2646 					conn->current_schema = strdup(curschema);
2647 			}
2648 			if (conn->current_schema)
2649 				conn->current_schema_valid = TRUE;
2650 		}
2651 		QR_Destructor(res);
2652 	}
2653 	return (const char *) conn->current_schema;
2654 }
2655 
CC_mark_a_object_to_discard(ConnectionClass * conn,int type,const char * plan)2656 int	CC_mark_a_object_to_discard(ConnectionClass *conn, int type, const char *plan)
2657 {
2658 	int	cnt = conn->num_discardp + 1, plansize;
2659 	char	*pname;
2660 
2661 	CC_REALLOC_return_with_error(conn->discardp, char *,
2662 		(cnt * sizeof(char *)), conn, "Couldn't alloc discardp.", -1);
2663 	plansize = strlen(plan) + 2;
2664 	CC_MALLOC_return_with_error(pname, char, plansize,
2665 		conn, "Couldn't alloc discardp mem.", -1);
2666 	pname[0] = (char) type;	/* 's':prepared statement 'p':cursor */
2667 	strncpy_null(pname + 1, plan, plansize - 1);
2668 	conn->discardp[conn->num_discardp++] = pname;
2669 
2670 	return 1;
2671 }
2672 
CC_discard_marked_objects(ConnectionClass * conn)2673 int	CC_discard_marked_objects(ConnectionClass *conn)
2674 {
2675 	int	i, cnt;
2676 	QResultClass *res;
2677 	char	*pname, cmd[64];
2678 
2679 	if ((cnt = conn->num_discardp) <= 0)
2680 		return 0;
2681 	for (i = cnt - 1; i >= 0; i--)
2682 	{
2683 		pname = conn->discardp[i];
2684 		if ('s' == pname[0])
2685 			SPRINTF_FIXED(cmd, "DEALLOCATE \"%s\"", pname + 1);
2686 		else
2687 			SPRINTF_FIXED(cmd, "CLOSE \"%s\"", pname + 1);
2688 		res = CC_send_query(conn, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN | READ_ONLY_QUERY, NULL);
2689 		QR_Destructor(res);
2690 		free(conn->discardp[i]);
2691 		conn->num_discardp--;
2692 	}
2693 
2694 	return 1;
2695 }
2696 
2697 static void
LIBPQ_update_transaction_status(ConnectionClass * self)2698 LIBPQ_update_transaction_status(ConnectionClass *self)
2699 {
2700 	if (!self->pqconn)
2701 		return;
2702 
2703 	MYLOG(DETAIL_LOG_LEVEL, "transactionStatus=%d\n", PQtransactionStatus(self->pqconn));
2704 	switch (PQtransactionStatus(self->pqconn))
2705 	{
2706 		case PQTRANS_IDLE:	// correspond to 'I' in ReadyForQuery message
2707 			if (CC_is_in_trans(self))
2708 			{
2709 				if (CC_is_in_error_trans(self))
2710 					CC_on_abort(self, NO_TRANS);
2711 				else
2712 					CC_on_commit(self);
2713 			}
2714 			break;
2715 
2716 		case PQTRANS_INTRANS:	// correspond to 'T' in ReadyForQuery message
2717 			CC_set_in_trans(self);
2718 			if (CC_is_in_error_trans(self))
2719 			{
2720 				CC_set_no_error_trans(self);
2721 				CC_on_abort_partial(self);
2722 			}
2723 			break;
2724 
2725 		case PQTRANS_INERROR:	// correspond to 'E' in ReadyForQuery message
2726 			CC_set_in_trans(self);
2727 			CC_set_in_error_trans(self);
2728 			break;
2729 
2730 		case PQTRANS_ACTIVE:	// no correspondence in ReadyForQuery message
2731 			/*
2732 			 * A query is still executing. It's not necessary to consider this status.
2733 			 */
2734 			// CC_set_in_trans(self);
2735 			break;
2736 
2737 		default: 			/* unknown status */
2738 			break;
2739 	}
2740 }
2741 
2742 #define        PROTOCOL3_OPTS_MAX      30
2743 
2744 static int
LIBPQ_connect(ConnectionClass * self)2745 LIBPQ_connect(ConnectionClass *self)
2746 {
2747 	CSTR		func = "LIBPQ_connect";
2748 	ConnInfo	*ci = &(self->connInfo);
2749 	char		ret = 0;
2750 	void	   *pqconn = NULL;
2751 	int			pqret;
2752 	int			pversion;
2753 	const	char	*opts[PROTOCOL3_OPTS_MAX], *vals[PROTOCOL3_OPTS_MAX];
2754 	PQconninfoOption	*conninfoOption = NULL, *pqopt;
2755 	int			i, cnt;
2756 	char		login_timeout_str[20];
2757 	char		keepalive_idle_str[20];
2758 	char		keepalive_interval_str[20];
2759 	char		*errmsg = NULL;
2760 
2761 	MYLOG(0, "connecting to the database using %s as the server and pqopt={%s}\n", self->connInfo.server, SAFE_NAME(ci->pqopt));
2762 
2763 	if (NULL == (conninfoOption = PQconninfoParse(SAFE_NAME(ci->pqopt), &errmsg)))
2764 	{
2765 		char emsg[200];
2766 
2767 		if (errmsg != NULL)
2768 			SPRINTF_FIXED(emsg, "libpq connection parameter error:%s", errmsg);
2769 		else
2770 			STRCPY_FIXED(emsg, "memory error? in PQconninfoParse");
2771 		CC_set_error(self, CONN_OPENDB_ERROR, emsg, func);
2772 		goto cleanup;
2773 	}
2774 	/* Build arrays of keywords & values, for PQconnectDBParams */
2775 	cnt = 0;
2776 	if (ci->server[0])
2777 	{
2778 		opts[cnt] = "host";		vals[cnt++] = ci->server;
2779 	}
2780 	if (ci->port[0])
2781 	{
2782 		opts[cnt] = "port";		vals[cnt++] = ci->port;
2783 	}
2784 	if (ci->database[0])
2785 	{
2786 		opts[cnt] = "dbname";	vals[cnt++] = ci->database;
2787 	}
2788 	if (ci->username[0])
2789 	{
2790 		opts[cnt] = "user";		vals[cnt++] = ci->username;
2791 	}
2792 	switch (ci->sslmode[0])
2793 	{
2794 		case '\0':
2795 			break;
2796 		case SSLLBYTE_VERIFY:
2797 			opts[cnt] = "sslmode";
2798 			switch (ci->sslmode[1])
2799 			{
2800 				case 'f':
2801 					vals[cnt++] = SSLMODE_VERIFY_FULL;
2802 					break;
2803 				case 'c':
2804 					vals[cnt++] = SSLMODE_VERIFY_CA;
2805 					break;
2806 				default:
2807 					vals[cnt++] = ci->sslmode;
2808 			}
2809 			break;
2810 		default:
2811 			opts[cnt] = "sslmode";
2812 			vals[cnt++] = ci->sslmode;
2813 	}
2814 	if (NAME_IS_VALID(ci->password))
2815 	{
2816 		opts[cnt] = "password";	vals[cnt++] = SAFE_NAME(ci->password);
2817 	}
2818 	if (ci->disable_keepalive)
2819 	{
2820 		opts[cnt] = "keepalives";	vals[cnt++] = "0";
2821 	}
2822 	if (self->login_timeout > 0)
2823 	{
2824 		SPRINTF_FIXED(login_timeout_str, "%u", (unsigned int) self->login_timeout);
2825 		opts[cnt] = "connect_timeout";	vals[cnt++] = login_timeout_str;
2826 	}
2827 	if (self->connInfo.keepalive_idle > 0)
2828 	{
2829 		ITOA_FIXED(keepalive_idle_str, self->connInfo.keepalive_idle);
2830 		opts[cnt] = "keepalives_idle";	vals[cnt++] = keepalive_idle_str;
2831 	}
2832 	if (self->connInfo.keepalive_interval > 0)
2833 	{
2834 		ITOA_FIXED(keepalive_interval_str, self->connInfo.keepalive_interval);
2835 		opts[cnt] = "keepalives_interval";	vals[cnt++] = keepalive_interval_str;
2836 	}
2837 	if (conninfoOption != NULL)
2838 	{
2839 		const char *keyword, *val;
2840 		int j;
2841 
2842 		for (i = 0, pqopt = conninfoOption; (keyword = pqopt->keyword) != NULL; i++, pqopt++)
2843 		{
2844 			if ((val = pqopt->val) != NULL)
2845 			{
2846 				for (j = 0; j < cnt; j++)
2847 				{
2848 					if (stricmp(opts[j], keyword) == 0)
2849 					{
2850 						char emsg[100];
2851 
2852 						if (vals[j] != NULL && strcmp(vals[j], val) == 0)
2853 							continue;
2854 						SPRINTF_FIXED(emsg, "%s parameter in pqopt option conflicts with other ordinary option", keyword);
2855 						CC_set_error(self, CONN_OPENDB_ERROR, emsg, func);
2856 						goto cleanup;
2857 					}
2858 				}
2859 				if (j >= cnt && cnt < PROTOCOL3_OPTS_MAX - 1)
2860 				{
2861 					opts[cnt] = keyword; vals[cnt++] = val;
2862 				}
2863 			}
2864 		}
2865 	}
2866 	opts[cnt] = vals[cnt] = NULL;
2867 	/* Ok, we're all set to connect */
2868 
2869 	if (get_qlog() > 0 || get_mylog() > 0)
2870 	{
2871 		const char **popt, **pval;
2872 
2873 		QLOG(0, "PQconnectdbParams:");
2874 		for (popt = opts, pval = vals; *popt; popt++, pval++)
2875 			QPRINTF(0, " %s='%s'", *popt, *pval);
2876 		QPRINTF(0, "\n");
2877 	}
2878 	pqconn = PQconnectdbParams(opts, vals, FALSE);
2879 	if (!pqconn)
2880 	{
2881 		CC_set_error(self, CONN_OPENDB_ERROR, "PQconnectdb error", func);
2882 		goto cleanup;
2883 	}
2884 	self->pqconn = pqconn;
2885 
2886 	pqret = PQstatus(pqconn);
2887 	if (pqret == CONNECTION_BAD && PQconnectionNeedsPassword(pqconn))
2888 	{
2889 		const char	*errmsg;
2890 
2891 		MYLOG(0, "password retry\n");
2892 		errmsg = PQerrorMessage(pqconn);
2893 		CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, errmsg, func);
2894 		QLOG(0, "PQfinish: %p\n", pqconn);
2895 		PQfinish(pqconn);
2896 		self->pqconn = NULL;
2897 		self->connInfo.password_required = TRUE;
2898 		ret = -1;
2899 		goto cleanup;
2900 	}
2901 
2902 	if (CONNECTION_OK != pqret)
2903 	{
2904 		const char	*errmsg;
2905 MYLOG(DETAIL_LOG_LEVEL, "status=%d\n", pqret);
2906 		errmsg = PQerrorMessage(pqconn);
2907 		CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, errmsg, func);
2908 		MYLOG(0, "Could not establish connection to the database; LIBPQ returned -> %s\n", errmsg);
2909 		goto cleanup;
2910 	}
2911 
2912 	MYLOG(0, "libpq connection to the database established.\n");
2913 	pversion = PQprotocolVersion(pqconn);
2914 	if (pversion < 3)
2915 	{
2916 		MYLOG(0, "Protocol version %d is not supported\n", pversion);
2917 		goto cleanup;
2918 	}
2919 	MYLOG(0, "protocol=%d\n", pversion);
2920 
2921 	pversion = PQserverVersion(pqconn);
2922 	self->pg_version_major = pversion / 10000;
2923 	self->pg_version_minor = (pversion % 10000) / 100;
2924 	SPRINTF_FIXED(self->pg_version, "%d.%d.%d",  self->pg_version_major, self->pg_version_minor, pversion % 100);
2925 
2926 	MYLOG(0, "Server version=%s\n", self->pg_version);
2927 
2928 	if (!CC_get_username(self)[0])
2929 	{
2930 		MYLOG(0, "PQuser=%s\n", PQuser(pqconn));
2931 		STRCPY_FIXED(self->connInfo.username, PQuser(pqconn));
2932 	}
2933 
2934 	ret = 1;
2935 
2936 cleanup:
2937 	if (errmsg != NULL)
2938 		free(errmsg);
2939 	PQconninfoFree(conninfoOption);
2940 	if (ret != 1)
2941 	{
2942 		if (self->pqconn)
2943 		{
2944 			QLOG(0, "PQfinish: %p\n", self->pqconn);
2945 			PQfinish(self->pqconn);
2946 		}
2947 		self->pqconn = NULL;
2948 	}
2949 
2950 	MYLOG(0, "leaving %d\n", ret);
2951 	return ret;
2952 }
2953 
2954 int
CC_send_cancel_request(const ConnectionClass * conn)2955 CC_send_cancel_request(const ConnectionClass *conn)
2956 {
2957 	int	ret = 0;
2958 	char	errbuf[256];
2959 	void	*cancel;
2960 
2961 	/* Check we have an open connection */
2962 	if (!conn || !conn->pqconn)
2963 		return FALSE;
2964 
2965 	cancel = PQgetCancel(conn->pqconn);
2966 	if (!cancel)
2967 		return FALSE;
2968 	ret = PQcancel(cancel, errbuf, sizeof(errbuf));
2969 	PQfreeCancel(cancel);
2970 	if (1 == ret)
2971 		return TRUE;
2972 	else
2973 		return FALSE;
2974 }
2975 
CurrCat(const ConnectionClass * conn)2976 const char *CurrCat(const ConnectionClass *conn)
2977 {
2978 	/*
2979 	 * Returning the database name causes problems in MS Query. It
2980 	 * generates query like: "SELECT DISTINCT a FROM byronnbad3
2981 	 * bad3"
2982 	 */
2983 	if (isMsQuery())	/* MS Query */
2984 		return NULL;
2985 	return conn->connInfo.database;
2986 }
2987 
CurrCatString(const ConnectionClass * conn)2988 const char *CurrCatString(const ConnectionClass *conn)
2989 {
2990 	const char *cat = CurrCat(conn);
2991 
2992 	if (!cat)
2993 		cat = NULL_STRING;
2994 	return cat;
2995 }
2996 
2997 /*------
2998  *	Create a null terminated lower-case string if the
2999  *	original string contains upper-case characters.
3000  *	The SQL_NTS length is considered.
3001  *------
3002  */
3003 SQLCHAR *
make_lstring_ifneeded(ConnectionClass * conn,const SQLCHAR * s,ssize_t len,BOOL ifallupper)3004 make_lstring_ifneeded(ConnectionClass *conn, const SQLCHAR *s, ssize_t len, BOOL ifallupper)
3005 {
3006 	ssize_t	length = len;
3007 	char	   *str = NULL;
3008 	const char *ccs = (const char *) s;
3009 
3010 	if (s && (len > 0 || (len == SQL_NTS && (length = strlen(ccs)) > 0)))
3011 	{
3012 		int	i;
3013 		UCHAR tchar;
3014 		encoded_str encstr;
3015 
3016 		make_encoded_str(&encstr, conn, ccs);
3017 		for (i = 0; i < length; i++)
3018 		{
3019 			tchar = encoded_nextchar(&encstr);
3020 			if (MBCS_NON_ASCII(encstr))
3021 				continue;
3022 			if (ifallupper && islower(tchar))
3023 			{
3024 				if (str)
3025 				{
3026 					free(str);
3027 					str = NULL;
3028 				}
3029 				break;
3030 			}
3031 			if (tolower(tchar) != tchar)
3032 			{
3033 				if (!str)
3034 				{
3035 					str = malloc(length + 1);
3036 					if (!str) return NULL;
3037 					memcpy(str, s, length);
3038 					str[length] = '\0';
3039 				}
3040 				str[i] = tolower(tchar);
3041 			}
3042 		}
3043 	}
3044 
3045 	return (SQLCHAR *) str;
3046 }
3047 
3048 /*
3049  *	Concatenate a single formatted argument to a given buffer handling the SQL_NTS thing.
3050  *	"fmt" must contain somewhere in it the single form '%.*s'.
3051  *	This is heavily used in creating queries for info routines (SQLTables, SQLColumns).
3052  *	This routine could be modified to use vsprintf() to handle multiple arguments.
3053  */
3054 static int
my_str(char * buf,int buflen,const char * fmt,const char * s,ssize_t len)3055 my_str(char *buf, int buflen, const char *fmt, const char *s, ssize_t len)
3056 {
3057 	if (s && (len > 0 || (len == SQL_NTS && *s != 0)))
3058 	{
3059 		size_t	length = (len > 0) ? len : strlen(s);
3060 
3061 		return snprintf(buf, buflen, fmt, length, s);
3062 	}
3063 	buf[0] = '\0';
3064 	return 0;
3065 }
3066 
3067 int
schema_str(char * buf,int buflen,const SQLCHAR * s,SQLLEN len,BOOL table_is_valid,ConnectionClass * conn)3068 schema_str(char *buf, int buflen, const SQLCHAR *s, SQLLEN len, BOOL table_is_valid, ConnectionClass *conn)
3069 {
3070 	CSTR	fmt = "%.*s";
3071 
3072 	buf[0] = '\0';
3073 	if (!s || 0 == len)
3074 	{
3075 		/*
3076 		 * Note that this driver assumes the implicit schema is
3077 		 * the CURRENT_SCHEMA() though it doesn't worth the
3078 		 * naming.
3079 		 */
3080 		if (table_is_valid)
3081 			return my_str(buf, buflen, fmt, CC_get_current_schema(conn), SQL_NTS);
3082 		return 0;
3083 	}
3084 	return my_str(buf, buflen, fmt, (char *) s, len);
3085 }
3086 
3087 static void
my_appendPQExpBuffer(PQExpBufferData * buf,const char * fmt,const char * s,ssize_t len)3088 my_appendPQExpBuffer(PQExpBufferData *buf, const char *fmt, const char *s, ssize_t len)
3089 {
3090 	if (s && (len > 0 || (len == SQL_NTS && *s != 0)))
3091 	{
3092 		size_t	length = (len > 0) ? len : strlen(s);
3093 
3094 		appendPQExpBuffer(buf, fmt, length, s);
3095 	}
3096 }
3097 
3098 /*
3099  *	my_appendPQExpBuffer1 is a extension of my_appendPQExpBuffer.
3100  *	It can have 1 more parameter than my_appendPQExpBuffer.
3101  */
3102 static void
my_appendPQExpBuffer1(PQExpBufferData * buf,const char * fmt,const char * s1,const char * s)3103 my_appendPQExpBuffer1(PQExpBufferData *buf, const char *fmt, const char *s1, const char *s)
3104 {
3105 	if (s && s[0] != '\0')
3106 	{
3107 		ssize_t	length = strlen(s);
3108 
3109 		if (s1)
3110 			appendPQExpBuffer(buf, fmt, s1, length, s);
3111 		else
3112 			appendPQExpBuffer(buf, fmt, length, s);
3113 	}
3114 }
3115 
3116 void
schema_appendPQExpBuffer(PQExpBufferData * buf,const char * fmt,const SQLCHAR * s,SQLLEN len,BOOL table_is_valid,ConnectionClass * conn)3117 schema_appendPQExpBuffer(PQExpBufferData *buf, const char *fmt, const SQLCHAR *s, SQLLEN len, BOOL table_is_valid, ConnectionClass *conn)
3118 {
3119 	if (!s || 0 == len)
3120 	{
3121 		/*
3122 		 * Note that this driver assumes the implicit schema is
3123 		 * the CURRENT_SCHEMA() though it doesn't worth the
3124 		 * naming.
3125 		 */
3126 		if (table_is_valid)
3127 			my_appendPQExpBuffer(buf, fmt, CC_get_current_schema(conn), SQL_NTS);
3128 		return;
3129 	}
3130 	my_appendPQExpBuffer(buf, fmt, (char *) s, len);
3131 }
3132 
3133 void
schema_appendPQExpBuffer1(PQExpBufferData * buf,const char * fmt,const char * s1,const char * s,BOOL table_is_valid,ConnectionClass * conn)3134 schema_appendPQExpBuffer1(PQExpBufferData *buf, const char *fmt, const char *s1, const char *s, BOOL table_is_valid, ConnectionClass *conn)
3135 {
3136 	if (!s || s[0] == '\0')
3137 	{
3138 		if (table_is_valid)
3139 			my_appendPQExpBuffer1(buf, fmt, s1, CC_get_current_schema(conn));
3140 		return;
3141 	}
3142 	my_appendPQExpBuffer1(buf, fmt, s1, s);
3143 }
3144 
3145 #ifdef	_HANDLE_ENLIST_IN_DTC_
3146 	/*
3147 	 *	Export the following functions so that the pgenlist dll
3148 	 *	can handle ConnectionClass objects as opaque ones.
3149 	 */
3150 
3151 #define	_PGDTC_FUNCS_IMPLEMENT_
3152 #include "connexp.h"
3153 
3154 #define	SYNC_AUTOCOMMIT(conn)								\
3155 	(SQL_AUTOCOMMIT_OFF != conn->autocommit_public ?		\
3156 	 (conn->transact_status |= CONN_IN_AUTOCOMMIT) :		\
3157 	 (conn->transact_status &= ~CONN_IN_AUTOCOMMIT))
3158 
PgDtc_create_connect_string(void * self,char * connstr,int strsize)3159 DLL_DECLARE void PgDtc_create_connect_string(void *self, char *connstr, int strsize)
3160 {
3161 	ConnectionClass	*conn = (ConnectionClass *) self;
3162 	ConnInfo *ci = &(conn->connInfo);
3163 	const char *drivername = ci->drivername;
3164 	char	xaOptStr[32];
3165 
3166 #if defined(_WIN32) && !defined(_WIN64)
3167 	/*
3168 	 * If this is an x86 driver running on an x64 host then the driver name
3169 	 * passed to MSDTC must be the (x64) driver but the client app will be
3170 	 * using the 32-bit driver name. So MSDTC.exe will fail to find the driver
3171 	 * and we'll fail to recover XA transactions.
3172 	 *
3173 	 * IsWow64Process(...) would be the ideal function for this, but is only
3174 	 * available on Windows 6+ (Vista/2k8). We'd use GetNativeSystemInfo, which
3175 	 * is supported on XP and 2k3, instead, but that won't link with older
3176 	 * SDKs.
3177 	 *
3178 	 * It's impler to just test the PROCESSOR_ARCHITEW6432 environment
3179 	 * variable.
3180 	 *
3181 	 * See http://www.postgresql.org/message-id/53A45B59.70303@2ndquadrant.com
3182 	 * for details on this issue.
3183 	 */
3184 	const char * const procenv = getenv("PROCESSOR_ARCHITEW6432");
3185 	if (procenv != NULL && strcmp(procenv, "AMD64") == 0)
3186 	{
3187 		/*
3188 		 * We're a 32-bit binary running under SysWow64 on a 64-bit host and need
3189 		 * to pass a different driver name.
3190 		 *
3191 		 * To avoid playing memory management games, just return a different
3192 		 * string constant depending on the unicode-ness of the driver.
3193 		 *
3194 		 * It probably doesn't matter whether we use the Unicode or ANSI driver
3195 		 * for the XA transaction manager, but pick the same as the client driver
3196 		 * to keep things as similar as possible.
3197 		 */
3198 		if (strcmp(drivername, DBMS_NAME) == 0)
3199 #ifdef UNICODE_SUPPORT
3200 		drivername = DBMS_NAME_UNICODE"(x64)";
3201 #else
3202 		drivername = DBMS_NAME_ANSI"(x64)";
3203 #endif
3204 	}
3205 #endif // _WIN32 &&  !_WIN64
3206 
3207 	if (0 >= ci->xa_opt)	return;
3208 	switch (ci->xa_opt)
3209 	{
3210 		case DTC_CHECK_LINK_ONLY:
3211 		case DTC_CHECK_BEFORE_LINK:
3212 			SPRINTF_FIXED(xaOptStr, KEYWORD_DTC_CHECK "=0;");
3213 			break;
3214 		case DTC_CHECK_RM_CONNECTION:
3215 			SPRINTF_FIXED(xaOptStr, KEYWORD_DTC_CHECK "=1;");
3216 			break;
3217 		default:
3218 			*xaOptStr = '\0';
3219 			break;
3220 	}
3221 	snprintf(connstr, strsize,
3222 			 "DRIVER={%s};%s"
3223 			 "SERVER=%s;PORT=%s;DATABASE=%s;"
3224 			 "UID=%s;PWD=%s;" ABBR_SSLMODE "=%s",
3225 			 drivername, xaOptStr,
3226 			 ci->server, ci->port, ci->database, ci->username,
3227 			 SAFE_NAME(ci->password), ci->sslmode
3228 		);
3229 	return;
3230 }
3231 
3232 #define SECURITY_WIN32
3233 #include <security.h>
PgDtc_is_recovery_available(void * self,char * reason,int rsize)3234 DLL_DECLARE int PgDtc_is_recovery_available(void *self, char *reason, int rsize)
3235 {
3236 	ConnectionClass	*conn = (ConnectionClass *) self;
3237 	ConnInfo *ci = &(conn->connInfo);
3238 	int	ret = -1;	// inknown
3239 	LONG	nameSize;
3240 	char	loginUser[256];
3241 	BOOL	outReason = FALSE;
3242 	BOOL	doubtRootCert = TRUE, doubtCert = TRUE;
3243 	const char *delim;
3244 
3245 	/*
3246 	 *	Root certificate is used?
3247 	 */
3248 	if (NULL != reason &&
3249 	    rsize > 0)
3250 		outReason = TRUE;
3251 	/*
3252 	 *	Root certificate is used?
3253 	 */
3254 	doubtRootCert = FALSE;
3255 	if (0 == stricmp(ci->sslmode, SSLMODE_VERIFY_CA) ||
3256 	    0 == stricmp(ci->sslmode, SSLMODE_VERIFY_FULL))
3257 	{
3258 		if (outReason)
3259 			strncpy_null(reason, "sslmode verify-[ca|full]", rsize);
3260 		return 0;
3261 	}
3262 
3263 	/*
3264 	 * Did we use SSL client certificate, SSPI, Kerberos or similar
3265 	 * authentication methods?
3266 	 */
3267 	doubtCert = FALSE;
3268 #ifdef HAVE_PQSSLINUSE
3269 	if (PQsslInUse(conn->pqconn))
3270 #else
3271 	if (PQgetssl(conn->pqconn) != NULL)
3272 #endif
3273 		doubtCert = TRUE;
3274 
3275 	nameSize = sizeof(loginUser);
3276 	if (GetUserNameEx(NameUserPrincipal, loginUser, &nameSize))
3277 	{
3278 		MYLOG(0, "loginUser=%s\n", loginUser);
3279 	}
3280 	else
3281 	{
3282 		int err = GetLastError();
3283 		switch (err)
3284 		{
3285 			case ERROR_NONE_MAPPED:
3286 				MYLOG(0, "The user name is unavailable in the specified format\n");
3287 				break;
3288 			case ERROR_NO_SUCH_DOMAIN:
3289 				MYLOG(0, "The domain controller is unavailable to perform the lookup\n");
3290 				break;
3291 			case ERROR_MORE_DATA:
3292 				MYLOG(0, "The buffer is too small\n");
3293 				break;
3294 			default:
3295 				MYLOG(0, "GetUserNameEx error=%d\n", err);
3296 				break;
3297 		}
3298 	}
3299 
3300 	ret = 1;
3301 	if (outReason)
3302 		*reason = '\0';
3303 	delim = "";
3304 	if (doubtRootCert)
3305 	{
3306 		if (outReason)
3307 			snprintf(reason, rsize, "%s%ssslmode verify-[ca|full]", reason, delim);
3308 		delim = ", ";
3309 		ret = -1;
3310 	}
3311 	if (doubtCert)
3312 	{
3313 		if (outReason)
3314 			snprintf(reason, rsize, "%s%scertificate", reason, delim);
3315 		delim = ", ";
3316 		ret = -1;
3317 	}
3318 	return ret;
3319 }
3320 
PgDtc_set_async(void * self,void * async)3321 DLL_DECLARE void PgDtc_set_async(void *self, void *async)
3322 {
3323 	ConnectionClass	*conn = (ConnectionClass *) self;
3324 
3325 	if (!conn)	return;
3326 	CONNLOCK_ACQUIRE(conn);
3327 	if (NULL != async)
3328 		CC_set_autocommit(conn, FALSE);
3329 	else
3330 		SYNC_AUTOCOMMIT(conn);
3331 	conn->asdum = async;
3332 	CONNLOCK_RELEASE(conn);
3333 }
3334 
PgDtc_get_async(void * self)3335 DLL_DECLARE void	*PgDtc_get_async(void *self)
3336 {
3337 	ConnectionClass *conn = (ConnectionClass *) self;
3338 
3339 	return conn->asdum;
3340 }
3341 
PgDtc_set_property(void * self,int property,void * value)3342 DLL_DECLARE void PgDtc_set_property(void *self, int property, void *value)
3343 {
3344 	ConnectionClass *conn = (ConnectionClass *) self;
3345 
3346 	CONNLOCK_ACQUIRE(conn);
3347 	switch (property)
3348 	{
3349 		case inprogress:
3350 			if (NULL != value)
3351 				CC_set_dtc_executing(conn);
3352 			else
3353 				CC_no_dtc_executing(conn);
3354 			break;
3355 		case enlisted:
3356 			if (NULL != value)
3357 				CC_set_dtc_enlisted(conn);
3358 			else
3359 				CC_no_dtc_enlisted(conn);
3360 			break;
3361 		case prepareRequested:
3362 			if (NULL != value)
3363 				CC_set_dtc_prepareRequested(conn);
3364 			else
3365 				CC_no_dtc_prepareRequested(conn);
3366 			break;
3367 	}
3368 	CONNLOCK_RELEASE(conn);
3369 }
3370 
PgDtc_set_error(void * self,const char * message,const char * func)3371 DLL_DECLARE void PgDtc_set_error(void *self, const char *message, const char *func)
3372 {
3373 	ConnectionClass *conn = (ConnectionClass *) self;
3374 
3375 	CC_set_error(conn, CONN_UNSUPPORTED_OPTION, message, func);
3376 }
3377 
PgDtc_get_property(void * self,int property)3378 DLL_DECLARE int PgDtc_get_property(void *self, int property)
3379 {
3380 	ConnectionClass *conn = (ConnectionClass *) self;
3381 	int	ret;
3382 
3383 	CONNLOCK_ACQUIRE(conn);
3384 	switch (property)
3385 	{
3386 		case inprogress:
3387 			ret = CC_is_dtc_executing(conn);
3388 			break;
3389 		case enlisted:
3390 			ret = CC_is_dtc_enlisted(conn);
3391 			break;
3392 		case inTrans:
3393 			ret = CC_is_in_trans(conn);
3394 			break;
3395 		case errorNumber:
3396 			ret = CC_get_errornumber(conn);
3397 			break;
3398 		case idleInGlobalTransaction:
3399 			ret = CC_is_idle_in_global_transaction(conn);
3400 			break;
3401 		case connected:
3402 			ret = (CONN_CONNECTED == conn->status);
3403 			break;
3404 		case prepareRequested:
3405 			ret = CC_is_dtc_prepareRequested(conn);
3406 			break;
3407 	}
3408 	CONNLOCK_RELEASE(conn);
3409 	return ret;
3410 }
3411 
PgDtc_connect(void * self)3412 DLL_DECLARE BOOL PgDtc_connect(void *self)
3413 {
3414 	CSTR	func = "PgDtc_connect";
3415 	ConnectionClass *conn = (ConnectionClass *) self;
3416 
3417 	if (CONN_CONNECTED == conn->status)
3418 		return TRUE;
3419 	if (CC_connect(conn, NULL) <= 0)
3420 	{
3421 		/* Error messages are filled in */
3422 		CC_log_error(func, "Error on CC_connect", conn);
3423 		return FALSE;
3424 	}
3425 	return TRUE;
3426 }
3427 
PgDtc_free_connect(void * self)3428 DLL_DECLARE void PgDtc_free_connect(void *self)
3429 {
3430 	ConnectionClass *conn = (ConnectionClass *) self;
3431 
3432 	PGAPI_FreeConnect(conn);
3433 }
3434 
PgDtc_one_phase_operation(void * self,int operation)3435 DLL_DECLARE BOOL PgDtc_one_phase_operation(void *self, int operation)
3436 {
3437 	ConnectionClass *conn = (ConnectionClass *) self;
3438 	BOOL	ret, is_in_progress = CC_is_dtc_executing(conn);
3439 
3440 	if (!is_in_progress)
3441 		CC_set_dtc_executing(conn);
3442 	switch (operation)
3443 	{
3444 		case ONE_PHASE_COMMIT:
3445 			ret = CC_commit(conn);
3446 			break;
3447 		default:
3448 			ret = CC_abort(conn);
3449 			break;
3450 	}
3451 
3452 	if (!is_in_progress)
3453 		CC_no_dtc_executing(conn);
3454 
3455 	return ret;
3456 }
3457 
3458 DLL_DECLARE BOOL
PgDtc_two_phase_operation(void * self,int operation,const char * gxid)3459 PgDtc_two_phase_operation(void *self, int operation, const char *gxid)
3460 {
3461 	ConnectionClass *conn = (ConnectionClass *) self;
3462 	QResultClass	*qres;
3463 	BOOL	ret = TRUE;
3464 	char		cmd[512];
3465 
3466 	switch (operation)
3467 	{
3468 		case PREPARE_TRANSACTION:
3469 			SPRINTF_FIXED(cmd, "PREPARE TRANSACTION '%s'", gxid);
3470 			break;
3471 		case COMMIT_PREPARED:
3472 			SPRINTF_FIXED(cmd, "COMMIT PREPARED '%s'", gxid);
3473 			break;
3474 		case ROLLBACK_PREPARED:
3475 			SPRINTF_FIXED(cmd, "ROLLBACK PREPARED '%s'", gxid);
3476 			break;
3477 	}
3478 
3479 	qres = CC_send_query(conn, cmd, NULL, 0, NULL);
3480 	if (!QR_command_maybe_successful(qres))
3481 		ret = FALSE;
3482 	QR_Destructor(qres);
3483 	return ret;
3484 }
3485 
3486 DLL_DECLARE BOOL
PgDtc_lock_cntrl(void * self,BOOL acquire,BOOL bTrial)3487 PgDtc_lock_cntrl(void *self, BOOL acquire, BOOL bTrial)
3488 {
3489 	ConnectionClass *conn = (ConnectionClass *) self;
3490 	BOOL	ret = TRUE;
3491 
3492 	if (acquire)
3493 		if (bTrial)
3494 			ret = TRY_ENTER_CONN_CS(conn);
3495 		else
3496 			ENTER_CONN_CS(conn);
3497 	else
3498 		LEAVE_CONN_CS(conn);
3499 
3500 	return ret;
3501 }
3502 
3503 static ConnectionClass *
CC_Copy(const ConnectionClass * conn)3504 CC_Copy(const ConnectionClass *conn)
3505 {
3506 	ConnectionClass	*newconn = CC_alloc();
3507 
3508 	if (newconn)
3509 	{
3510 		memcpy(newconn, conn, sizeof(ConnectionClass));
3511 		CC_lockinit(newconn);
3512 	}
3513 	return newconn;
3514 }
3515 
3516 DLL_DECLARE void *
PgDtc_isolate(void * self,DWORD option)3517 PgDtc_isolate(void *self, DWORD option)
3518 {
3519 	BOOL	disposingConn = (0 != (disposingConnection & option));
3520 	ConnectionClass *sconn = (ConnectionClass *) self, *newconn = NULL;
3521 
3522 	if (0 == (useAnotherRoom & option))
3523 	{
3524 		HENV	henv = sconn->henv;
3525 
3526 		CC_cleanup(sconn, TRUE);
3527 		if (newconn = CC_Copy(sconn), NULL == newconn)
3528 			return newconn;
3529 		MYLOG(0, "newconn=%p from %p\n", newconn, sconn);
3530 		CC_initialize(sconn, FALSE);
3531 		if (!disposingConn)
3532 			CC_copy_conninfo(&sconn->connInfo, &newconn->connInfo);
3533 		CC_initialize_pg_version(sconn);
3534 		sconn->henv = henv;
3535 		newconn->henv = NULL;
3536 		SYNC_AUTOCOMMIT(sconn);
3537 		return newconn;
3538 	}
3539 	newconn = CC_Constructor();
3540 	if (!newconn) return NULL;
3541 	CC_copy_conninfo(&newconn->connInfo, &sconn->connInfo);
3542 	CC_initialize_pg_version(newconn);
3543 	newconn->asdum = sconn->asdum;
3544 	newconn->gTranInfo = sconn->gTranInfo;
3545 	CC_set_dtc_isolated(newconn);
3546 	sconn->asdum = NULL;
3547 	SYNC_AUTOCOMMIT(sconn);
3548 	CC_set_dtc_clear(sconn);
3549 	MYLOG(0, "generated connection=%p with %p\n", newconn, newconn->asdum);
3550 
3551 	return newconn;
3552 }
3553 
3554 #endif /* _HANDLE_ENLIST_IN_DTC_ */
3555 
3556 BOOL
CC_set_transact(ConnectionClass * self,UInt4 isolation)3557 CC_set_transact(ConnectionClass *self, UInt4 isolation)
3558 {
3559 	char *query;
3560 	QResultClass *res;
3561 	BOOL	bShow = FALSE;
3562 
3563 	if (PG_VERSION_LT(self, 8.0) &&
3564 		(isolation == SQL_TXN_READ_UNCOMMITTED ||
3565 		 isolation == SQL_TXN_REPEATABLE_READ))
3566 	{
3567 		CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "READ_UNCOMMITTED or REPEATABLE_READ is not supported by the server", __FUNCTION__);
3568 		return FALSE;
3569 	}
3570 
3571 	switch (isolation)
3572 	{
3573 		case SQL_TXN_SERIALIZABLE:
3574 			query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE";
3575 						break;
3576 		case SQL_TXN_REPEATABLE_READ:
3577 			query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ";
3578 			break;
3579 		case SQL_TXN_READ_UNCOMMITTED:
3580 			query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
3581 			break;
3582 		default:
3583 			query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
3584 			break;
3585 	}
3586 	if (self->default_isolation == 0)
3587 		bShow = TRUE;
3588 	if (bShow)
3589 		res = CC_send_query_append(self, ISOLATION_SHOW_QUERY, NULL, READ_ONLY_QUERY, NULL, query).first;
3590 	else
3591 		res = CC_send_query(self, query, NULL, READ_ONLY_QUERY, NULL);
3592 	if (!QR_command_maybe_successful(res))
3593 	{
3594 		CC_set_error(self, CONN_EXEC_ERROR, "ISOLATION change request to the server error", __FUNCTION__);
3595 		QR_Destructor(res);
3596 		return FALSE;
3597 	}
3598 	if (bShow)
3599 		handle_show_results(res);
3600 	QR_Destructor(res);
3601 	self->server_isolation = isolation;
3602 
3603 	return TRUE;
3604 }
3605 
3606