Merge commit 'origin/master'
[versaplex.git] / vxodbc / connection.cc
blob447330f475dcd2a077ca3baaabdfe1a791fb3b1f
1 /*
2 * Description: This module contains routines related to
3 * connecting to and disconnecting from the Postgres DBMS.
4 */
5 /* Multibyte support Eiji Tokuya 2001-03-15 */
7 #include "connection.h"
9 #include <stdio.h>
10 #include <string.h>
11 #include <ctype.h>
12 #ifndef WIN32
13 #include <errno.h>
14 #endif /* WIN32 */
16 #include "environ.h"
17 #include "statement.h"
18 #include "qresult.h"
19 #include "dlg_specific.h"
21 #include "multibyte.h"
23 #include "pgapifunc.h"
25 #include <wvdbusconn.h>
26 #include <wvistreamlist.h>
27 #include "wvssl_necessities.h"
29 #define STMT_INCREMENT 16 /* how many statement holders to allocate
30 * at a time */
32 #define PRN_NULLCHECK
34 extern GLOBAL_VALUES globals;
37 RETCODE SQL_API PGAPI_AllocConnect(HENV henv, HDBC FAR * phdbc)
39 EnvironmentClass *env = (EnvironmentClass *) henv;
40 ConnectionClass *conn;
41 CSTR func = "PGAPI_AllocConnect";
43 mylog("%s: entering...\n", func);
45 conn = CC_Constructor();
46 mylog("**** %s: henv = %p, conn = %p\n", func, henv, conn);
48 if (!conn)
50 env->errormsg =
51 "Couldn't allocate memory for Connection object.";
52 env->errornumber = ENV_ALLOC_ERROR;
53 *phdbc = SQL_NULL_HDBC;
54 EN_log_error(func, "", env);
55 return SQL_ERROR;
58 if (!EN_add_connection(env, conn))
60 env->errormsg = "Maximum number of connections exceeded.";
61 env->errornumber = ENV_ALLOC_ERROR;
62 CC_Destructor(conn);
63 *phdbc = SQL_NULL_HDBC;
64 EN_log_error(func, "", env);
65 return SQL_ERROR;
68 if (phdbc)
69 *phdbc = (HDBC) conn;
71 return SQL_SUCCESS;
75 RETCODE SQL_API
76 PGAPI_Connect(HDBC hdbc,
77 const SQLCHAR FAR * szDSN,
78 SQLSMALLINT cbDSN,
79 const SQLCHAR FAR * szUID,
80 SQLSMALLINT cbUID,
81 const SQLCHAR FAR * szAuthStr, SQLSMALLINT cbAuthStr)
83 ConnectionClass *conn = (ConnectionClass *) hdbc;
84 ConnInfo *ci;
85 CSTR func = "PGAPI_Connect";
86 RETCODE ret = SQL_SUCCESS;
87 char fchar;
89 mylog("%s: entering..cbDSN=%hi.\n", func, cbDSN);
90 init_wvssl();
92 if (!conn)
94 CC_log_error(func, "", NULL);
95 return SQL_INVALID_HANDLE;
98 ci = &conn->connInfo;
100 make_string(szDSN, cbDSN, ci->dsn, sizeof(ci->dsn));
102 /* get the values for the DSN from the registry */
103 memcpy(&ci->drivers, &globals, sizeof(globals));
104 getDSNinfo(ci, CONN_OVERWRITE);
105 logs_on_off(1, true, true);
106 /* initialize pg_version from connInfo.protocol */
107 CC_initialize_pg_version(conn);
109 mylog("PGAPI_Connect making DBus connection to %s\n", ci->dbus_moniker);
110 conn->dbus = new WvDBusConn(ci->dbus_moniker);
113 * override values from DSN info with UID and authStr(pwd) This only
114 * occurs if the values are actually there.
116 // VX_CLEANUP: These may be unused.
117 fchar = ci->username[0]; /* save the first byte */
118 make_string(szUID, cbUID, ci->username, sizeof(ci->username));
119 if ('\0' == ci->username[0]) /* an empty string is specified */
120 ci->username[0] = fchar; /* restore the original username */
121 fchar = ci->password[0];
122 make_string(szAuthStr, cbAuthStr, ci->password,
123 sizeof(ci->password));
124 if ('\0' == ci->password[0]) /* an empty string is specified */
125 ci->password[0] = fchar; /* restore the original password */
127 /* fill in any defaults */
128 getDSNdefaults(ci);
130 qlog("conn = %p, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func,
131 ci->dsn, ci->username, ci->password ? "xxxxx" : "");
133 mylog("%s: returning..%d.\n", func, ret);
135 return ret;
139 RETCODE SQL_API
140 PGAPI_BrowseConnect(HDBC hdbc,
141 const SQLCHAR FAR * szConnStrIn,
142 SQLSMALLINT cbConnStrIn,
143 SQLCHAR FAR * szConnStrOut,
144 SQLSMALLINT cbConnStrOutMax,
145 SQLSMALLINT FAR * pcbConnStrOut)
147 CSTR func = "PGAPI_BrowseConnect";
148 ConnectionClass *conn = (ConnectionClass *) hdbc;
150 mylog("%s: entering...\n", func);
152 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR,
153 "Function not implemented", func);
154 return SQL_ERROR;
158 /* Drop any hstmts open on hdbc and disconnect from database */
159 RETCODE SQL_API PGAPI_Disconnect(HDBC hdbc)
161 ConnectionClass *conn = (ConnectionClass *) hdbc;
162 CSTR func = "PGAPI_Disconnect";
165 mylog("%s: entering...\n", func);
167 if (!conn)
169 CC_log_error(func, "", NULL);
170 return SQL_INVALID_HANDLE;
173 qlog("conn=%p, %s\n", conn, func);
175 if (conn->status == CONN_EXECUTING)
177 CC_set_error(conn, CONN_IN_USE,
178 "A transaction is currently being executed", func);
179 return SQL_ERROR;
182 logs_on_off(-1, true, true);
183 mylog("%s: about to CC_cleanup\n", func);
185 /* Close the connection and free statements */
186 CC_cleanup(conn);
188 mylog("%s: done CC_cleanup\n", func);
189 mylog("%s: returning...\n", func);
191 return SQL_SUCCESS;
195 RETCODE SQL_API PGAPI_FreeConnect(HDBC hdbc)
197 ConnectionClass *conn = (ConnectionClass *) hdbc;
198 CSTR func = "PGAPI_FreeConnect";
200 mylog("%s: entering...\n", func);
201 mylog("**** in %s: hdbc=%p\n", func, hdbc);
203 if (!conn)
205 CC_log_error(func, "", NULL);
206 return SQL_INVALID_HANDLE;
209 /* Remove the connection from the environment */
210 if (!EN_remove_connection(conn->henv, conn))
212 CC_set_error(conn, CONN_IN_USE,
213 "A transaction is currently being executed", func);
214 return SQL_ERROR;
217 CC_Destructor(conn);
219 mylog("%s: returning...\n", func);
221 return SQL_SUCCESS;
225 void CC_conninfo_init(ConnInfo * conninfo)
227 memset(conninfo, 0, sizeof(ConnInfo));
228 conninfo->disallow_premature = -1;
229 conninfo->allow_keyset = -1;
230 conninfo->lf_conversion = -1;
231 conninfo->true_is_minus1 = -1;
232 conninfo->int8_as = -101;
233 conninfo->bytea_as_longvarbinary = -1;
234 conninfo->use_server_side_prepare = -1;
235 conninfo->lower_case_identifier = -1;
236 conninfo->rollback_on_error = -1;
237 conninfo->force_abbrev_connstr = -1;
238 conninfo->bde_environment = -1;
239 conninfo->fake_mss = -1;
240 conninfo->cvt_null_date_string = -1;
241 #ifdef _HANDLE_ENLIST_IN_DTC_
242 conninfo->xa_opt = -1;
243 #endif /* _HANDLE_ENLIST_IN_DTC_ */
244 memcpy(&(conninfo->drivers), &globals, sizeof(globals));
247 #ifdef WIN32
248 extern int platformId;
249 #endif /* WIN32 */
252 * IMPLEMENTATION CONNECTION CLASS
255 static void reset_current_schema(ConnectionClass * self)
257 if (self->current_schema)
259 free(self->current_schema);
260 self->current_schema = NULL;
264 ConnectionClass *CC_Constructor()
266 extern int exepgm;
267 ConnectionClass *rv, *retrv = NULL;
269 rv = (ConnectionClass *) calloc(sizeof(ConnectionClass), 1);
271 if (rv != NULL)
273 // rv->henv = NULL; /* not yet associated with an environment */
275 // rv->__error_message = NULL;
276 // rv->__error_number = 0;
277 // rv->sqlstate[0] = '\0';
278 // rv->errormsg_created = FALSE;
280 rv->status = CONN_NOT_CONNECTED;
282 CC_conninfo_init(&(rv->connInfo));
284 rv->stmts =
285 (StatementClass **) malloc(sizeof(StatementClass *) *
286 STMT_INCREMENT);
287 if (!rv->stmts)
288 goto cleanup;
289 memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
291 rv->num_stmts = STMT_INCREMENT;
292 rv->descs =
293 (DescriptorClass **) malloc(sizeof(DescriptorClass *) *
294 STMT_INCREMENT);
295 if (!rv->descs)
296 goto cleanup;
297 memset(rv->descs, 0,
298 sizeof(DescriptorClass *) * STMT_INCREMENT);
300 rv->num_descs = STMT_INCREMENT;
302 // rv->ncursors = 0;
303 // rv->ntables = 0;
304 // rv->col_info = NULL;
306 // rv->translation_option = 0;
307 // rv->translation_handle = NULL;
308 // rv->DataSourceToDriver = NULL;
309 // rv->DriverToDataSource = NULL;
310 rv->driver_version = ODBCVER;
311 #ifdef WIN32
312 if (VER_PLATFORM_WIN32_WINDOWS == platformId
313 && rv->driver_version > 0x0300)
314 rv->driver_version = 0x0300;
315 #endif /* WIN32 */
316 // memset(rv->pg_version, 0, sizeof(rv->pg_version));
317 // rv->pg_version_number = .0;
318 // rv->pg_version_major = 0;
319 // rv->pg_version_minor = 0;
320 // rv->ms_jet = 0;
321 if (1 == exepgm)
322 rv->ms_jet = 1;
323 // rv->unicode = 0;
324 // rv->result_uncommitted = 0;
325 // rv->schema_support = 0;
326 rv->isolation = SQL_TXN_READ_COMMITTED;
327 // rv->original_client_encoding = NULL;
328 // rv->current_client_encoding = NULL;
329 // rv->server_encoding = NULL;
330 // rv->current_schema = NULL;
331 // rv->num_discardp = 0;
332 // rv->discardp = NULL;
333 rv->mb_maxbyte_per_char = 1;
334 rv->max_identifier_length = -1;
335 rv->escape_in_literal = ESCAPE_IN_LITERAL;
337 /* Initialize statement options to defaults */
338 /* Statements under this conn will inherit these options */
340 InitializeStatementOptions(&rv->stmtOptions);
341 InitializeARDFields(&rv->ardOptions);
342 InitializeAPDFields(&rv->apdOptions);
343 #ifdef _HANDLE_ENLIST_IN_DTC_
344 // rv->asdum = NULL;
345 #endif /* _HANDLE_ENLIST_IN_DTC_ */
346 INIT_CONNLOCK(rv);
347 INIT_CONN_CS(rv);
348 retrv = rv;
351 cleanup:
352 if (rv && !retrv)
353 CC_Destructor(rv);
354 return retrv;
358 char CC_Destructor(ConnectionClass * self)
360 mylog("enter CC_Destructor, self=%p\n", self);
362 if (self->status == CONN_EXECUTING)
363 return 0;
365 CC_cleanup(self); /* cleanup socket and statements */
367 mylog("after CC_Cleanup\n");
369 /* Free up statement holders */
370 if (self->stmts)
372 free(self->stmts);
373 self->stmts = NULL;
375 if (self->descs)
377 free(self->descs);
378 self->descs = NULL;
380 mylog("after free statement holders\n");
382 NULL_THE_NAME(self->schemaIns);
383 NULL_THE_NAME(self->tableIns);
384 if (self->__error_message)
385 free(self->__error_message);
386 DELETE_CONN_CS(self);
387 DELETE_CONNLOCK(self);
388 free(self);
390 mylog("exit CC_Destructor\n");
392 return 1;
396 // VX_CLEANUP: We don't support cursors
397 /* Return how many cursors are opened on this connection */
398 int CC_cursor_count(ConnectionClass * self)
400 StatementClass *stmt;
401 int i, count = 0;
402 QResultClass *res;
404 mylog("CC_cursor_count: self=%p, num_stmts=%d\n", self,
405 self->num_stmts);
407 CONNLOCK_ACQUIRE(self);
408 for (i = 0; i < self->num_stmts; i++)
410 stmt = self->stmts[i];
411 if (stmt && (res = SC_get_Result(stmt)) && QR_get_cursor(res))
412 count++;
414 CONNLOCK_RELEASE(self);
416 mylog("CC_cursor_count: returning %d\n", count);
418 return count;
422 void CC_clear_error(ConnectionClass * self)
424 if (!self)
425 return;
426 CONNLOCK_ACQUIRE(self);
427 self->__error_number = 0;
428 if (self->__error_message)
430 free(self->__error_message);
431 self->__error_message = NULL;
433 self->sqlstate[0] = '\0';
434 self->errormsg_created = FALSE;
435 CONNLOCK_RELEASE(self);
438 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
439 // about to implement it sensibly. Most people who call this either we don't
440 // care about, or we should reimplement.
442 * Used to begin a transaction.
444 char CC_begin(ConnectionClass * self)
446 return FALSE;
449 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
450 // about to implement it sensibly. Most people who call this either we don't
451 // care about, or we should reimplement.
453 * Used to commit a transaction.
454 * We are almost always in the middle of a transaction.
456 char CC_commit(ConnectionClass * self)
458 return FALSE;
461 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
462 // about to implement it sensibly. Most people who call this either we don't
463 // care about, or we should reimplement.
465 * Used to cancel a transaction.
466 * We are almost always in the middle of a transaction.
468 char CC_abort(ConnectionClass * self)
470 return FALSE;
474 /* This is called by SQLDisconnect also */
475 char CC_cleanup(ConnectionClass * self)
477 int i;
478 StatementClass *stmt;
479 DescriptorClass *desc;
481 if (self->status == CONN_EXECUTING)
482 return FALSE;
484 mylog("in CC_Cleanup, self=%p\n", self);
486 /* Free all the stmts on this connection */
487 for (i = 0; i < self->num_stmts; i++)
489 stmt = self->stmts[i];
490 if (stmt)
492 stmt->hdbc = NULL; /* prevent any more dbase interactions */
494 SC_Destructor(stmt);
496 self->stmts[i] = NULL;
499 /* Free all the descs on this connection */
500 for (i = 0; i < self->num_descs; i++)
502 desc = self->descs[i];
503 if (desc)
505 DC_get_conn(desc) = NULL; /* prevent any more dbase interactions */
506 DC_Destructor(desc);
507 free(desc);
508 self->descs[i] = NULL;
512 /* Check for translation dll */
513 #ifdef WIN32
514 if (self->translation_handle)
516 FreeLibrary(self->translation_handle);
517 self->translation_handle = NULL;
519 #endif
521 self->status = CONN_NOT_CONNECTED;
522 CC_conninfo_init(&(self->connInfo));
523 if (self->original_client_encoding)
525 free(self->original_client_encoding);
526 self->original_client_encoding = NULL;
528 if (self->current_client_encoding)
530 free(self->current_client_encoding);
531 self->current_client_encoding = NULL;
533 if (self->server_encoding)
535 free(self->server_encoding);
536 self->server_encoding = NULL;
538 reset_current_schema(self);
539 /* Free cached table info */
540 if (self->col_info)
542 for (i = 0; i < self->ntables; i++)
544 if (self->col_info[i]->result) /* Free the SQLColumns result structure */
545 QR_Destructor(self->col_info[i]->result);
547 NULL_THE_NAME(self->col_info[i]->schema_name);
548 NULL_THE_NAME(self->col_info[i]->table_name);
549 free(self->col_info[i]);
551 free(self->col_info);
552 self->col_info = NULL;
554 self->ntables = 0;
555 self->coli_allocated = 0;
556 if (self->num_discardp > 0 && self->discardp)
558 for (i = 0; i < self->num_discardp; i++)
559 free(self->discardp[i]);
560 self->num_discardp = 0;
562 if (self->discardp)
564 free(self->discardp);
565 self->discardp = NULL;
567 if (self->dbus)
568 WVRELEASE(self->dbus);
570 mylog("exit CC_Cleanup\n");
571 return TRUE;
575 int CC_set_translation(ConnectionClass * self)
578 #ifdef WIN32
579 CSTR func = "CC_set_translation";
581 if (self->translation_handle != NULL)
583 FreeLibrary(self->translation_handle);
584 self->translation_handle = NULL;
587 if (self->connInfo.translation_dll[0] == 0)
588 return TRUE;
590 self->translation_option = atoi(self->connInfo.translation_option);
591 self->translation_handle =
592 LoadLibrary(self->connInfo.translation_dll);
594 if (self->translation_handle == NULL)
596 CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL,
597 "Could not load the translation DLL.", func);
598 return FALSE;
601 self->DataSourceToDriver
603 (DataSourceToDriverProc) GetProcAddress(self->
604 translation_handle,
605 "SQLDataSourceToDriver");
607 self->DriverToDataSource
609 (DriverToDataSourceProc) GetProcAddress(self->
610 translation_handle,
611 "SQLDriverToDataSource");
613 if (self->DataSourceToDriver == NULL
614 || self->DriverToDataSource == NULL)
616 CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL,
617 "Could not find translation DLL functions.", func);
618 return FALSE;
620 #endif
621 return TRUE;
625 static char CC_initial_log(ConnectionClass * self, const char *func)
627 const ConnInfo *ci = &self->connInfo;
628 char vermsg[128];
630 snprintf(vermsg, sizeof(vermsg), "Driver Version='%s,%s'"
631 #ifdef WIN32
632 " linking"
633 #ifdef _MT
634 #ifdef _DLL
635 " dynamic"
636 #else
637 " static"
638 #endif /* _DLL */
639 " Multithread"
640 #else
641 " Singlethread"
642 #endif /* _MT */
643 #ifdef NOT_USED
644 #ifdef _DEBUG
645 " Debug"
646 #else
647 " Release"
648 #endif /* DEBUG */
649 #endif /* NOT_USED */
650 " library"
651 #endif /* WIN32 */
652 "\n", VXODBCDRIVERVERSION, PG_BUILD_VERSION);
653 qlog(vermsg);
654 mylog(vermsg);
656 if (self->original_client_encoding)
657 self->ccsc = pg_CS_code((const UCHAR *)self->original_client_encoding);
658 if (self->status != CONN_NOT_CONNECTED)
660 CC_set_error(self, CONN_OPENDB_ERROR, "Already connected.",
661 func);
662 return 0;
665 mylog
666 ("%s: DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n",
667 func, ci->dsn, ci->server, ci->port, ci->database,
668 ci->username, ci->password ? "xxxxx" : "");
670 if (ci->port[0] == '\0' ||
671 #ifdef WIN32
672 ci->server[0] == '\0' ||
673 #endif /* WIN32 */
674 ci->database[0] == '\0')
676 CC_set_error(self, CONN_INIREAD_ERROR,
677 "Missing server name, port, or database name in call to CC_connect.",
678 func);
679 return 0;
682 return 1;
686 char CC_add_statement(ConnectionClass * self, StatementClass * stmt)
688 int i;
689 char ret = TRUE;
691 mylog("CC_add_statement: self=%p, stmt=%p\n", self, stmt);
693 CONNLOCK_ACQUIRE(self);
694 for (i = 0; i < self->num_stmts; i++)
696 if (!self->stmts[i])
698 stmt->hdbc = self;
699 self->stmts[i] = stmt;
700 break;
704 if (i >= self->num_stmts) /* no more room -- allocate more memory */
706 self->stmts =
707 (StatementClass **) realloc(self->stmts,
708 sizeof(StatementClass *) *
709 (STMT_INCREMENT +
710 self->num_stmts));
711 if (!self->stmts)
712 ret = FALSE;
713 else
715 memset(&self->stmts[self->num_stmts], 0,
716 sizeof(StatementClass *) * STMT_INCREMENT);
718 stmt->hdbc = self;
719 self->stmts[self->num_stmts] = stmt;
721 self->num_stmts += STMT_INCREMENT;
724 CONNLOCK_RELEASE(self);
726 return TRUE;
729 static void CC_set_error_statements(ConnectionClass * self)
731 int i;
733 mylog("CC_error_statements: self=%p\n", self);
735 for (i = 0; i < self->num_stmts; i++)
737 if (NULL != self->stmts[i])
738 SC_ref_CC_error(self->stmts[i]);
743 char CC_remove_statement(ConnectionClass * self, StatementClass * stmt)
745 int i;
746 char ret = FALSE;
748 CONNLOCK_ACQUIRE(self);
749 for (i = 0; i < self->num_stmts; i++)
751 if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING)
753 self->stmts[i] = NULL;
754 ret = TRUE;
755 break;
758 CONNLOCK_RELEASE(self);
760 return ret;
764 * Create a more informative error message by concatenating the connection
765 * error message with its socket error message.
767 // VX_CLEANUP: This is a bit dumb now that there is no socket error message.
768 static char *CC_create_errormsg(ConnectionClass * self)
770 size_t pos;
771 char msg[4096];
772 const char *sockerrmsg;
774 mylog("enter CC_create_errormsg\n");
776 msg[0] = '\0';
778 if (CC_get_errormsg(self))
779 strncpy(msg, CC_get_errormsg(self), sizeof(msg));
781 mylog("msg = '%s'\n", msg);
782 mylog("exit CC_create_errormsg\n");
783 return msg ? strdup(msg) : NULL;
787 void
788 CC_set_error(ConnectionClass * self, int number, const char *message,
789 const char *func)
791 CONNLOCK_ACQUIRE(self);
792 if (self->__error_message)
793 free(self->__error_message);
794 self->__error_number = number;
795 self->__error_message = message ? strdup(message) : NULL;
796 if (0 != number)
797 CC_set_error_statements(self);
798 if (func && number != 0)
799 CC_log_error(func, "", self);
800 CONNLOCK_RELEASE(self);
804 void CC_set_errormsg(ConnectionClass * self, const char *message)
806 CONNLOCK_ACQUIRE(self);
807 if (self->__error_message)
808 free(self->__error_message);
809 self->__error_message = message ? strdup(message) : NULL;
810 CONNLOCK_RELEASE(self);
814 char CC_get_error(ConnectionClass * self, int *number, char **message)
816 int rv;
817 char *msgcrt;
819 mylog("enter CC_get_error\n");
821 CONNLOCK_ACQUIRE(self);
822 /* Create a very informative errormsg if it hasn't been done yet. */
823 if (!self->errormsg_created)
825 msgcrt = CC_create_errormsg(self);
826 if (self->__error_message)
827 free(self->__error_message);
828 self->__error_message = msgcrt;
829 self->errormsg_created = TRUE;
832 if (CC_get_errornumber(self))
834 *number = CC_get_errornumber(self);
835 *message = CC_get_errormsg(self);
837 rv = (CC_get_errornumber(self) != 0);
839 self->__error_number = 0; /* clear the error */
840 CONNLOCK_RELEASE(self);
842 mylog("exit CC_get_error\n");
844 return rv;
848 static void CC_clear_cursors(ConnectionClass * self, BOOL on_abort)
850 int i;
851 StatementClass *stmt;
852 QResultClass *res;
854 if (!self->ncursors)
855 return;
856 CONNLOCK_ACQUIRE(self);
857 for (i = 0; i < self->num_stmts; i++)
859 stmt = self->stmts[i];
860 if (stmt && (res = SC_get_Result(stmt)) && QR_get_cursor(res))
862 if ((on_abort && !QR_is_permanent(res)) ||
863 !QR_is_withhold(res))
865 * non-holdable cursors are automatically closed
866 * at commit time.
867 * all non-permanent cursors are automatically closed
868 * at rollback time.
870 QR_set_cursor(res, NULL);
871 else if (!QR_is_permanent(res))
873 QResultClass *wres;
874 char cmd[64];
876 snprintf(cmd, sizeof(cmd), "MOVE 0 in \"%s\"",
877 QR_get_cursor(res));
878 CONNLOCK_RELEASE(self);
879 wres =
880 CC_send_query(self, cmd, NULL,
881 ROLLBACK_ON_ERROR |
882 IGNORE_ABORT_ON_CONN, NULL);
883 if (QR_command_maybe_successful(wres))
884 QR_set_permanent(res);
885 else
886 QR_set_cursor(res, NULL);
887 QR_Destructor(wres);
888 CONNLOCK_ACQUIRE(self);
892 CONNLOCK_RELEASE(self);
895 static BOOL is_setting_search_path(const UCHAR * query)
897 for (query += 4; *query; query++)
899 if (!isspace(*query))
901 if (strnicmp((const char *)query, "search_path", 11) == 0)
902 return TRUE;
903 query++;
904 while (*query && !isspace(*query))
905 query++;
908 return FALSE;
911 // VX_CLEANUP: This can't possibly have been doing anything useful.
912 // But it's called from a million places, so I can't totally kill it just yet.
913 // Also, those million other places may want to call something non-useless.
915 * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
916 * the same existing QResultClass (this occurs when the tuple cache is depleted and
917 * needs to be re-filled).
919 * The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
920 * (i.e., C3326857) for SQL select statements. This cursor is then used in future
921 * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
923 QResultClass *CC_send_query(ConnectionClass * self, char *query,
924 QueryInfo * qi, UDWORD flag,
925 StatementClass * stmt)
927 CSTR func = "CC_send_query";
928 QResultClass *cmdres = NULL, *retres = NULL, *res = NULL;
930 CC_set_error(self, CONNECTION_COMMUNICATION_ERROR,
931 "CC_send_query not implemented", func);
932 return NULL;
936 static char CC_setenv(ConnectionClass * self)
938 HSTMT hstmt;
939 StatementClass *stmt;
940 RETCODE result;
941 char status = TRUE;
942 CSTR func = "CC_setenv";
945 mylog("%s: entering...\n", func);
948 * This function must use the local odbc API functions since the odbc state
949 * has not transitioned to "connected" yet.
952 result = PGAPI_AllocStmt(self, &hstmt);
953 if (!SQL_SUCCEEDED(result))
954 return FALSE;
955 stmt = (StatementClass *) hstmt;
957 stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */
959 /* Set the Datestyle to the format the driver expects it to be in */
960 result =
961 PGAPI_ExecDirect(hstmt, (const UCHAR *)"set DateStyle to 'ISO'",
962 SQL_NTS, 0);
963 if (!SQL_SUCCEEDED(result))
964 status = FALSE;
966 mylog("%s: result %d, status %d from set DateStyle\n", func, result,
967 status);
969 /* extra_float_digits (applicable since 7.4) */
970 if (PG_VERSION_GT(self, 7.3))
972 result =
973 PGAPI_ExecDirect(hstmt,
974 (const UCHAR *)"set extra_float_digits to 2",
975 SQL_NTS, 0);
976 if (!SQL_SUCCEEDED(result))
977 status = FALSE;
979 mylog("%s: result %d, status %d from set extra_float_digits\n",
980 func, result, status);
984 PGAPI_FreeStmt(hstmt, SQL_DROP);
986 return status;
989 char CC_send_settings(ConnectionClass * self)
991 HSTMT hstmt;
992 StatementClass *stmt;
993 RETCODE result;
994 char status = TRUE;
995 #ifdef HAVE_STRTOK_R
996 char *last;
997 #endif /* HAVE_STRTOK_R */
998 CSTR func = "CC_send_settings";
1001 mylog("%s: entering...\n", func);
1004 * This function must use the local odbc API functions since the odbc state
1005 * has not transitioned to "connected" yet.
1008 result = PGAPI_AllocStmt(self, &hstmt);
1009 if (!SQL_SUCCEEDED(result))
1010 return FALSE;
1011 stmt = (StatementClass *) hstmt;
1013 stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */
1015 PGAPI_FreeStmt(hstmt, SQL_DROP);
1017 return status;
1022 * This function initializes the version of PostgreSQL from
1023 * connInfo.protocol that we're connected to.
1024 * h-inoue 01-2-2001
1026 void CC_initialize_pg_version(ConnectionClass * self)
1028 strcpy(self->pg_version, self->connInfo.protocol);
1029 if (PROTOCOL_62(&self->connInfo))
1031 self->pg_version_number = (float) 6.2;
1032 self->pg_version_major = 6;
1033 self->pg_version_minor = 2;
1034 } else if (PROTOCOL_63(&self->connInfo))
1036 self->pg_version_number = (float) 6.3;
1037 self->pg_version_major = 6;
1038 self->pg_version_minor = 3;
1039 } else if (PROTOCOL_64(&self->connInfo))
1041 self->pg_version_number = (float) 6.4;
1042 self->pg_version_major = 6;
1043 self->pg_version_minor = 4;
1044 } else
1046 self->pg_version_number = (float) 7.4;
1047 self->pg_version_major = 7;
1048 self->pg_version_minor = 4;
1052 void
1053 CC_log_error(const char *func, const char *desc,
1054 const ConnectionClass * self)
1056 #ifdef PRN_NULLCHECK
1057 #define nullcheck(a) (a ? a : "(NULL)")
1058 #endif
1060 if (self)
1062 qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",
1063 func, desc, self->__error_number,
1064 nullcheck(self->__error_message));
1065 mylog
1066 ("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",
1067 func, desc, self->__error_number,
1068 nullcheck(self->__error_message));
1069 qlog(" ------------------------------------------------------------\n");
1070 qlog(" henv=%p, conn=%p, status=%u, num_stmts=%d\n",
1071 self->henv, self, self->status, self->num_stmts);
1072 } else
1074 qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n",
1075 func, desc);
1076 mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n",
1077 func, desc);
1079 #undef PRN_NULLCHECK
1082 int CC_get_max_query_len(const ConnectionClass * conn)
1084 int value;
1086 /* Long Queries in 7.0+ */
1087 if (PG_VERSION_GE(conn, 7.0))
1088 value = 0 /* MAX_STATEMENT_LEN */ ;
1089 /* Prior to 7.0 we used 2*BLCKSZ */
1090 else if (PG_VERSION_GE(conn, 6.5))
1091 value = (2 * BLCKSZ);
1092 else
1093 /* Prior to 6.5 we used BLCKSZ */
1094 value = BLCKSZ;
1095 return value;
1098 // VX_CLEANUP: This looks like a fairly cromulent thing to ask, but
1099 // CC_send_query is the wrong way to get an answer.
1100 // VX_CLEANUP: We probably don't support schemas, so anything referencing
1101 // conn->schema_support is probably junk.
1103 * This doesn't really return the CURRENT SCHEMA
1104 * but there's no alternative.
1106 const char *CC_get_current_schema(ConnectionClass * conn)
1108 if (!conn->current_schema && conn->schema_support)
1110 QResultClass *res;
1112 if (res =
1113 CC_send_query(conn, "select current_schema()", NULL,
1114 IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR,
1115 NULL), QR_command_maybe_successful(res))
1117 if (QR_get_num_total_tuples(res) == 1)
1118 conn->current_schema =
1119 strdup((const char *)QR_get_value_backend_text(res, 0, 0));
1121 QR_Destructor(res);
1123 return (const char *) conn->current_schema;
1126 int CC_mark_a_object_to_discard(ConnectionClass * conn, int type,
1127 const char *plan)
1129 int cnt = conn->num_discardp + 1;
1130 char *pname;
1132 CC_REALLOC_return_with_error(conn->discardp, char *,
1133 (cnt * sizeof(char *)), conn,
1134 "Couldn't alloc discardp.", -1);
1135 CC_MALLOC_return_with_error(pname, char, (strlen(plan) + 2), conn,
1136 "Couldn't alloc discardp mem.", -1);
1137 pname[0] = (char) type; /* 's':prepared statement 'p':cursor */
1138 strcpy(pname + 1, plan);
1139 conn->discardp[conn->num_discardp++] = pname;
1141 return 1;
1144 int CC_discard_marked_objects(ConnectionClass * conn)
1146 int i, cnt;
1147 QResultClass *res;
1148 char *pname, cmd[64];
1150 if ((cnt = conn->num_discardp) <= 0)
1151 return 0;
1152 for (i = cnt - 1; i >= 0; i--)
1154 pname = conn->discardp[i];
1155 if ('s' == pname[0])
1156 snprintf(cmd, sizeof(cmd), "DEALLOCATE \"%s\"", pname + 1);
1157 else
1158 snprintf(cmd, sizeof(cmd), "CLOSE \"%s\"", pname + 1);
1159 res =
1160 CC_send_query(conn, cmd, NULL,
1161 ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN,
1162 NULL);
1163 QR_Destructor(res);
1164 free(conn->discardp[i]);
1165 conn->num_discardp--;
1168 return 1;
1171 const char *CurrCat(const ConnectionClass * conn)
1173 extern int exepgm;
1174 static const char *const ourdb = "__VERSAPLEX";
1176 return exepgm == 2 /* MS Query */ ? 0 : ourdb;
1179 const char *CurrCatString(const ConnectionClass * conn)
1181 const char *cat = CurrCat(conn);
1183 return cat ? cat : NULL_STRING;