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