connection.c
来自「postgresql-odbc,跨平台应用」· C语言 代码 · 共 2,634 行 · 第 1/5 页
C
2,634 行
/*------ * Module: connection.c * * Description: This module contains routines related to * connecting to and disconnecting from the Postgres DBMS. * * Classes: ConnectionClass (Functions prefix: "CC_") * * API functions: SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect, * SQLBrowseConnect(NI) * * Comments: See "notice.txt" for copyright and license information. *------- *//* Multibyte support Eiji Tokuya 2001-03-15 */#include <libpq-fe.h>#include "connection.h"#include <stdio.h>#include <string.h>#include <ctype.h>#ifndef WIN32#include <errno.h>#endif /* WIN32 */#include "environ.h"#include "socket.h"#include "statement.h"#include "qresult.h"#include "lobj.h"#include "dlg_specific.h"#include "loadlib.h"#include "multibyte.h"#include "pgapifunc.h"#include "md5.h"#define STMT_INCREMENT 16 /* how many statement holders to allocate * at a time */#define PRN_NULLCHECKstatic void CC_lookup_pg_version(ConnectionClass *self);static void CC_lookup_lo(ConnectionClass *self);static char *CC_create_errormsg(ConnectionClass *self);extern GLOBAL_VALUES globals;RETCODE SQL_APIPGAPI_AllocConnect( HENV henv, HDBC FAR * phdbc){ EnvironmentClass *env = (EnvironmentClass *) henv; ConnectionClass *conn; CSTR func = "PGAPI_AllocConnect"; mylog("%s: entering...\n", func); conn = CC_Constructor(); mylog("**** %s: henv = %p, conn = %p\n", func, henv, conn); if (!conn) { env->errormsg = "Couldn't allocate memory for Connection object."; env->errornumber = ENV_ALLOC_ERROR; *phdbc = SQL_NULL_HDBC; EN_log_error(func, "", env); return SQL_ERROR; } if (!EN_add_connection(env, conn)) { env->errormsg = "Maximum number of connections exceeded."; env->errornumber = ENV_ALLOC_ERROR; CC_Destructor(conn); *phdbc = SQL_NULL_HDBC; EN_log_error(func, "", env); return SQL_ERROR; } if (phdbc) *phdbc = (HDBC) conn; return SQL_SUCCESS;}RETCODE SQL_APIPGAPI_Connect( HDBC hdbc, const SQLCHAR FAR * szDSN, SQLSMALLINT cbDSN, const SQLCHAR FAR * szUID, SQLSMALLINT cbUID, const SQLCHAR FAR * szAuthStr, SQLSMALLINT cbAuthStr){ ConnectionClass *conn = (ConnectionClass *) hdbc; ConnInfo *ci; CSTR func = "PGAPI_Connect"; RETCODE ret = SQL_SUCCESS; char fchar; mylog("%s: entering..cbDSN=%hi.\n", func, cbDSN); if (!conn) { CC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } ci = &conn->connInfo; make_string(szDSN, cbDSN, ci->dsn, sizeof(ci->dsn)); /* get the values for the DSN from the registry */ memcpy(&ci->drivers, &globals, sizeof(globals)); getDSNinfo(ci, CONN_OVERWRITE); logs_on_off(1, ci->drivers.debug, ci->drivers.commlog); /* initialize pg_version from connInfo.protocol */ CC_initialize_pg_version(conn); /* * override values from DSN info with UID and authStr(pwd) This only * occurs if the values are actually there. */ fchar = ci->username[0]; /* save the first byte */ make_string(szUID, cbUID, ci->username, sizeof(ci->username)); if ('\0' == ci->username[0]) /* an empty string is specified */ ci->username[0] = fchar; /* restore the original username */ fchar = ci->password[0]; make_string(szAuthStr, cbAuthStr, ci->password, sizeof(ci->password)); if ('\0' == ci->password[0]) /* an empty string is specified */ ci->password[0] = fchar; /* restore the original password */ /* fill in any defaults */ getDSNdefaults(ci); qlog("conn = %p, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password ? "xxxxx" : ""); if (CC_connect(conn, AUTH_REQ_OK, NULL) <= 0) { /* Error messages are filled in */ CC_log_error(func, "Error on CC_connect", conn); ret = SQL_ERROR; } mylog("%s: returning..%d.\n", func, ret); return ret;}RETCODE SQL_APIPGAPI_BrowseConnect( HDBC hdbc, const SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut){ CSTR func = "PGAPI_BrowseConnect"; ConnectionClass *conn = (ConnectionClass *) hdbc; mylog("%s: entering...\n", func); CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Function not implemented", func); return SQL_ERROR;}/* Drop any hstmts open on hdbc and disconnect from database */RETCODE SQL_APIPGAPI_Disconnect( HDBC hdbc){ ConnectionClass *conn = (ConnectionClass *) hdbc; CSTR func = "PGAPI_Disconnect"; mylog("%s: entering...\n", func); if (!conn) { CC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } qlog("conn=%p, %s\n", conn, func); if (conn->status == CONN_EXECUTING) { CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func); return SQL_ERROR; } logs_on_off(-1, conn->connInfo.drivers.debug, conn->connInfo.drivers.commlog); mylog("%s: about to CC_cleanup\n", func); /* Close the connection and free statements */ CC_cleanup(conn); mylog("%s: done CC_cleanup\n", func); mylog("%s: returning...\n", func); return SQL_SUCCESS;}RETCODE SQL_APIPGAPI_FreeConnect( HDBC hdbc){ ConnectionClass *conn = (ConnectionClass *) hdbc; CSTR func = "PGAPI_FreeConnect"; mylog("%s: entering...\n", func); mylog("**** in %s: hdbc=%p\n", func, hdbc); if (!conn) { CC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } /* Remove the connection from the environment */ if (!EN_remove_connection(conn->henv, conn)) { CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func); return SQL_ERROR; } CC_Destructor(conn); mylog("%s: returning...\n", func); return SQL_SUCCESS;}static voidCC_globals_init(GLOBAL_VALUES *globs){ memset(globs, 0, sizeof(GLOBAL_VALUES)); globs->fetch_max = -1001; globs->socket_buffersize = -1001; globs->unknown_sizes = -1; globs->max_varchar_size = -1001; globs->max_longvarchar_size = -1001; globs->debug = -1; globs->commlog = -1; globs->disable_optimizer = -1; globs->ksqo = -1; globs->unique_index = -1; globs->onlyread = -1; globs->use_declarefetch = -1; globs->text_as_longvarchar = -1; globs->unknowns_as_longvarchar = -1; globs->bools_as_char = -1; globs->lie = -1; globs->parse = -1; globs->cancel_as_freestmt = -1;}voidCC_conninfo_init(ConnInfo *conninfo){ memset(conninfo, 0, sizeof(ConnInfo)); conninfo->disallow_premature = -1; conninfo->allow_keyset = -1; conninfo->lf_conversion = -1; conninfo->true_is_minus1 = -1; conninfo->int8_as = -101; conninfo->bytea_as_longvarbinary = -1; conninfo->use_server_side_prepare = -1; conninfo->lower_case_identifier = -1; conninfo->rollback_on_error = -1; conninfo->force_abbrev_connstr = -1; conninfo->bde_environment = -1; conninfo->fake_mss = -1; conninfo->cvt_null_date_string = -1; conninfo->autocommit_public = SQL_AUTOCOMMIT_ON; conninfo->accessible_only = -1;#ifdef _HANDLE_ENLIST_IN_DTC_ conninfo->xa_opt = -1;#endif /* _HANDLE_ENLIST_IN_DTC_ */ memcpy(&(conninfo->drivers), &globals, sizeof(globals));}#ifdef WIN32extern int platformId;#endif /* WIN32 *//* * IMPLEMENTATION CONNECTION CLASS */static voidreset_current_schema(ConnectionClass *self){ if (self->current_schema) { free(self->current_schema); self->current_schema = NULL; }}ConnectionClass *CC_Constructor(){ extern int exepgm; ConnectionClass *rv, *retrv = NULL; rv = (ConnectionClass *) calloc(sizeof(ConnectionClass), 1); if (rv != NULL) { // rv->henv = NULL; /* not yet associated with an environment */ // rv->__error_message = NULL; // rv->__error_number = 0; // rv->sqlstate[0] = '\0'; // rv->errormsg_created = FALSE; rv->status = CONN_NOT_CONNECTED; rv->transact_status = CONN_IN_AUTOCOMMIT; /* autocommit by default */ CC_conninfo_init(&(rv->connInfo)); rv->sock = SOCK_Constructor(rv); if (!rv->sock) goto cleanup; rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT); if (!rv->stmts) goto cleanup; memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT); rv->num_stmts = STMT_INCREMENT;#if (ODBCVER >= 0x0300) rv->descs = (DescriptorClass **) malloc(sizeof(DescriptorClass *) * STMT_INCREMENT); if (!rv->descs) goto cleanup; memset(rv->descs, 0, sizeof(DescriptorClass *) * STMT_INCREMENT); rv->num_descs = STMT_INCREMENT;#endif /* ODBCVER */ rv->lobj_type = PG_TYPE_LO_UNDEFINED; // rv->ncursors = 0; // rv->ntables = 0; // rv->col_info = NULL; // rv->translation_option = 0; // rv->translation_handle = NULL; // rv->DataSourceToDriver = NULL; // rv->DriverToDataSource = NULL; rv->driver_version = ODBCVER;#ifdef WIN32 if (VER_PLATFORM_WIN32_WINDOWS == platformId && rv->driver_version > 0x0300) rv->driver_version = 0x0300;#endif /* WIN32 */ // memset(rv->pg_version, 0, sizeof(rv->pg_version)); // rv->pg_version_number = .0; // rv->pg_version_major = 0; // rv->pg_version_minor = 0; // rv->ms_jet = 0; if (1 == exepgm) rv->ms_jet = 1; // rv->unicode = 0; // rv->result_uncommitted = 0; // rv->schema_support = 0; rv->isolation = SQL_TXN_READ_COMMITTED; // rv->original_client_encoding = NULL; // rv->current_client_encoding = NULL; // rv->server_encoding = NULL; // rv->current_schema = NULL; // rv->num_discardp = 0; // rv->discardp = NULL; rv->mb_maxbyte_per_char = 1; rv->max_identifier_length = -1; rv->escape_in_literal = ESCAPE_IN_LITERAL; /* Initialize statement options to defaults */ /* Statements under this conn will inherit these options */ InitializeStatementOptions(&rv->stmtOptions); InitializeARDFields(&rv->ardOptions); InitializeAPDFields(&rv->apdOptions);#ifdef _HANDLE_ENLIST_IN_DTC_ // rv->asdum = NULL;#endif /* _HANDLE_ENLIST_IN_DTC_ */ INIT_CONNLOCK(rv); INIT_CONN_CS(rv); retrv = rv; }cleanup: if (rv && !retrv) CC_Destructor(rv); return retrv;}charCC_Destructor(ConnectionClass *self){ mylog("enter CC_Destructor, self=%p\n", self); if (self->status == CONN_EXECUTING) return 0; CC_cleanup(self); /* cleanup socket and statements */ mylog("after CC_Cleanup\n"); /* Free up statement holders */ if (self->stmts) { free(self->stmts); self->stmts = NULL; }#if (ODBCVER >= 0x0300) if (self->descs) { free(self->descs); self->descs = NULL; }#endif /* ODBCVER */ mylog("after free statement holders\n"); NULL_THE_NAME(self->schemaIns); NULL_THE_NAME(self->tableIns); if (self->__error_message) free(self->__error_message); DELETE_CONN_CS(self); DELETE_CONNLOCK(self); free(self); mylog("exit CC_Destructor\n"); return 1;}/* Return how many cursors are opened on this connection */intCC_cursor_count(ConnectionClass *self){ StatementClass *stmt; int i, count = 0; QResultClass *res; mylog("CC_cursor_count: self=%p, num_stmts=%d\n", self, self->num_stmts); CONNLOCK_ACQUIRE(self); for (i = 0; i < self->num_stmts; i++) { stmt = self->stmts[i]; if (stmt && (res = SC_get_Result(stmt)) && QR_get_cursor(res)) count++; } CONNLOCK_RELEASE(self); mylog("CC_cursor_count: returning %d\n", count); return count;}voidCC_clear_error(ConnectionClass *self){ if (!self) return; CONNLOCK_ACQUIRE(self); self->__error_number = 0; if (self->__error_message) { free(self->__error_message); self->__error_message = NULL; } self->sqlstate[0] = '\0'; self->errormsg_created = FALSE; CONNLOCK_RELEASE(self);}CSTR bgncmd = "BEGIN";CSTR rbkcmd = "ROLLBACK";CSTR semi_colon = ";";/* * Used to begin a transaction. */charCC_begin(ConnectionClass *self){ char ret = TRUE; if (!CC_is_in_trans(self)) { QResultClass *res = CC_send_query(self, bgncmd, NULL, 0, NULL); mylog("CC_begin: sending BEGIN!\n"); ret = QR_command_maybe_successful(res); QR_Destructor(res); } return ret;}/* * Used to commit a transaction. * We are almost always in the middle of a transaction. */charCC_commit(ConnectionClass *self){ char ret = TRUE; if (CC_is_in_trans(self)) { QResultClass *res = CC_send_query(self, "COMMIT", NULL, 0, NULL);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?