<commit_before>/*-------
 * Module:			environ.c
 *
 * Description:		This module contains routines related to
 *					the environment, such as storing connection handles,
 *					and returning errors.
 *
 * Classes:			EnvironmentClass (Functions prefix: "EN_")
 *
 * API functions:	SQLAllocEnv, SQLFreeEnv, SQLError
 *
 * Comments:		See "notice.txt" for copyright and license information.
 *-------
 */

#include "environ.h"

#include "connection.h"
#include "dlg_specific.h"
#include "statement.h"
#include <stdlib.h>
#include <string.h>
#include "pgapifunc.h"
#ifdef	WIN32
#ifndef	_WSASTARTUP_IN_DLLMAIN_
#include <winsock2.h>
#endif /* _WSASTARTUP_IN_DLLMAIN_ */
#endif /* WIN32 */
#include "loadlib.h"

extern GLOBAL_VALUES globals;

/* The one instance of the handles */
ConnectionClass *conns[MAX_CONNECTIONS];
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION	conns_cs;
CRITICAL_SECTION	common_cs; /* commonly used for short term blocking */
#elif defined(POSIX_MULTITHREAD_SUPPORT)
pthread_mutex_t     conns_cs;
pthread_mutex_t     common_cs;
#endif /* WIN_MULTITHREAD_SUPPORT */


RETCODE		SQL_API
PGAPI_AllocEnv(HENV FAR * phenv)
{
	CSTR func = "PGAPI_AllocEnv";
	SQLRETURN	ret = SQL_SUCCESS;

	mylog("**** in %s ** \n", func);

	/*
	 * Hack for systems on which none of the constructor-making techniques
	 * in psqlodbc.c work: if globals appears not to have been
	 * initialized, then cause it to be initialized.  Since this should be
	 * the first function called in this shared library, doing it here
	 * should work.
	 */
	if (globals.socket_buffersize <= 0)
	{
		initialize_global_cs();
		getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
	}

	*phenv = (HENV) EN_Constructor();
	if (!*phenv)
	{
		*phenv = SQL_NULL_HENV;
		EN_log_error(func, "Error allocating environment", NULL);
		ret = SQL_ERROR;
	}

	mylog("** exit %s: phenv = %p **\n", func, *phenv);
	return ret;
}


RETCODE		SQL_API
PGAPI_FreeEnv(HENV henv)
{
	CSTR func = "PGAPI_FreeEnv";
	SQLRETURN	ret = SQL_SUCCESS;
	EnvironmentClass *env = (EnvironmentClass *) henv;

	mylog("**** in PGAPI_FreeEnv: env = %p ** \n", env);

	if (env && EN_Destructor(env))
	{
#ifdef	_HANDLE_ENLIST_IN_DTC_
		CALL_DtcOnRelease();
#endif /* _HANDLE_ENLIST_IN_DTC_ */
		mylog("   ok\n");
		goto cleanup;
	}

	mylog("    error\n");
	ret = SQL_ERROR;
cleanup:
	EN_log_error(func, "Error freeing environment", env);
	return ret;
}


static void
pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver3str, const UCHAR *ver2str)
{
	strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str);
}

PG_ErrorInfo	*ER_Constructor(SDWORD errnumber, const char *msg)
{
	PG_ErrorInfo	*error;
	ssize_t		aladd, errsize;

	if (DESC_OK == errnumber)
		return NULL;
	if (msg)
	{
		errsize = strlen(msg);
		aladd = errsize;
	}
	else
	{
		errsize = -1;
		aladd = 0;
	}
	error = (PG_ErrorInfo *) malloc(sizeof(PG_ErrorInfo) + aladd);
	if (error)
	{
		memset(error, 0, sizeof(PG_ErrorInfo));
		error->status = errnumber;
		error->errorsize = (Int4) errsize;
		if (errsize > 0)
			memcpy(error->__error_message, msg, errsize);
		error->__error_message[aladd] = '\0';
        	error->recsize = -1;
	}
	return error;
}

void
ER_Destructor(PG_ErrorInfo *self)
{
	free(self);
}

PG_ErrorInfo *ER_Dup(const PG_ErrorInfo *self)
{
	PG_ErrorInfo	*new;
	Int4		alsize;

	if (!self)
		return NULL;
	alsize = sizeof(PG_ErrorInfo);
	if (self->errorsize  > 0)
		alsize += self->errorsize;
	new = (PG_ErrorInfo *) malloc(alsize);
	memcpy(new, self, alsize);

	return new;
}

#define	DRVMNGRDIV	511
/*		Returns the next SQL error information. */
RETCODE		SQL_API
ER_ReturnError(PG_ErrorInfo **pgerror,
		SQLSMALLINT	RecNumber,
		SQLCHAR FAR * szSqlState,
		SQLINTEGER FAR * pfNativeError,
		SQLCHAR FAR * szErrorMsg,
		SQLSMALLINT cbErrorMsgMax,
		SQLSMALLINT FAR * pcbErrorMsg,
		UWORD flag)
{
	CSTR func = "ER_ReturnError";
	/* CC: return an error of a hstmt  */
	PG_ErrorInfo	*error;
	BOOL		partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
			clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
	const char	*msg;
	SWORD		msglen, stapos, wrtlen, pcblen;

	if (!pgerror || !*pgerror)
		return SQL_NO_DATA_FOUND;
	error = *pgerror;
	msg = error->__error_message;
	mylog("%s: status = %d, msg = #%s#\n", func, error->status, msg);
	msglen = (SQLSMALLINT) strlen(msg);
	/*
	 *	Even though an application specifies a larger error message
	 *	buffer, the driver manager changes it silently.
	 *	Therefore we divide the error message into ... 
	 */
	if (error->recsize < 0)
	{
		if (cbErrorMsgMax > 0)
			error->recsize = cbErrorMsgMax - 1; /* apply the first request */
		else
			error->recsize = DRVMNGRDIV;
	}
	if (RecNumber < 0)
	{
		if (0 == error->errorpos)
			RecNumber = 1;
		else
			RecNumber = 2 + (error->errorpos - 1) / error->recsize;
	}
	stapos = (RecNumber - 1) * error->recsize;
	if (stapos > msglen)
		return SQL_NO_DATA_FOUND; 
	pcblen = wrtlen = msglen - stapos;
	if (pcblen > error->recsize)
		pcblen = error->recsize;
	if (0 == cbErrorMsgMax)
		wrtlen = 0; 
	else if (wrtlen >= cbErrorMsgMax)
	{
		if (partial_ok)
			wrtlen = cbErrorMsgMax - 1;
		else if (cbErrorMsgMax <= error->recsize)
			wrtlen = 0;
		else 
			wrtlen = error->recsize;
	}
	if (wrtlen > pcblen)
		wrtlen = pcblen;
	if (NULL != pcbErrorMsg)
		*pcbErrorMsg = pcblen;

	if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
	{
		memcpy(szErrorMsg, msg + stapos, wrtlen);
		szErrorMsg[wrtlen] = '\0';
	}

	if (NULL != pfNativeError)
		*pfNativeError = error->status;

	if (NULL != szSqlState)
		strncpy(szSqlState, error->sqlstate, 6);

	mylog("	     szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
	if (clear_str)
	{
		error->errorpos = stapos + wrtlen;
		if (error->errorpos >= msglen)
		{
			ER_Destructor(error);
			*pgerror = NULL;
		}
	}
	if (wrtlen == 0)
		return SQL_SUCCESS_WITH_INFO;
	else
		return SQL_SUCCESS;
}


RETCODE		SQL_API
PGAPI_ConnectError(	HDBC hdbc,
			SQLSMALLINT	RecNumber,
			SQLCHAR FAR * szSqlState,
			SQLINTEGER FAR * pfNativeError,
			SQLCHAR FAR * szErrorMsg,
			SQLSMALLINT cbErrorMsgMax,
			SQLSMALLINT FAR * pcbErrorMsg,
			UWORD flag)
{
	ConnectionClass *conn = (ConnectionClass *) hdbc;
	EnvironmentClass *env = (EnvironmentClass *) conn->henv;
	char		*msg;
	int		status;
	BOOL	once_again = FALSE;
	ssize_t		msglen;

	mylog("**** PGAPI_ConnectError: hdbc=%p <%d>\n", hdbc, cbErrorMsgMax);
	if (RecNumber != 1 && RecNumber != -1)
		return SQL_NO_DATA_FOUND;
	if (cbErrorMsgMax < 0)
		return SQL_ERROR;
	if (CONN_EXECUTING == conn->status || !CC_get_error(conn, &status, &msg) || NULL == msg)
	{
		mylog("CC_Get_error returned nothing.\n");
		if (NULL != szSqlState)
			strcpy(szSqlState, "00000");
		if (NULL != pcbErrorMsg)
			*pcbErrorMsg = 0;
		if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
			szErrorMsg[0] = '\0';

		return SQL_NO_DATA_FOUND;
	}
	mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);

	msglen = strlen(msg);
	if (NULL != pcbErrorMsg)
	{
		*pcbErrorMsg = (SQLSMALLINT) msglen;
		if (cbErrorMsgMax == 0)
			once_again = TRUE;
		else if (msglen >= cbErrorMsgMax)
			*pcbErrorMsg = cbErrorMsgMax - 1;
	}
	if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
		strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
	if (NULL != pfNativeError)
		*pfNativeError = status;

	if (NULL != szSqlState)
	{
		if (conn->sqlstate[0])
			strcpy(szSqlState, conn->sqlstate);
		else	
		switch (status)
		{
			case CONN_OPTION_VALUE_CHANGED:
				pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
				break;
			case CONN_TRUNCATED:
				pg_sqlstate_set(env, szSqlState, "01004", "01004");
				/* data truncated */
				break;
			case CONN_INIREAD_ERROR:
				pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
				/* data source not found */
				break;
			case CONNECTION_SERVER_NOT_REACHED:
			case CONN_OPENDB_ERROR:
				pg_sqlstate_set(env, szSqlState, "08001", "08001");
				/* unable to connect to data source */
				break;
			case CONN_INVALID_AUTHENTICATION:
			case CONN_AUTH_TYPE_UNSUPPORTED:
				pg_sqlstate_set(env, szSqlState, "28000", "28000");
				break;
			case CONN_STMT_ALLOC_ERROR:
				pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
				/* memory allocation failure */
				break;
			case CONN_IN_USE:
				pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
				/* general error */
				break;
			case CONN_UNSUPPORTED_OPTION:
				pg_sqlstate_set(env, szSqlState, "HYC00", "IM001");
				/* driver does not support this function */
				break;
			case CONN_INVALID_ARGUMENT_NO:
				pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
				/* invalid argument value */
				break;
			case CONN_TRANSACT_IN_PROGRES:
				pg_sqlstate_set(env, szSqlState, "HY010", "S1010");

				/*
				 * when the user tries to switch commit mode in a
				 * transaction
				 */
				/* -> function sequence error */
				break;
			case CONN_NO_MEMORY_ERROR:
				pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
				break;
			case CONN_NOT_IMPLEMENTED_ERROR:
				pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
				break;
			case CONN_VALUE_OUT_OF_RANGE:
				pg_sqlstate_set(env, szSqlState, "HY019", "22003");
				break;
			case CONNECTION_COULD_NOT_SEND:
			case CONNECTION_COULD_NOT_RECEIVE:
			case CONNECTION_COMMUNICATION_ERROR:
				pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
				break;
			default:
				pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
				/* general error */
				break;
		}
	}

	mylog("	     szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, msglen, szErrorMsg);
	if (once_again)
	{
		CC_set_errornumber(conn, status);
		return SQL_SUCCESS_WITH_INFO;
	}
	else
		return SQL_SUCCESS;
}

RETCODE		SQL_API
PGAPI_EnvError(		HENV henv,
			SQLSMALLINT	RecNumber,
			SQLCHAR FAR * szSqlState,
			SQLINTEGER FAR * pfNativeError,
			SQLCHAR FAR * szErrorMsg,
			SQLSMALLINT cbErrorMsgMax,
			SQLSMALLINT FAR * pcbErrorMsg,
			UWORD flag)
{
	EnvironmentClass *env = (EnvironmentClass *) henv;
	char		*msg;
	int		status;

	mylog("**** PGAPI_EnvError: henv=%p <%d>\n", henv, cbErrorMsgMax);
	if (RecNumber != 1 && RecNumber != -1)
		return SQL_NO_DATA_FOUND;
	if (cbErrorMsgMax < 0)
		return SQL_ERROR;
	if (!EN_get_error(env, &status, &msg) || NULL == msg)
	{
			mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
		
		if (NULL != szSqlState)
			pg_sqlstate_set(env, szSqlState, "00000", "00000");
		if (NULL != pcbErrorMsg)
			*pcbErrorMsg = 0;
		if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
			szErrorMsg[0] = '\0';

		return SQL_NO_DATA_FOUND;
	}
	mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);

	if (NULL != pcbErrorMsg)
		*pcbErrorMsg = (SQLSMALLINT) strlen(msg);
	if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
		strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
	if (NULL != pfNativeError)
		*pfNativeError = status;

	if (szSqlState)
	{
		switch (status)
		{
			case ENV_ALLOC_ERROR:
				/* memory allocation failure */
				pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
				break;
			default:
				pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
				/* general error */
				break;
		}
	}

	return SQL_SUCCESS;
}


/*		Returns the next SQL error information. */
RETCODE		SQL_API
PGAPI_Error(
			HENV henv,
			HDBC hdbc,
			HSTMT hstmt,
			SQLCHAR FAR * szSqlState,
			SQLINTEGER FAR * pfNativeError,
			SQLCHAR FAR * szErrorMsg,
			SQLSMALLINT cbErrorMsgMax,
			SQLSMALLINT FAR * pcbErrorMsg)
{
	RETCODE	ret;
	UWORD	flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR;

	mylog("**** PGAPI_Error: henv=%p, hdbc=%p hstmt=%d\n", henv, hdbc, hstmt);

	if (cbErrorMsgMax < 0)
		return SQL_ERROR;
	if (SQL_NULL_HSTMT != hstmt)
		ret = PGAPI_StmtError(hstmt, -1, szSqlState, pfNativeError,
			 szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
	else if (SQL_NULL_HDBC != hdbc)
		ret = PGAPI_ConnectError(hdbc, -1, szSqlState, pfNativeError,
			 szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
	else if (SQL_NULL_HENV != henv)
		ret = PGAPI_EnvError(henv, -1, szSqlState, pfNativeError,
			 szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
	else
	{
		if (NULL != szSqlState)
			strcpy(szSqlState, "00000");
		if (NULL != pcbErrorMsg)
			*pcbErrorMsg = 0;
		if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
			szErrorMsg[0] = '\0';

		ret = SQL_NO_DATA_FOUND;
	}
	mylog("**** PGAPI_Error exit code=%d\n", ret);
	return ret;
}

/*
 * EnvironmentClass implementation
 */
EnvironmentClass *
EN_Constructor(void)
{
	CSTR	func = "EN_Constructor";
	EnvironmentClass *rv = NULL;
#ifndef	_WSASTARTUP_IN_DLLMAIN_
	WORD		wVersionRequested;
	WSADATA		wsaData;

	/* Load the WinSock Library */
	wVersionRequested = MAKEWORD(1, 1);

	if (WSAStartup(wVersionRequested, &wsaData))
		return rv;
	/* Verify that this is the minimum version of WinSock */
	if (LOBYTE(wsaData.wVersion) != 1 ||
	    HIBYTE(wsaData.wVersion) != 1)
	{
		goto cleanup;
	}
#endif /* _WSASTARTUP_IN_DLLMAIN_ */

	rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass));
cleanup:
	if (rv)
	{<commit_msg>wsaData evades with *nix.<commit_after>/*-------
 * Module:			environ.c
 *
 * Description:		This module contains routines related to
 *					the environment, such as storing connection handles,
 *					and returning errors.
 *
 * Classes:			EnvironmentClass (Functions prefix: "EN_")
 *
 * API functions:	SQLAllocEnv, SQLFreeEnv, SQLError
 *
 * Comments:		See "notice.txt" for copyright and license information.
 *-------
 */

#include "environ.h"

#include "connection.h"
#include "dlg_specific.h"
#include "statement.h"
#include <stdlib.h>
#include <string.h>
#include "pgapifunc.h"
#ifdef	WIN32
#ifndef	_WSASTARTUP_IN_DLLMAIN_
#include <winsock2.h>
#endif /* _WSASTARTUP_IN_DLLMAIN_ */
#endif /* WIN32 */
#include "loadlib.h"

extern GLOBAL_VALUES globals;

/* The one instance of the handles */
ConnectionClass *conns[MAX_CONNECTIONS];
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION	conns_cs;
CRITICAL_SECTION	common_cs; /* commonly used for short term blocking */
#elif defined(POSIX_MULTITHREAD_SUPPORT)
pthread_mutex_t     conns_cs;
pthread_mutex_t     common_cs;
#endif /* WIN_MULTITHREAD_SUPPORT */


RETCODE		SQL_API
PGAPI_AllocEnv(HENV FAR * phenv)
{
	CSTR func = "PGAPI_AllocEnv";
	SQLRETURN	ret = SQL_SUCCESS;

	mylog("**** in %s ** \n", func);

	/*
	 * Hack for systems on which none of the constructor-making techniques
	 * in psqlodbc.c work: if globals appears not to have been
	 * initialized, then cause it to be initialized.  Since this should be
	 * the first function called in this shared library, doing it here
	 * should work.
	 */
	if (globals.socket_buffersize <= 0)
	{
		initialize_global_cs();
		getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
	}

	*phenv = (HENV) EN_Constructor();
	if (!*phenv)
	{
		*phenv = SQL_NULL_HENV;
		EN_log_error(func, "Error allocating environment", NULL);
		ret = SQL_ERROR;
	}

	mylog("** exit %s: phenv = %p **\n", func, *phenv);
	return ret;
}


RETCODE		SQL_API
PGAPI_FreeEnv(HENV henv)
{
	CSTR func = "PGAPI_FreeEnv";
	SQLRETURN	ret = SQL_SUCCESS;
	EnvironmentClass *env = (EnvironmentClass *) henv;

	mylog("**** in PGAPI_FreeEnv: env = %p ** \n", env);

	if (env && EN_Destructor(env))
	{
#ifdef	_HANDLE_ENLIST_IN_DTC_
		CALL_DtcOnRelease();
#endif /* _HANDLE_ENLIST_IN_DTC_ */
		mylog("   ok\n");
		goto cleanup;
	}

	mylog("    error\n");
	ret = SQL_ERROR;
cleanup:
	EN_log_error(func, "Error freeing environment", env);
	return ret;
}


static void
pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver3str, const UCHAR *ver2str)
{
	strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str);
}

PG_ErrorInfo	*ER_Constructor(SDWORD errnumber, const char *msg)
{
	PG_ErrorInfo	*error;
	ssize_t		aladd, errsize;

	if (DESC_OK == errnumber)
		return NULL;
	if (msg)
	{
		errsize = strlen(msg);
		aladd = errsize;
	}
	else
	{
		errsize = -1;
		aladd = 0;
	}
	error = (PG_ErrorInfo *) malloc(sizeof(PG_ErrorInfo) + aladd);
	if (error)
	{
		memset(error, 0, sizeof(PG_ErrorInfo));
		error->status = errnumber;
		error->errorsize = (Int4) errsize;
		if (errsize > 0)
			memcpy(error->__error_message, msg, errsize);
		error->__error_message[aladd] = '\0';
        	error->recsize = -1;
	}
	return error;
}

void
ER_Destructor(PG_ErrorInfo *self)
{
	free(self);
}

PG_ErrorInfo *ER_Dup(const PG_ErrorInfo *self)
{
	PG_ErrorInfo	*new;
	Int4		alsize;

	if (!self)
		return NULL;
	alsize = sizeof(PG_ErrorInfo);
	if (self->errorsize  > 0)
		alsize += self->errorsize;
	new = (PG_ErrorInfo *) malloc(alsize);
	memcpy(new, self, alsize);

	return new;
}

#define	DRVMNGRDIV	511
/*		Returns the next SQL error information. */
RETCODE		SQL_API
ER_ReturnError(PG_ErrorInfo **pgerror,
		SQLSMALLINT	RecNumber,
		SQLCHAR FAR * szSqlState,
		SQLINTEGER FAR * pfNativeError,
		SQLCHAR FAR * szErrorMsg,
		SQLSMALLINT cbErrorMsgMax,
		SQLSMALLINT FAR * pcbErrorMsg,
		UWORD flag)
{
	CSTR func = "ER_ReturnError";
	/* CC: return an error of a hstmt  */
	PG_ErrorInfo	*error;
	BOOL		partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
			clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
	const char	*msg;
	SWORD		msglen, stapos, wrtlen, pcblen;

	if (!pgerror || !*pgerror)
		return SQL_NO_DATA_FOUND;
	error = *pgerror;
	msg = error->__error_message;
	mylog("%s: status = %d, msg = #%s#\n", func, error->status, msg);
	msglen = (SQLSMALLINT) strlen(msg);
	/*
	 *	Even though an application specifies a larger error message
	 *	buffer, the driver manager changes it silently.
	 *	Therefore we divide the error message into ... 
	 */
	if (error->recsize < 0)
	{
		if (cbErrorMsgMax > 0)
			error->recsize = cbErrorMsgMax - 1; /* apply the first request */
		else
			error->recsize = DRVMNGRDIV;
	}
	if (RecNumber < 0)
	{
		if (0 == error->errorpos)
			RecNumber = 1;
		else
			RecNumber = 2 + (error->errorpos - 1) / error->recsize;
	}
	stapos = (RecNumber - 1) * error->recsize;
	if (stapos > msglen)
		return SQL_NO_DATA_FOUND; 
	pcblen = wrtlen = msglen - stapos;
	if (pcblen > error->recsize)
		pcblen = error->recsize;
	if (0 == cbErrorMsgMax)
		wrtlen = 0; 
	else if (wrtlen >= cbErrorMsgMax)
	{
		if (partial_ok)
			wrtlen = cbErrorMsgMax - 1;
		else if (cbErrorMsgMax <= error->recsize)
			wrtlen = 0;
		else 
			wrtlen = error->recsize;
	}
	if (wrtlen > pcblen)
		wrtlen = pcblen;
	if (NULL != pcbErrorMsg)
		*pcbErrorMsg = pcblen;

	if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
	{
		memcpy(szErrorMsg, msg + stapos, wrtlen);
		szErrorMsg[wrtlen] = '\0';
	}

	if (NULL != pfNativeError)
		*pfNativeError = error->status;

	if (NULL != szSqlState)
		strncpy(szSqlState, error->sqlstate, 6);

	mylog("	     szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
	if (clear_str)
	{
		error->errorpos = stapos + wrtlen;
		if (error->errorpos >= msglen)
		{
			ER_Destructor(error);
			*pgerror = NULL;
		}
	}
	if (wrtlen == 0)
		return SQL_SUCCESS_WITH_INFO;
	else
		return SQL_SUCCESS;
}


RETCODE		SQL_API
PGAPI_ConnectError(	HDBC hdbc,
			SQLSMALLINT	RecNumber,
			SQLCHAR FAR * szSqlState,
			SQLINTEGER FAR * pfNativeError,
			SQLCHAR FAR * szErrorMsg,
			SQLSMALLINT cbErrorMsgMax,
			SQLSMALLINT FAR * pcbErrorMsg,
			UWORD flag)
{
	ConnectionClass *conn = (ConnectionClass *) hdbc;
	EnvironmentClass *env = (EnvironmentClass *) conn->henv;
	char		*msg;
	int		status;
	BOOL	once_again = FALSE;
	ssize_t		msglen;

	mylog("**** PGAPI_ConnectError: hdbc=%p <%d>\n", hdbc, cbErrorMsgMax);
	if (RecNumber != 1 && RecNumber != -1)
		return SQL_NO_DATA_FOUND;
	if (cbErrorMsgMax < 0)
		return SQL_ERROR;
	if (CONN_EXECUTING == conn->status || !CC_get_error(conn, &status, &msg) || NULL == msg)
	{
		mylog("CC_Get_error returned nothing.\n");
		if (NULL != szSqlState)
			strcpy(szSqlState, "00000");
		if (NULL != pcbErrorMsg)
			*pcbErrorMsg = 0;
		if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
			szErrorMsg[0] = '\0';

		return SQL_NO_DATA_FOUND;
	}
	mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg);

	msglen = strlen(msg);
	if (NULL != pcbErrorMsg)
	{
		*pcbErrorMsg = (SQLSMALLINT) msglen;
		if (cbErrorMsgMax == 0)
			once_again = TRUE;
		else if (msglen >= cbErrorMsgMax)
			*pcbErrorMsg = cbErrorMsgMax - 1;
	}
	if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
		strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
	if (NULL != pfNativeError)
		*pfNativeError = status;

	if (NULL != szSqlState)
	{
		if (conn->sqlstate[0])
			strcpy(szSqlState, conn->sqlstate);
		else	
		switch (status)
		{
			case CONN_OPTION_VALUE_CHANGED:
				pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
				break;
			case CONN_TRUNCATED:
				pg_sqlstate_set(env, szSqlState, "01004", "01004");
				/* data truncated */
				break;
			case CONN_INIREAD_ERROR:
				pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
				/* data source not found */
				break;
			case CONNECTION_SERVER_NOT_REACHED:
			case CONN_OPENDB_ERROR:
				pg_sqlstate_set(env, szSqlState, "08001", "08001");
				/* unable to connect to data source */
				break;
			case CONN_INVALID_AUTHENTICATION:
			case CONN_AUTH_TYPE_UNSUPPORTED:
				pg_sqlstate_set(env, szSqlState, "28000", "28000");
				break;
			case CONN_STMT_ALLOC_ERROR:
				pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
				/* memory allocation failure */
				break;
			case CONN_IN_USE:
				pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
				/* general error */
				break;
			case CONN_UNSUPPORTED_OPTION:
				pg_sqlstate_set(env, szSqlState, "HYC00", "IM001");
				/* driver does not support this function */
				break;
			case CONN_INVALID_ARGUMENT_NO:
				pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
				/* invalid argument value */
				break;
			case CONN_TRANSACT_IN_PROGRES:
				pg_sqlstate_set(env, szSqlState, "HY010", "S1010");

				/*
				 * when the user tries to switch commit mode in a
				 * transaction
				 */
				/* -> function sequence error */
				break;
			case CONN_NO_MEMORY_ERROR:
				pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
				break;
			case CONN_NOT_IMPLEMENTED_ERROR:
				pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
				break;
			case CONN_VALUE_OUT_OF_RANGE:
				pg_sqlstate_set(env, szSqlState, "HY019", "22003");
				break;
			case CONNECTION_COULD_NOT_SEND:
			case CONNECTION_COULD_NOT_RECEIVE:
			case CONNECTION_COMMUNICATION_ERROR:
				pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
				break;
			default:
				pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
				/* general error */
				break;
		}
	}

	mylog("	     szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, msglen, szErrorMsg);
	if (once_again)
	{
		CC_set_errornumber(conn, status);
		return SQL_SUCCESS_WITH_INFO;
	}
	else
		return SQL_SUCCESS;
}

RETCODE		SQL_API
PGAPI_EnvError(		HENV henv,
			SQLSMALLINT	RecNumber,
			SQLCHAR FAR * szSqlState,
			SQLINTEGER FAR * pfNativeError,
			SQLCHAR FAR * szErrorMsg,
			SQLSMALLINT cbErrorMsgMax,
			SQLSMALLINT FAR * pcbErrorMsg,
			UWORD flag)
{
	EnvironmentClass *env = (EnvironmentClass *) henv;
	char		*msg;
	int		status;

	mylog("**** PGAPI_EnvError: henv=%p <%d>\n", henv, cbErrorMsgMax);
	if (RecNumber != 1 && RecNumber != -1)
		return SQL_NO_DATA_FOUND;
	if (cbErrorMsgMax < 0)
		return SQL_ERROR;
	if (!EN_get_error(env, &status, &msg) || NULL == msg)
	{
			mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
		
		if (NULL != szSqlState)
			pg_sqlstate_set(env, szSqlState, "00000", "00000");
		if (NULL != pcbErrorMsg)
			*pcbErrorMsg = 0;
		if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
			szErrorMsg[0] = '\0';

		return SQL_NO_DATA_FOUND;
	}
	mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);

	if (NULL != pcbErrorMsg)
		*pcbErrorMsg = (SQLSMALLINT) strlen(msg);
	if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
		strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
	if (NULL != pfNativeError)
		*pfNativeError = status;

	if (szSqlState)
	{
		switch (status)
		{
			case ENV_ALLOC_ERROR:
				/* memory allocation failure */
				pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
				break;
			default:
				pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
				/* general error */
				break;
		}
	}

	return SQL_SUCCESS;
}


/*		Returns the next SQL error information. */
RETCODE		SQL_API
PGAPI_Error(
			HENV henv,
			HDBC hdbc,
			HSTMT hstmt,
			SQLCHAR FAR * szSqlState,
			SQLINTEGER FAR * pfNativeError,
			SQLCHAR FAR * szErrorMsg,
			SQLSMALLINT cbErrorMsgMax,
			SQLSMALLINT FAR * pcbErrorMsg)
{
	RETCODE	ret;
	UWORD	flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR;

	mylog("**** PGAPI_Error: henv=%p, hdbc=%p hstmt=%d\n", henv, hdbc, hstmt);

	if (cbErrorMsgMax < 0)
		return SQL_ERROR;
	if (SQL_NULL_HSTMT != hstmt)
		ret = PGAPI_StmtError(hstmt, -1, szSqlState, pfNativeError,
			 szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
	else if (SQL_NULL_HDBC != hdbc)
		ret = PGAPI_ConnectError(hdbc, -1, szSqlState, pfNativeError,
			 szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
	else if (SQL_NULL_HENV != henv)
		ret = PGAPI_EnvError(henv, -1, szSqlState, pfNativeError,
			 szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag);
	else
	{
		if (NULL != szSqlState)
			strcpy(szSqlState, "00000");
		if (NULL != pcbErrorMsg)
			*pcbErrorMsg = 0;
		if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
			szErrorMsg[0] = '\0';

		ret = SQL_NO_DATA_FOUND;
	}
	mylog("**** PGAPI_Error exit code=%d\n", ret);
	return ret;
}

/*
 * EnvironmentClass implementation
 */
EnvironmentClass *
EN_Constructor(void)
{
	CSTR	func = "EN_Constructor";
	EnvironmentClass *rv = NULL;
#ifdef WIN32
#ifndef	_WSASTARTUP_IN_DLLMAIN_
	WORD		wVersionRequested;
	WSADATA		wsaData;

	/* Load the WinSock Library */
	wVersionRequested = MAKEWORD(1, 1);

	if (WSAStartup(wVersionRequested, &wsaData))
		return rv;
	/* Verify that this is the minimum version of WinSock */
	if (LOBYTE(wsaData.wVersion) != 1 ||
	    HIBYTE(wsaData.wVersion) != 1)
	{
		goto cleanup;
	}
#endif /* _WSASTARTUP_IN_DLLMAIN_ */
#endif

	rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass));
cleanup:
	if (rv)
	{
{'fraction_non_alphanumeric': 0.1315036722071898, 'fraction_numerical': 0.017008117510630073, 'mean_word_length': 3.959930981595092, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 101, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '38213', 'n_tokens_mistral': 11378, 'n_tokens_neox': 10175, 'n_words': 2346}