19 Star 39 Fork 46

openGauss / openGauss-connector-odbc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
environ.c 14.61 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
/*-------
* 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 "readme.txt" for copyright and license information.
*-------
*/
#include "environ.h"
#include "misc.h"
#include "connection.h"
#include "dlg_specific.h"
#include "statement.h"
#include <stdlib.h>
#include <string.h>
#include "pgapifunc.h"
#ifdef WIN32
#include <winsock2.h>
#endif /* WIN32 */
#include "loadlib.h"
/* The one instance of the handles */
static int conns_count = 0;
static ConnectionClass **conns = NULL;
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION conns_cs;
CRITICAL_SECTION common_cs; /* commonly used for short term blocking */
CRITICAL_SECTION common_lcs; /* commonly used for not necessarily short term blocking */
#elif defined(POSIX_MULTITHREAD_SUPPORT)
pthread_mutex_t conns_cs;
pthread_mutex_t common_cs;
pthread_mutex_t common_lcs;
#endif /* WIN_MULTITHREAD_SUPPORT */
void shortterm_common_lock(void)
{
ENTER_COMMON_CS;
}
void shortterm_common_unlock(void)
{
LEAVE_COMMON_CS;
}
int getConnCount(void)
{
return conns_count;
}
ConnectionClass * const *getConnList(void)
{
return conns;
}
RETCODE SQL_API
PGAPI_AllocEnv(HENV * phenv)
{
CSTR func = "PGAPI_AllocEnv";
SQLRETURN ret = SQL_SUCCESS;
MYLOG(0, "entering\n");
/*
* For systems on which none of the constructor-making
* techniques in psqlodbc.c work:
* It's ok to call initialize_global_cs() twice.
*/
{
initialize_global_cs();
}
*phenv = (HENV) EN_Constructor();
if (!*phenv)
{
*phenv = SQL_NULL_HENV;
EN_log_error(func, "Error allocating environment", NULL);
ret = SQL_ERROR;
}
MYLOG(0, "leaving phenv=%p\n", *phenv);
return ret;
}
RETCODE SQL_API
PGAPI_FreeEnv(HENV henv)
{
CSTR func = "PGAPI_FreeEnv";
SQLRETURN ret = SQL_SUCCESS;
EnvironmentClass *env = (EnvironmentClass *) henv;
MYLOG(0, "entering env=%p\n", env);
if (env && EN_Destructor(env))
{
MYLOG(0, " ok\n");
goto cleanup;
}
ret = SQL_ERROR;
EN_log_error(func, "Error freeing environment", NULL);
cleanup:
return ret;
}
#define SIZEOF_SQLSTATE 6
static void
pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const char *ver3str, const char *ver2str)
{
strncpy_null((char *) szSqlState, EN_is_odbc3(env) ? ver3str : ver2str, SIZEOF_SQLSTATE);
}
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 - sizeof(error->__error_message) + 1;
if (aladd < 0)
aladd = 0;
}
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 = (Int2) errsize;
if (errsize > 0)
memcpy(error->__error_message, msg, errsize);
error->__error_message[errsize] = '\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);
if (new)
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 * szSqlState,
SQLINTEGER * pfNativeError,
SQLCHAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT * pcbErrorMsg,
UWORD flag)
{
/* CC: return an error of a hstmt */
PG_ErrorInfo *error;
BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0);
const char *msg;
SWORD msglen, stapos, wrtlen, pcblen;
if (!pgerror)
return SQL_NO_DATA_FOUND;
error = pgerror;
msg = error->__error_message;
MYLOG(0, "entering status = %d, msg = #%s#\n", 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;
}
else if (1 == RecNumber && cbErrorMsgMax > 0)
error->recsize = cbErrorMsgMax - 1;
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 = cbErrorMsgMax - 1;
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_null((char *) szSqlState, error->sqlstate, 6);
MYLOG(0, " szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
if (wrtlen < pcblen)
return SQL_SUCCESS_WITH_INFO;
else
return SQL_SUCCESS;
}
RETCODE SQL_API
PGAPI_ConnectError(HDBC hdbc,
SQLSMALLINT RecNumber,
SQLCHAR * szSqlState,
SQLINTEGER * pfNativeError,
SQLCHAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT * pcbErrorMsg,
UWORD flag)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
EnvironmentClass *env = (EnvironmentClass *) conn->henv;
char *msg;
int status;
BOOL once_again = FALSE;
ssize_t msglen;
MYLOG(0, "entering 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(0, "CC_Get_error returned nothing.\n");
if (NULL != szSqlState)
strncpy_null((char *) szSqlState, "00000", SIZEOF_SQLSTATE);
if (NULL != pcbErrorMsg)
*pcbErrorMsg = 0;
if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
szErrorMsg[0] = '\0';
return SQL_NO_DATA_FOUND;
}
MYLOG(0, "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((char *) szErrorMsg, msg, cbErrorMsgMax);
if (NULL != pfNativeError)
*pfNativeError = status;
if (NULL != szSqlState)
{
if (conn->sqlstate[0])
strncpy_null((char *) szSqlState, conn->sqlstate, SIZEOF_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, "HY011", "S1011");
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_ILLEGAL_TRANSACT_STATE:
pg_sqlstate_set(env, szSqlState, "25000", "S1010");
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:
case CONNECTION_NO_RESPONSE:
pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
break;
default:
pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
/* general error */
break;
}
}
MYLOG(0, " szSqlState = '%s',len=" FORMAT_SSIZE_T ", szError='%s'\n", szSqlState ? (char *) szSqlState : PRINT_NULL, msglen, szErrorMsg ? (char *) szErrorMsg : PRINT_NULL);
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 * szSqlState,
SQLINTEGER * pfNativeError,
SQLCHAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT * pcbErrorMsg,
UWORD flag)
{
EnvironmentClass *env = (EnvironmentClass *) henv;
char *msg = NULL;
int status;
MYLOG(0, "entering 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(0, "EN_get_error: msg = #%s#\n", 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(0, "EN_get_error: status = %d, msg = #%s#\n", status, msg);
if (NULL != pcbErrorMsg)
*pcbErrorMsg = (SQLSMALLINT) strlen(msg);
if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
strncpy_null((char *) 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;
}
/*
* EnvironmentClass implementation
*/
EnvironmentClass *
EN_Constructor(void)
{
EnvironmentClass *rv = NULL;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
const int major = 2, minor = 2;
/* Load the WinSock Library */
wVersionRequested = MAKEWORD(major, minor);
if (WSAStartup(wVersionRequested, &wsaData))
{
MYLOG(0, " WSAStartup error\n");
return rv;
}
/* Verify that this is the minimum version of WinSock */
if (LOBYTE(wsaData.wVersion) >= 1 &&
(LOBYTE(wsaData.wVersion) >= 2 ||
HIBYTE(wsaData.wVersion) >= 1))
;
else
{
MYLOG(0, " WSAStartup version=(%d,%d)\n",
LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
goto cleanup;
}
#endif /* WIN32 */
rv = (EnvironmentClass *) malloc(sizeof(EnvironmentClass));
if (NULL == rv)
{
MYLOG(0, " malloc error\n");
goto cleanup;
}
rv->errormsg = 0;
rv->errornumber = 0;
rv->flag = 0;
INIT_ENV_CS(rv);
cleanup:
#ifdef WIN32
if (NULL == rv)
{
WSACleanup();
}
#endif /* WIN32 */
return rv;
}
char
EN_Destructor(EnvironmentClass *self)
{
int lf, nullcnt;
char rv = 1;
MYLOG(0, "entering self=%p\n", self);
if (!self)
return 0;
/*
* the error messages are static strings distributed throughout the
* source--they should not be freed
*/
/* Free any connections belonging to this environment */
ENTER_CONNS_CS;
for (lf = 0, nullcnt = 0; lf < conns_count; lf++)
{
if (NULL == conns[lf])
nullcnt++;
else if (conns[lf]->henv == self)
{
if (CC_Destructor(conns[lf]))
conns[lf] = NULL;
else
rv = 0;
nullcnt++;
}
}
if (conns && nullcnt >= conns_count)
{
MYLOG(0, "clearing conns count=%d\n", conns_count);
free(conns);
conns = NULL;
conns_count = 0;
}
LEAVE_CONNS_CS;
DELETE_ENV_CS(self);
free(self);
#ifdef WIN32
WSACleanup();
#endif
MYLOG(0, "leaving rv=%d\n", rv);
#ifdef _MEMORY_DEBUG_
debug_memory_check();
#endif /* _MEMORY_DEBUG_ */
return rv;
}
char
EN_get_error(EnvironmentClass *self, int *number, char **message)
{
if (self && self->errormsg && self->errornumber)
{
*message = self->errormsg;
*number = self->errornumber;
self->errormsg = 0;
self->errornumber = 0;
return 1;
}
else
return 0;
}
#define INIT_CONN_COUNT 128
char
EN_add_connection(EnvironmentClass *self, ConnectionClass *conn)
{
int i, alloc;
ConnectionClass **newa;
char ret = FALSE;
MYLOG(0, "entering self = %p, conn = %p\n", self, conn);
ENTER_CONNS_CS;
for (i = 0; i < conns_count; i++)
{
if (!conns[i])
{
conn->henv = self;
conns[i] = conn;
ret = TRUE;
MYLOG(0, " added at i=%d, conn->henv = %p, conns[i]->henv = %p\n", i, conn->henv, conns[i]->henv);
goto cleanup;
}
}
if (conns_count > 0)
alloc = 2 * conns_count;
else
alloc = INIT_CONN_COUNT;
if (newa = (ConnectionClass **) realloc(conns, alloc * sizeof(ConnectionClass *)), NULL == newa)
goto cleanup;
conn->henv = self;
newa[conns_count] = conn;
conns = newa;
ret = TRUE;
MYLOG(0, " added at %d, conn->henv = %p, conns[%d]->henv = %p\n", conns_count, conn->henv, conns_count, conns[conns_count]->henv);
for (i = conns_count + 1; i < alloc; i++)
conns[i] = NULL;
conns_count = alloc;
cleanup:
LEAVE_CONNS_CS;
return ret;
}
char
EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn)
{
int i;
for (i = 0; i < conns_count; i++)
if (conns[i] == conn && conns[i]->status != CONN_EXECUTING)
{
ENTER_CONNS_CS;
conns[i] = NULL;
LEAVE_CONNS_CS;
return TRUE;
}
return FALSE;
}
void
EN_log_error(const char *func, char *desc, EnvironmentClass *self)
{
if (self)
MYLOG(0, "ENVIRON ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, self->errormsg);
else
MYLOG(0, "INVALID ENVIRON HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
}
C
1
https://gitee.com/opengauss/openGauss-connector-odbc.git
git@gitee.com:opengauss/openGauss-connector-odbc.git
opengauss
openGauss-connector-odbc
openGauss-connector-odbc
master

搜索帮助