2 * Description: This module contains routines related to
3 * connecting to and disconnecting from the Postgres DBMS.
5 /* Multibyte support Eiji Tokuya 2001-03-15 */
7 #include "connection.h"
17 #include "statement.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
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
);
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
);
58 if (!EN_add_connection(env
, conn
))
60 env
->errormsg
= "Maximum number of connections exceeded.";
61 env
->errornumber
= ENV_ALLOC_ERROR
;
63 *phdbc
= SQL_NULL_HDBC
;
64 EN_log_error(func
, "", env
);
76 PGAPI_Connect(HDBC hdbc
,
77 const SQLCHAR FAR
* szDSN
,
79 const SQLCHAR FAR
* szUID
,
81 const SQLCHAR FAR
* szAuthStr
, SQLSMALLINT cbAuthStr
)
83 ConnectionClass
*conn
= (ConnectionClass
*) hdbc
;
85 CSTR func
= "PGAPI_Connect";
86 RETCODE ret
= SQL_SUCCESS
;
89 mylog("%s: entering..cbDSN=%hi.\n", func
, cbDSN
);
94 CC_log_error(func
, "", NULL
);
95 return SQL_INVALID_HANDLE
;
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 */
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
);
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
);
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
);
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
);
182 logs_on_off(-1, true, true);
183 mylog("%s: about to CC_cleanup\n", func
);
185 /* Close the connection and free statements */
188 mylog("%s: done CC_cleanup\n", func
);
189 mylog("%s: returning...\n", func
);
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
);
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
);
219 mylog("%s: returning...\n", func
);
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
));
248 extern int platformId
;
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()
267 ConnectionClass
*rv
, *retrv
= NULL
;
269 rv
= (ConnectionClass
*) calloc(sizeof(ConnectionClass
), 1);
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
));
285 (StatementClass
**) malloc(sizeof(StatementClass
*) *
289 memset(rv
->stmts
, 0, sizeof(StatementClass
*) * STMT_INCREMENT
);
291 rv
->num_stmts
= STMT_INCREMENT
;
293 (DescriptorClass
**) malloc(sizeof(DescriptorClass
*) *
298 sizeof(DescriptorClass
*) * STMT_INCREMENT
);
300 rv
->num_descs
= STMT_INCREMENT
;
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
;
312 if (VER_PLATFORM_WIN32_WINDOWS
== platformId
313 && rv
->driver_version
> 0x0300)
314 rv
->driver_version
= 0x0300;
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;
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_
345 #endif /* _HANDLE_ENLIST_IN_DTC_ */
358 char CC_Destructor(ConnectionClass
* self
)
360 mylog("enter CC_Destructor, self=%p\n", self
);
362 if (self
->status
== CONN_EXECUTING
)
365 CC_cleanup(self
); /* cleanup socket and statements */
367 mylog("after CC_Cleanup\n");
369 /* Free up statement holders */
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
);
390 mylog("exit CC_Destructor\n");
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
;
404 mylog("CC_cursor_count: self=%p, num_stmts=%d\n", self
,
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
))
414 CONNLOCK_RELEASE(self
);
416 mylog("CC_cursor_count: returning %d\n", count
);
422 void CC_clear_error(ConnectionClass
* self
)
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
)
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
)
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
)
474 /* This is called by SQLDisconnect also */
475 char CC_cleanup(ConnectionClass
* self
)
478 StatementClass
*stmt
;
479 DescriptorClass
*desc
;
481 if (self
->status
== CONN_EXECUTING
)
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
];
492 stmt
->hdbc
= NULL
; /* prevent any more dbase interactions */
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
];
505 DC_get_conn(desc
) = NULL
; /* prevent any more dbase interactions */
508 self
->descs
[i
] = NULL
;
512 /* Check for translation dll */
514 if (self
->translation_handle
)
516 FreeLibrary(self
->translation_handle
);
517 self
->translation_handle
= NULL
;
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 */
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
;
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;
564 free(self
->discardp
);
565 self
->discardp
= NULL
;
568 WVRELEASE(self
->dbus
);
570 mylog("exit CC_Cleanup\n");
575 int CC_set_translation(ConnectionClass
* self
)
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)
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
);
601 self
->DataSourceToDriver
603 (DataSourceToDriverProc
) GetProcAddress(self
->
605 "SQLDataSourceToDriver");
607 self
->DriverToDataSource
609 (DriverToDataSourceProc
) GetProcAddress(self
->
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
);
625 static char CC_initial_log(ConnectionClass
* self
, const char *func
)
627 const ConnInfo
*ci
= &self
->connInfo
;
630 snprintf(vermsg
, sizeof(vermsg
), "Driver Version='%s,%s'"
649 #endif /* NOT_USED */
652 "\n", VXODBCDRIVERVERSION
, PG_BUILD_VERSION
);
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.",
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' ||
672 ci
->server
[0] == '\0' ||
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.",
686 char CC_add_statement(ConnectionClass
* self
, StatementClass
* stmt
)
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
++)
699 self
->stmts
[i
] = stmt
;
704 if (i
>= self
->num_stmts
) /* no more room -- allocate more memory */
707 (StatementClass
**) realloc(self
->stmts
,
708 sizeof(StatementClass
*) *
715 memset(&self
->stmts
[self
->num_stmts
], 0,
716 sizeof(StatementClass
*) * STMT_INCREMENT
);
719 self
->stmts
[self
->num_stmts
] = stmt
;
721 self
->num_stmts
+= STMT_INCREMENT
;
724 CONNLOCK_RELEASE(self
);
729 static void CC_set_error_statements(ConnectionClass
* self
)
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
)
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
;
758 CONNLOCK_RELEASE(self
);
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
)
772 const char *sockerrmsg
;
774 mylog("enter CC_create_errormsg\n");
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
;
788 CC_set_error(ConnectionClass
* self
, int number
, const char *message
,
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
;
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
)
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");
848 static void CC_clear_cursors(ConnectionClass
* self
, BOOL on_abort
)
851 StatementClass
*stmt
;
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
867 * all non-permanent cursors are automatically closed
870 QR_set_cursor(res
, NULL
);
871 else if (!QR_is_permanent(res
))
876 snprintf(cmd
, sizeof(cmd
), "MOVE 0 in \"%s\"",
878 CONNLOCK_RELEASE(self
);
880 CC_send_query(self
, cmd
, NULL
,
882 IGNORE_ABORT_ON_CONN
, NULL
);
883 if (QR_command_maybe_successful(wres
))
884 QR_set_permanent(res
);
886 QR_set_cursor(res
, NULL
);
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)
904 while (*query
&& !isspace(*query
))
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
);
936 static char CC_setenv(ConnectionClass
* self
)
939 StatementClass
*stmt
;
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
))
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 */
961 PGAPI_ExecDirect(hstmt
, (const UCHAR
*)"set DateStyle to 'ISO'",
963 if (!SQL_SUCCEEDED(result
))
966 mylog("%s: result %d, status %d from set DateStyle\n", func
, result
,
969 /* extra_float_digits (applicable since 7.4) */
970 if (PG_VERSION_GT(self
, 7.3))
973 PGAPI_ExecDirect(hstmt
,
974 (const UCHAR
*)"set extra_float_digits to 2",
976 if (!SQL_SUCCEEDED(result
))
979 mylog("%s: result %d, status %d from set extra_float_digits\n",
980 func
, result
, status
);
984 PGAPI_FreeStmt(hstmt
, SQL_DROP
);
989 char CC_send_settings(ConnectionClass
* self
)
992 StatementClass
*stmt
;
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
))
1011 stmt
= (StatementClass
*) hstmt
;
1013 stmt
->internal
= TRUE
; /* ensure no BEGIN/COMMIT/ABORT stuff */
1015 PGAPI_FreeStmt(hstmt
, SQL_DROP
);
1022 * This function initializes the version of PostgreSQL from
1023 * connInfo.protocol that we're connected to.
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;
1046 self
->pg_version_number
= (float) 7.4;
1047 self
->pg_version_major
= 7;
1048 self
->pg_version_minor
= 4;
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)")
1062 qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",
1063 func
, desc
, self
->__error_number
,
1064 nullcheck(self
->__error_message
));
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
);
1074 qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n",
1076 mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n",
1079 #undef PRN_NULLCHECK
1082 int CC_get_max_query_len(const ConnectionClass
* conn
)
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
);
1093 /* Prior to 6.5 we used BLCKSZ */
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
)
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));
1123 return (const char *) conn
->current_schema
;
1126 int CC_mark_a_object_to_discard(ConnectionClass
* conn
, int type
,
1129 int cnt
= conn
->num_discardp
+ 1;
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
;
1144 int CC_discard_marked_objects(ConnectionClass
* conn
)
1148 char *pname
, cmd
[64];
1150 if ((cnt
= conn
->num_discardp
) <= 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);
1158 snprintf(cmd
, sizeof(cmd
), "CLOSE \"%s\"", pname
+ 1);
1160 CC_send_query(conn
, cmd
, NULL
,
1161 ROLLBACK_ON_ERROR
| IGNORE_ABORT_ON_CONN
,
1164 free(conn
->discardp
[i
]);
1165 conn
->num_discardp
--;
1171 const char *CurrCat(const ConnectionClass
* conn
)
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
;