Better error reporting when git-get-modules fails.
[versaplex.git] / vxodbc / connection.cc
blob55b4803ea0523a5e398b5d245375dd3edb62d52e
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>
28 #define STMT_INCREMENT 16 /* how many statement holders to allocate
29 * at a time */
31 #define PRN_NULLCHECK
33 extern GLOBAL_VALUES globals;
36 RETCODE SQL_API PGAPI_AllocConnect(HENV henv, HDBC FAR * phdbc)
38 EnvironmentClass *env = (EnvironmentClass *) henv;
39 ConnectionClass *conn;
40 CSTR func = "PGAPI_AllocConnect";
42 mylog("%s: entering...\n", func);
44 conn = CC_Constructor();
45 mylog("**** %s: henv = %p, conn = %p\n", func, henv, conn);
47 if (!conn)
49 env->errormsg =
50 "Couldn't allocate memory for Connection object.";
51 env->errornumber = ENV_ALLOC_ERROR;
52 *phdbc = SQL_NULL_HDBC;
53 EN_log_error(func, "", env);
54 return SQL_ERROR;
57 if (!EN_add_connection(env, conn))
59 env->errormsg = "Maximum number of connections exceeded.";
60 env->errornumber = ENV_ALLOC_ERROR;
61 CC_Destructor(conn);
62 *phdbc = SQL_NULL_HDBC;
63 EN_log_error(func, "", env);
64 return SQL_ERROR;
67 if (phdbc)
68 *phdbc = (HDBC) conn;
70 return SQL_SUCCESS;
74 RETCODE SQL_API
75 PGAPI_Connect(HDBC hdbc,
76 const SQLCHAR FAR * szDSN,
77 SQLSMALLINT cbDSN,
78 const SQLCHAR FAR * szUID,
79 SQLSMALLINT cbUID,
80 const SQLCHAR FAR * szAuthStr, SQLSMALLINT cbAuthStr)
82 ConnectionClass *conn = (ConnectionClass *) hdbc;
83 ConnInfo *ci;
84 CSTR func = "PGAPI_Connect";
85 RETCODE ret = SQL_SUCCESS;
86 char fchar;
88 mylog("%s: entering..cbDSN=%hi.\n", func, cbDSN);
90 if (!conn)
92 CC_log_error(func, "", NULL);
93 return SQL_INVALID_HANDLE;
96 ci = &conn->connInfo;
98 make_string(szDSN, cbDSN, ci->dsn, sizeof(ci->dsn));
100 /* get the values for the DSN from the registry */
101 memcpy(&ci->drivers, &globals, sizeof(globals));
102 getDSNinfo(ci, CONN_OVERWRITE);
103 logs_on_off(1, true, true);
104 /* initialize pg_version from connInfo.protocol */
105 CC_initialize_pg_version(conn);
107 mylog("PGAPI_Connect making DBus connection to %s\n", ci->dbus_moniker);
108 conn->dbus = new WvDBusConn(ci->dbus_moniker);
111 * override values from DSN info with UID and authStr(pwd) This only
112 * occurs if the values are actually there.
114 // VX_CLEANUP: These may be unused.
115 fchar = ci->username[0]; /* save the first byte */
116 make_string(szUID, cbUID, ci->username, sizeof(ci->username));
117 if ('\0' == ci->username[0]) /* an empty string is specified */
118 ci->username[0] = fchar; /* restore the original username */
119 fchar = ci->password[0];
120 make_string(szAuthStr, cbAuthStr, ci->password,
121 sizeof(ci->password));
122 if ('\0' == ci->password[0]) /* an empty string is specified */
123 ci->password[0] = fchar; /* restore the original password */
125 /* fill in any defaults */
126 getDSNdefaults(ci);
128 qlog("conn = %p, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func,
129 ci->dsn, ci->username, ci->password ? "xxxxx" : "");
131 mylog("%s: returning..%d.\n", func, ret);
133 return ret;
137 RETCODE SQL_API
138 PGAPI_BrowseConnect(HDBC hdbc,
139 const SQLCHAR FAR * szConnStrIn,
140 SQLSMALLINT cbConnStrIn,
141 SQLCHAR FAR * szConnStrOut,
142 SQLSMALLINT cbConnStrOutMax,
143 SQLSMALLINT FAR * pcbConnStrOut)
145 CSTR func = "PGAPI_BrowseConnect";
146 ConnectionClass *conn = (ConnectionClass *) hdbc;
148 mylog("%s: entering...\n", func);
150 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR,
151 "Function not implemented", func);
152 return SQL_ERROR;
156 /* Drop any hstmts open on hdbc and disconnect from database */
157 RETCODE SQL_API PGAPI_Disconnect(HDBC hdbc)
159 ConnectionClass *conn = (ConnectionClass *) hdbc;
160 CSTR func = "PGAPI_Disconnect";
163 mylog("%s: entering...\n", func);
165 if (!conn)
167 CC_log_error(func, "", NULL);
168 return SQL_INVALID_HANDLE;
171 qlog("conn=%p, %s\n", conn, func);
173 if (conn->status == CONN_EXECUTING)
175 CC_set_error(conn, CONN_IN_USE,
176 "A transaction is currently being executed", func);
177 return SQL_ERROR;
180 logs_on_off(-1, true, true);
181 mylog("%s: about to CC_cleanup\n", func);
183 /* Close the connection and free statements */
184 CC_cleanup(conn);
186 mylog("%s: done CC_cleanup\n", func);
187 mylog("%s: returning...\n", func);
189 return SQL_SUCCESS;
193 RETCODE SQL_API PGAPI_FreeConnect(HDBC hdbc)
195 ConnectionClass *conn = (ConnectionClass *) hdbc;
196 CSTR func = "PGAPI_FreeConnect";
198 mylog("%s: entering...\n", func);
199 mylog("**** in %s: hdbc=%p\n", func, hdbc);
201 if (!conn)
203 CC_log_error(func, "", NULL);
204 return SQL_INVALID_HANDLE;
207 /* Remove the connection from the environment */
208 if (!EN_remove_connection(conn->henv, conn))
210 CC_set_error(conn, CONN_IN_USE,
211 "A transaction is currently being executed", func);
212 return SQL_ERROR;
215 CC_Destructor(conn);
217 mylog("%s: returning...\n", func);
219 return SQL_SUCCESS;
223 void CC_conninfo_init(ConnInfo * conninfo)
225 memset(conninfo, 0, sizeof(ConnInfo));
226 conninfo->disallow_premature = -1;
227 conninfo->allow_keyset = -1;
228 conninfo->lf_conversion = -1;
229 conninfo->true_is_minus1 = -1;
230 conninfo->int8_as = -101;
231 conninfo->bytea_as_longvarbinary = -1;
232 conninfo->use_server_side_prepare = -1;
233 conninfo->lower_case_identifier = -1;
234 conninfo->rollback_on_error = -1;
235 conninfo->force_abbrev_connstr = -1;
236 conninfo->bde_environment = -1;
237 conninfo->fake_mss = -1;
238 conninfo->cvt_null_date_string = -1;
239 #ifdef _HANDLE_ENLIST_IN_DTC_
240 conninfo->xa_opt = -1;
241 #endif /* _HANDLE_ENLIST_IN_DTC_ */
242 memcpy(&(conninfo->drivers), &globals, sizeof(globals));
245 #ifdef WIN32
246 extern int platformId;
247 #endif /* WIN32 */
250 * IMPLEMENTATION CONNECTION CLASS
253 static void reset_current_schema(ConnectionClass * self)
255 if (self->current_schema)
257 free(self->current_schema);
258 self->current_schema = NULL;
262 ConnectionClass *CC_Constructor()
264 extern int exepgm;
265 ConnectionClass *rv, *retrv = NULL;
267 rv = (ConnectionClass *) calloc(sizeof(ConnectionClass), 1);
269 if (rv != NULL)
271 // rv->henv = NULL; /* not yet associated with an environment */
273 // rv->__error_message = NULL;
274 // rv->__error_number = 0;
275 // rv->sqlstate[0] = '\0';
276 // rv->errormsg_created = FALSE;
278 rv->status = CONN_NOT_CONNECTED;
280 CC_conninfo_init(&(rv->connInfo));
282 rv->stmts =
283 (StatementClass **) malloc(sizeof(StatementClass *) *
284 STMT_INCREMENT);
285 if (!rv->stmts)
286 goto cleanup;
287 memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
289 rv->num_stmts = STMT_INCREMENT;
290 rv->descs =
291 (DescriptorClass **) malloc(sizeof(DescriptorClass *) *
292 STMT_INCREMENT);
293 if (!rv->descs)
294 goto cleanup;
295 memset(rv->descs, 0,
296 sizeof(DescriptorClass *) * STMT_INCREMENT);
298 rv->num_descs = STMT_INCREMENT;
300 // rv->ncursors = 0;
301 // rv->ntables = 0;
302 // rv->col_info = NULL;
304 // rv->translation_option = 0;
305 // rv->translation_handle = NULL;
306 // rv->DataSourceToDriver = NULL;
307 // rv->DriverToDataSource = NULL;
308 rv->driver_version = ODBCVER;
309 #ifdef WIN32
310 if (VER_PLATFORM_WIN32_WINDOWS == platformId
311 && rv->driver_version > 0x0300)
312 rv->driver_version = 0x0300;
313 #endif /* WIN32 */
314 // memset(rv->pg_version, 0, sizeof(rv->pg_version));
315 // rv->pg_version_number = .0;
316 // rv->pg_version_major = 0;
317 // rv->pg_version_minor = 0;
318 // rv->ms_jet = 0;
319 if (1 == exepgm)
320 rv->ms_jet = 1;
321 // rv->unicode = 0;
322 // rv->result_uncommitted = 0;
323 // rv->schema_support = 0;
324 rv->isolation = SQL_TXN_READ_COMMITTED;
325 // rv->original_client_encoding = NULL;
326 // rv->current_client_encoding = NULL;
327 // rv->server_encoding = NULL;
328 // rv->current_schema = NULL;
329 // rv->num_discardp = 0;
330 // rv->discardp = NULL;
331 rv->mb_maxbyte_per_char = 1;
332 rv->max_identifier_length = -1;
333 rv->escape_in_literal = ESCAPE_IN_LITERAL;
335 /* Initialize statement options to defaults */
336 /* Statements under this conn will inherit these options */
338 InitializeStatementOptions(&rv->stmtOptions);
339 InitializeARDFields(&rv->ardOptions);
340 InitializeAPDFields(&rv->apdOptions);
341 #ifdef _HANDLE_ENLIST_IN_DTC_
342 // rv->asdum = NULL;
343 #endif /* _HANDLE_ENLIST_IN_DTC_ */
344 INIT_CONNLOCK(rv);
345 INIT_CONN_CS(rv);
346 retrv = rv;
349 cleanup:
350 if (rv && !retrv)
351 CC_Destructor(rv);
352 return retrv;
356 char CC_Destructor(ConnectionClass * self)
358 mylog("enter CC_Destructor, self=%p\n", self);
360 if (self->status == CONN_EXECUTING)
361 return 0;
363 CC_cleanup(self); /* cleanup socket and statements */
365 mylog("after CC_Cleanup\n");
367 /* Free up statement holders */
368 if (self->stmts)
370 free(self->stmts);
371 self->stmts = NULL;
373 if (self->descs)
375 free(self->descs);
376 self->descs = NULL;
378 mylog("after free statement holders\n");
380 NULL_THE_NAME(self->schemaIns);
381 NULL_THE_NAME(self->tableIns);
382 if (self->__error_message)
383 free(self->__error_message);
384 DELETE_CONN_CS(self);
385 DELETE_CONNLOCK(self);
386 free(self);
388 mylog("exit CC_Destructor\n");
390 return 1;
394 // VX_CLEANUP: We don't support cursors
395 /* Return how many cursors are opened on this connection */
396 int CC_cursor_count(ConnectionClass * self)
398 StatementClass *stmt;
399 int i, count = 0;
400 QResultClass *res;
402 mylog("CC_cursor_count: self=%p, num_stmts=%d\n", self,
403 self->num_stmts);
405 CONNLOCK_ACQUIRE(self);
406 for (i = 0; i < self->num_stmts; i++)
408 stmt = self->stmts[i];
409 if (stmt && (res = SC_get_Result(stmt)) && QR_get_cursor(res))
410 count++;
412 CONNLOCK_RELEASE(self);
414 mylog("CC_cursor_count: returning %d\n", count);
416 return count;
420 void CC_clear_error(ConnectionClass * self)
422 if (!self)
423 return;
424 CONNLOCK_ACQUIRE(self);
425 self->__error_number = 0;
426 if (self->__error_message)
428 free(self->__error_message);
429 self->__error_message = NULL;
431 self->sqlstate[0] = '\0';
432 self->errormsg_created = FALSE;
433 CONNLOCK_RELEASE(self);
436 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
437 // about to implement it sensibly. Most people who call this either we don't
438 // care about, or we should reimplement.
440 * Used to begin a transaction.
442 char CC_begin(ConnectionClass * self)
444 return FALSE;
447 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
448 // about to implement it sensibly. Most people who call this either we don't
449 // care about, or we should reimplement.
451 * Used to commit a transaction.
452 * We are almost always in the middle of a transaction.
454 char CC_commit(ConnectionClass * self)
456 return FALSE;
459 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
460 // about to implement it sensibly. Most people who call this either we don't
461 // care about, or we should reimplement.
463 * Used to cancel a transaction.
464 * We are almost always in the middle of a transaction.
466 char CC_abort(ConnectionClass * self)
468 return FALSE;
472 /* This is called by SQLDisconnect also */
473 char CC_cleanup(ConnectionClass * self)
475 int i;
476 StatementClass *stmt;
477 DescriptorClass *desc;
479 if (self->status == CONN_EXECUTING)
480 return FALSE;
482 mylog("in CC_Cleanup, self=%p\n", self);
484 /* Free all the stmts on this connection */
485 for (i = 0; i < self->num_stmts; i++)
487 stmt = self->stmts[i];
488 if (stmt)
490 stmt->hdbc = NULL; /* prevent any more dbase interactions */
492 SC_Destructor(stmt);
494 self->stmts[i] = NULL;
497 /* Free all the descs on this connection */
498 for (i = 0; i < self->num_descs; i++)
500 desc = self->descs[i];
501 if (desc)
503 DC_get_conn(desc) = NULL; /* prevent any more dbase interactions */
504 DC_Destructor(desc);
505 free(desc);
506 self->descs[i] = NULL;
510 /* Check for translation dll */
511 #ifdef WIN32
512 if (self->translation_handle)
514 FreeLibrary(self->translation_handle);
515 self->translation_handle = NULL;
517 #endif
519 self->status = CONN_NOT_CONNECTED;
520 CC_conninfo_init(&(self->connInfo));
521 if (self->original_client_encoding)
523 free(self->original_client_encoding);
524 self->original_client_encoding = NULL;
526 if (self->current_client_encoding)
528 free(self->current_client_encoding);
529 self->current_client_encoding = NULL;
531 if (self->server_encoding)
533 free(self->server_encoding);
534 self->server_encoding = NULL;
536 reset_current_schema(self);
537 /* Free cached table info */
538 if (self->col_info)
540 for (i = 0; i < self->ntables; i++)
542 if (self->col_info[i]->result) /* Free the SQLColumns result structure */
543 QR_Destructor(self->col_info[i]->result);
545 NULL_THE_NAME(self->col_info[i]->schema_name);
546 NULL_THE_NAME(self->col_info[i]->table_name);
547 free(self->col_info[i]);
549 free(self->col_info);
550 self->col_info = NULL;
552 self->ntables = 0;
553 self->coli_allocated = 0;
554 if (self->num_discardp > 0 && self->discardp)
556 for (i = 0; i < self->num_discardp; i++)
557 free(self->discardp[i]);
558 self->num_discardp = 0;
560 if (self->discardp)
562 free(self->discardp);
563 self->discardp = NULL;
565 if (self->dbus)
566 WVRELEASE(self->dbus);
568 mylog("exit CC_Cleanup\n");
569 return TRUE;
573 int CC_set_translation(ConnectionClass * self)
576 #ifdef WIN32
577 CSTR func = "CC_set_translation";
579 if (self->translation_handle != NULL)
581 FreeLibrary(self->translation_handle);
582 self->translation_handle = NULL;
585 if (self->connInfo.translation_dll[0] == 0)
586 return TRUE;
588 self->translation_option = atoi(self->connInfo.translation_option);
589 self->translation_handle =
590 LoadLibrary(self->connInfo.translation_dll);
592 if (self->translation_handle == NULL)
594 CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL,
595 "Could not load the translation DLL.", func);
596 return FALSE;
599 self->DataSourceToDriver
601 (DataSourceToDriverProc) GetProcAddress(self->
602 translation_handle,
603 "SQLDataSourceToDriver");
605 self->DriverToDataSource
607 (DriverToDataSourceProc) GetProcAddress(self->
608 translation_handle,
609 "SQLDriverToDataSource");
611 if (self->DataSourceToDriver == NULL
612 || self->DriverToDataSource == NULL)
614 CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL,
615 "Could not find translation DLL functions.", func);
616 return FALSE;
618 #endif
619 return TRUE;
623 static char CC_initial_log(ConnectionClass * self, const char *func)
625 const ConnInfo *ci = &self->connInfo;
626 char vermsg[128];
628 snprintf(vermsg, sizeof(vermsg), "Driver Version='%s,%s'"
629 #ifdef WIN32
630 " linking"
631 #ifdef _MT
632 #ifdef _DLL
633 " dynamic"
634 #else
635 " static"
636 #endif /* _DLL */
637 " Multithread"
638 #else
639 " Singlethread"
640 #endif /* _MT */
641 #ifdef NOT_USED
642 #ifdef _DEBUG
643 " Debug"
644 #else
645 " Release"
646 #endif /* DEBUG */
647 #endif /* NOT_USED */
648 " library"
649 #endif /* WIN32 */
650 "\n", VXODBCDRIVERVERSION, PG_BUILD_VERSION);
651 qlog(vermsg);
652 mylog(vermsg);
654 if (self->original_client_encoding)
655 self->ccsc = pg_CS_code((const UCHAR *)self->original_client_encoding);
656 if (self->status != CONN_NOT_CONNECTED)
658 CC_set_error(self, CONN_OPENDB_ERROR, "Already connected.",
659 func);
660 return 0;
663 mylog
664 ("%s: DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n",
665 func, ci->dsn, ci->server, ci->port, ci->database,
666 ci->username, ci->password ? "xxxxx" : "");
668 if (ci->port[0] == '\0' ||
669 #ifdef WIN32
670 ci->server[0] == '\0' ||
671 #endif /* WIN32 */
672 ci->database[0] == '\0')
674 CC_set_error(self, CONN_INIREAD_ERROR,
675 "Missing server name, port, or database name in call to CC_connect.",
676 func);
677 return 0;
680 return 1;
684 char CC_add_statement(ConnectionClass * self, StatementClass * stmt)
686 int i;
687 char ret = TRUE;
689 mylog("CC_add_statement: self=%p, stmt=%p\n", self, stmt);
691 CONNLOCK_ACQUIRE(self);
692 for (i = 0; i < self->num_stmts; i++)
694 if (!self->stmts[i])
696 stmt->hdbc = self;
697 self->stmts[i] = stmt;
698 break;
702 if (i >= self->num_stmts) /* no more room -- allocate more memory */
704 self->stmts =
705 (StatementClass **) realloc(self->stmts,
706 sizeof(StatementClass *) *
707 (STMT_INCREMENT +
708 self->num_stmts));
709 if (!self->stmts)
710 ret = FALSE;
711 else
713 memset(&self->stmts[self->num_stmts], 0,
714 sizeof(StatementClass *) * STMT_INCREMENT);
716 stmt->hdbc = self;
717 self->stmts[self->num_stmts] = stmt;
719 self->num_stmts += STMT_INCREMENT;
722 CONNLOCK_RELEASE(self);
724 return TRUE;
727 static void CC_set_error_statements(ConnectionClass * self)
729 int i;
731 mylog("CC_error_statements: self=%p\n", self);
733 for (i = 0; i < self->num_stmts; i++)
735 if (NULL != self->stmts[i])
736 SC_ref_CC_error(self->stmts[i]);
741 char CC_remove_statement(ConnectionClass * self, StatementClass * stmt)
743 int i;
744 char ret = FALSE;
746 CONNLOCK_ACQUIRE(self);
747 for (i = 0; i < self->num_stmts; i++)
749 if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING)
751 self->stmts[i] = NULL;
752 ret = TRUE;
753 break;
756 CONNLOCK_RELEASE(self);
758 return ret;
762 * Create a more informative error message by concatenating the connection
763 * error message with its socket error message.
765 // VX_CLEANUP: This is a bit dumb now that there is no socket error message.
766 static char *CC_create_errormsg(ConnectionClass * self)
768 size_t pos;
769 char msg[4096];
770 const char *sockerrmsg;
772 mylog("enter CC_create_errormsg\n");
774 msg[0] = '\0';
776 if (CC_get_errormsg(self))
777 strncpy(msg, CC_get_errormsg(self), sizeof(msg));
779 mylog("msg = '%s'\n", msg);
780 mylog("exit CC_create_errormsg\n");
781 return msg ? strdup(msg) : NULL;
785 void
786 CC_set_error(ConnectionClass * self, int number, const char *message,
787 const char *func)
789 CONNLOCK_ACQUIRE(self);
790 if (self->__error_message)
791 free(self->__error_message);
792 self->__error_number = number;
793 self->__error_message = message ? strdup(message) : NULL;
794 if (0 != number)
795 CC_set_error_statements(self);
796 if (func && number != 0)
797 CC_log_error(func, "", self);
798 CONNLOCK_RELEASE(self);
802 void CC_set_errormsg(ConnectionClass * self, const char *message)
804 CONNLOCK_ACQUIRE(self);
805 if (self->__error_message)
806 free(self->__error_message);
807 self->__error_message = message ? strdup(message) : NULL;
808 CONNLOCK_RELEASE(self);
812 char CC_get_error(ConnectionClass * self, int *number, char **message)
814 int rv;
815 char *msgcrt;
817 mylog("enter CC_get_error\n");
819 CONNLOCK_ACQUIRE(self);
820 /* Create a very informative errormsg if it hasn't been done yet. */
821 if (!self->errormsg_created)
823 msgcrt = CC_create_errormsg(self);
824 if (self->__error_message)
825 free(self->__error_message);
826 self->__error_message = msgcrt;
827 self->errormsg_created = TRUE;
830 if (CC_get_errornumber(self))
832 *number = CC_get_errornumber(self);
833 *message = CC_get_errormsg(self);
835 rv = (CC_get_errornumber(self) != 0);
837 self->__error_number = 0; /* clear the error */
838 CONNLOCK_RELEASE(self);
840 mylog("exit CC_get_error\n");
842 return rv;
846 static void CC_clear_cursors(ConnectionClass * self, BOOL on_abort)
848 int i;
849 StatementClass *stmt;
850 QResultClass *res;
852 if (!self->ncursors)
853 return;
854 CONNLOCK_ACQUIRE(self);
855 for (i = 0; i < self->num_stmts; i++)
857 stmt = self->stmts[i];
858 if (stmt && (res = SC_get_Result(stmt)) && QR_get_cursor(res))
860 if ((on_abort && !QR_is_permanent(res)) ||
861 !QR_is_withhold(res))
863 * non-holdable cursors are automatically closed
864 * at commit time.
865 * all non-permanent cursors are automatically closed
866 * at rollback time.
868 QR_set_cursor(res, NULL);
869 else if (!QR_is_permanent(res))
871 QResultClass *wres;
872 char cmd[64];
874 snprintf(cmd, sizeof(cmd), "MOVE 0 in \"%s\"",
875 QR_get_cursor(res));
876 CONNLOCK_RELEASE(self);
877 wres =
878 CC_send_query(self, cmd, NULL,
879 ROLLBACK_ON_ERROR |
880 IGNORE_ABORT_ON_CONN, NULL);
881 if (QR_command_maybe_successful(wres))
882 QR_set_permanent(res);
883 else
884 QR_set_cursor(res, NULL);
885 QR_Destructor(wres);
886 CONNLOCK_ACQUIRE(self);
890 CONNLOCK_RELEASE(self);
893 static BOOL is_setting_search_path(const UCHAR * query)
895 for (query += 4; *query; query++)
897 if (!isspace(*query))
899 if (strnicmp((const char *)query, "search_path", 11) == 0)
900 return TRUE;
901 query++;
902 while (*query && !isspace(*query))
903 query++;
906 return FALSE;
909 // VX_CLEANUP: This can't possibly have been doing anything useful.
910 // But it's called from a million places, so I can't totally kill it just yet.
911 // Also, those million other places may want to call something non-useless.
913 * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
914 * the same existing QResultClass (this occurs when the tuple cache is depleted and
915 * needs to be re-filled).
917 * The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
918 * (i.e., C3326857) for SQL select statements. This cursor is then used in future
919 * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
921 QResultClass *CC_send_query(ConnectionClass * self, char *query,
922 QueryInfo * qi, UDWORD flag,
923 StatementClass * stmt)
925 CSTR func = "CC_send_query";
926 QResultClass *cmdres = NULL, *retres = NULL, *res = NULL;
928 CC_set_error(self, CONNECTION_COMMUNICATION_ERROR,
929 "CC_send_query not implemented", func);
930 return NULL;
934 static char CC_setenv(ConnectionClass * self)
936 HSTMT hstmt;
937 StatementClass *stmt;
938 RETCODE result;
939 char status = TRUE;
940 CSTR func = "CC_setenv";
943 mylog("%s: entering...\n", func);
946 * This function must use the local odbc API functions since the odbc state
947 * has not transitioned to "connected" yet.
950 result = PGAPI_AllocStmt(self, &hstmt);
951 if (!SQL_SUCCEEDED(result))
952 return FALSE;
953 stmt = (StatementClass *) hstmt;
955 stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */
957 /* Set the Datestyle to the format the driver expects it to be in */
958 result =
959 PGAPI_ExecDirect(hstmt, (const UCHAR *)"set DateStyle to 'ISO'",
960 SQL_NTS, 0);
961 if (!SQL_SUCCEEDED(result))
962 status = FALSE;
964 mylog("%s: result %d, status %d from set DateStyle\n", func, result,
965 status);
967 /* extra_float_digits (applicable since 7.4) */
968 if (PG_VERSION_GT(self, 7.3))
970 result =
971 PGAPI_ExecDirect(hstmt,
972 (const UCHAR *)"set extra_float_digits to 2",
973 SQL_NTS, 0);
974 if (!SQL_SUCCEEDED(result))
975 status = FALSE;
977 mylog("%s: result %d, status %d from set extra_float_digits\n",
978 func, result, status);
982 PGAPI_FreeStmt(hstmt, SQL_DROP);
984 return status;
987 char CC_send_settings(ConnectionClass * self)
989 HSTMT hstmt;
990 StatementClass *stmt;
991 RETCODE result;
992 char status = TRUE;
993 #ifdef HAVE_STRTOK_R
994 char *last;
995 #endif /* HAVE_STRTOK_R */
996 CSTR func = "CC_send_settings";
999 mylog("%s: entering...\n", func);
1002 * This function must use the local odbc API functions since the odbc state
1003 * has not transitioned to "connected" yet.
1006 result = PGAPI_AllocStmt(self, &hstmt);
1007 if (!SQL_SUCCEEDED(result))
1008 return FALSE;
1009 stmt = (StatementClass *) hstmt;
1011 stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */
1013 PGAPI_FreeStmt(hstmt, SQL_DROP);
1015 return status;
1020 * This function initializes the version of PostgreSQL from
1021 * connInfo.protocol that we're connected to.
1022 * h-inoue 01-2-2001
1024 void CC_initialize_pg_version(ConnectionClass * self)
1026 strcpy(self->pg_version, self->connInfo.protocol);
1027 if (PROTOCOL_62(&self->connInfo))
1029 self->pg_version_number = (float) 6.2;
1030 self->pg_version_major = 6;
1031 self->pg_version_minor = 2;
1032 } else if (PROTOCOL_63(&self->connInfo))
1034 self->pg_version_number = (float) 6.3;
1035 self->pg_version_major = 6;
1036 self->pg_version_minor = 3;
1037 } else if (PROTOCOL_64(&self->connInfo))
1039 self->pg_version_number = (float) 6.4;
1040 self->pg_version_major = 6;
1041 self->pg_version_minor = 4;
1042 } else
1044 self->pg_version_number = (float) 7.4;
1045 self->pg_version_major = 7;
1046 self->pg_version_minor = 4;
1050 void
1051 CC_log_error(const char *func, const char *desc,
1052 const ConnectionClass * self)
1054 #ifdef PRN_NULLCHECK
1055 #define nullcheck(a) (a ? a : "(NULL)")
1056 #endif
1058 if (self)
1060 qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",
1061 func, desc, self->__error_number,
1062 nullcheck(self->__error_message));
1063 mylog
1064 ("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",
1065 func, desc, self->__error_number,
1066 nullcheck(self->__error_message));
1067 qlog(" ------------------------------------------------------------\n");
1068 qlog(" henv=%p, conn=%p, status=%u, num_stmts=%d\n",
1069 self->henv, self, self->status, self->num_stmts);
1070 } else
1072 qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n",
1073 func, desc);
1074 mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n",
1075 func, desc);
1077 #undef PRN_NULLCHECK
1080 int CC_get_max_query_len(const ConnectionClass * conn)
1082 int value;
1084 /* Long Queries in 7.0+ */
1085 if (PG_VERSION_GE(conn, 7.0))
1086 value = 0 /* MAX_STATEMENT_LEN */ ;
1087 /* Prior to 7.0 we used 2*BLCKSZ */
1088 else if (PG_VERSION_GE(conn, 6.5))
1089 value = (2 * BLCKSZ);
1090 else
1091 /* Prior to 6.5 we used BLCKSZ */
1092 value = BLCKSZ;
1093 return value;
1096 // VX_CLEANUP: This looks like a fairly cromulent thing to ask, but
1097 // CC_send_query is the wrong way to get an answer.
1098 // VX_CLEANUP: We probably don't support schemas, so anything referencing
1099 // conn->schema_support is probably junk.
1101 * This doesn't really return the CURRENT SCHEMA
1102 * but there's no alternative.
1104 const char *CC_get_current_schema(ConnectionClass * conn)
1106 if (!conn->current_schema && conn->schema_support)
1108 QResultClass *res;
1110 if (res =
1111 CC_send_query(conn, "select current_schema()", NULL,
1112 IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR,
1113 NULL), QR_command_maybe_successful(res))
1115 if (QR_get_num_total_tuples(res) == 1)
1116 conn->current_schema =
1117 strdup((const char *)QR_get_value_backend_text(res, 0, 0));
1119 QR_Destructor(res);
1121 return (const char *) conn->current_schema;
1124 int CC_mark_a_object_to_discard(ConnectionClass * conn, int type,
1125 const char *plan)
1127 int cnt = conn->num_discardp + 1;
1128 char *pname;
1130 CC_REALLOC_return_with_error(conn->discardp, char *,
1131 (cnt * sizeof(char *)), conn,
1132 "Couldn't alloc discardp.", -1);
1133 CC_MALLOC_return_with_error(pname, char, (strlen(plan) + 2), conn,
1134 "Couldn't alloc discardp mem.", -1);
1135 pname[0] = (char) type; /* 's':prepared statement 'p':cursor */
1136 strcpy(pname + 1, plan);
1137 conn->discardp[conn->num_discardp++] = pname;
1139 return 1;
1142 int CC_discard_marked_objects(ConnectionClass * conn)
1144 int i, cnt;
1145 QResultClass *res;
1146 char *pname, cmd[64];
1148 if ((cnt = conn->num_discardp) <= 0)
1149 return 0;
1150 for (i = cnt - 1; i >= 0; i--)
1152 pname = conn->discardp[i];
1153 if ('s' == pname[0])
1154 snprintf(cmd, sizeof(cmd), "DEALLOCATE \"%s\"", pname + 1);
1155 else
1156 snprintf(cmd, sizeof(cmd), "CLOSE \"%s\"", pname + 1);
1157 res =
1158 CC_send_query(conn, cmd, NULL,
1159 ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN,
1160 NULL);
1161 QR_Destructor(res);
1162 free(conn->discardp[i]);
1163 conn->num_discardp--;
1166 return 1;
1169 // VX_CLEANUP: This can obviously be simplified away.
1170 const char *CurrCat(const ConnectionClass * conn)
1172 return NULL;
1175 const char *CurrCatString(const ConnectionClass * conn)
1177 const char *cat = CurrCat(conn);
1179 if (!cat)
1180 cat = NULL_STRING;
1181 return cat;