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 + -
显示快捷键?