#include "dpiImpl.h"
#if defined(_MSC_VER)
#pragma section(".CRT$XCU", read)
#define DPI_INITIALIZER_HELPER(f, p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define DPI_INITIALIZER(f) DPI_INITIALIZER_HELPER(f, "")
#else
#define DPI_INITIALIZER(f) DPI_INITIALIZER_HELPER(f, "_")
#endif
#else
#define DPI_INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
static void *dpiGlobalEnvHandle = NULL;
static void *dpiGlobalErrorHandle = NULL;
static void *dpiGlobalThreadKey = NULL;
static dpiErrorBuffer dpiGlobalErrorBuffer;
static dpiVersionInfo dpiGlobalClientVersionInfo;
static int dpiGlobalInitialized = 0;
static dpiMutexType dpiGlobalMutex;
static char *dpiGlobalConfigDir = NULL;
static int dpiGlobal__extendedInitialize(dpiContextCreateParams *params,
const char *fnName, dpiError *error);
static void dpiGlobal__finalize(void);
static int dpiGlobal__getErrorBuffer(const char *fnName, dpiError *error);
int dpiGlobal__ensureInitialized(const char *fnName,
dpiContextCreateParams *params, dpiVersionInfo **clientVersionInfo,
dpiError *error)
{
error->handle = NULL;
error->buffer = &dpiGlobalErrorBuffer;
error->buffer->fnName = fnName;
if (!dpiGlobalInitialized) {
dpiMutex__acquire(dpiGlobalMutex);
if (!dpiGlobalInitialized)
dpiGlobal__extendedInitialize(params, fnName, error);
dpiMutex__release(dpiGlobalMutex);
if (!dpiGlobalInitialized)
return DPI_FAILURE;
}
*clientVersionInfo = &dpiGlobalClientVersionInfo;
return dpiGlobal__getErrorBuffer(fnName, error);
}
static int dpiGlobal__extendedInitialize(dpiContextCreateParams *params,
const char *fnName, dpiError *error)
{
int status;
dpiDebug__initialize();
if (dpiDebugLevel & DPI_DEBUG_LEVEL_FNS)
dpiDebug__print("fn start %s\n", fnName);
if (dpiOci__loadLib(params, &dpiGlobalClientVersionInfo,
&dpiGlobalConfigDir, error) < 0)
return DPI_FAILURE;
if (dpiOci__envNlsCreate(&dpiGlobalEnvHandle, DPI_OCI_THREADED,
DPI_CHARSET_ID_UTF8, DPI_CHARSET_ID_UTF8, error) < 0)
return DPI_FAILURE;
if (dpiOci__handleAlloc(dpiGlobalEnvHandle, &dpiGlobalErrorHandle,
DPI_OCI_HTYPE_ERROR, "create global error", error) < 0) {
dpiOci__handleFree(dpiGlobalEnvHandle, DPI_OCI_HTYPE_ENV);
return DPI_FAILURE;
}
status = dpiOci__threadKeyInit(dpiGlobalEnvHandle, dpiGlobalErrorHandle,
&dpiGlobalThreadKey, (void*) dpiUtils__freeMemory, error);
if (status < 0) {
dpiOci__handleFree(dpiGlobalEnvHandle, DPI_OCI_HTYPE_ENV);
return DPI_FAILURE;
}
dpiGlobalInitialized = 1;
return DPI_SUCCESS;
}
static void dpiGlobal__finalize(void)
{
void *errorBuffer = NULL;
dpiError error;
dpiMutex__acquire(dpiGlobalMutex);
dpiGlobalInitialized = 0;
error.buffer = &dpiGlobalErrorBuffer;
if (dpiGlobalThreadKey) {
dpiOci__threadKeyGet(dpiGlobalEnvHandle, dpiGlobalErrorHandle,
dpiGlobalThreadKey, &errorBuffer, &error);
if (errorBuffer) {
dpiOci__threadKeySet(dpiGlobalEnvHandle, dpiGlobalErrorHandle,
dpiGlobalThreadKey, NULL, &error);
dpiUtils__freeMemory(errorBuffer);
}
dpiOci__threadKeyDestroy(dpiGlobalEnvHandle, dpiGlobalErrorHandle,
&dpiGlobalThreadKey, &error);
dpiGlobalThreadKey = NULL;
}
if (dpiGlobalEnvHandle) {
dpiOci__handleFree(dpiGlobalEnvHandle, DPI_OCI_HTYPE_ENV);
dpiGlobalEnvHandle = NULL;
}
if (dpiGlobalConfigDir) {
free(dpiGlobalConfigDir);
dpiGlobalConfigDir = NULL;
}
dpiMutex__release(dpiGlobalMutex);
}
static int dpiGlobal__getErrorBuffer(const char *fnName, dpiError *error)
{
dpiErrorBuffer *tempErrorBuffer;
if (dpiOci__threadKeyGet(dpiGlobalEnvHandle, dpiGlobalErrorHandle,
dpiGlobalThreadKey, (void**) &tempErrorBuffer, error) < 0)
return DPI_FAILURE;
if (!tempErrorBuffer) {
if (dpiUtils__allocateMemory(1, sizeof(dpiErrorBuffer), 1,
"allocate error buffer", (void**) &tempErrorBuffer, error) < 0)
return DPI_FAILURE;
if (dpiOci__threadKeySet(dpiGlobalEnvHandle, dpiGlobalErrorHandle,
dpiGlobalThreadKey, tempErrorBuffer, error) < 0) {
dpiUtils__freeMemory(tempErrorBuffer);
return DPI_FAILURE;
}
}
if (fnName) {
tempErrorBuffer->code = 0;
tempErrorBuffer->offset = 0;
tempErrorBuffer->errorNum = (dpiErrorNum) 0;
tempErrorBuffer->isRecoverable = 0;
tempErrorBuffer->messageLength = 0;
tempErrorBuffer->fnName = fnName;
tempErrorBuffer->action = "start";
tempErrorBuffer->isWarning = 0;
strcpy(tempErrorBuffer->encoding, DPI_CHARSET_NAME_UTF8);
}
error->buffer = tempErrorBuffer;
return DPI_SUCCESS;
}
int dpiGlobal__initError(const char *fnName, dpiError *error)
{
error->handle = NULL;
error->buffer = &dpiGlobalErrorBuffer;
if (fnName)
error->buffer->fnName = fnName;
if (!dpiGlobalInitialized)
return dpiError__set(error, "check context creation",
DPI_ERR_CONTEXT_NOT_CREATED);
return dpiGlobal__getErrorBuffer(fnName, error);
}
DPI_INITIALIZER(dpiGlobal__initialize)
{
memset(&dpiGlobalErrorBuffer, 0, sizeof(dpiGlobalErrorBuffer));
strcpy(dpiGlobalErrorBuffer.encoding, DPI_CHARSET_NAME_UTF8);
dpiMutex__initialize(dpiGlobalMutex);
atexit(dpiGlobal__finalize);
}
int dpiGlobal__lookupCharSet(const char *name, uint16_t *charsetId,
dpiError *error)
{
char oraCharsetName[DPI_OCI_NLS_MAXBUFSZ];
if (strcmp(name, DPI_CHARSET_NAME_UTF8) == 0)
*charsetId = DPI_CHARSET_ID_UTF8;
else if (strcmp(name, DPI_CHARSET_NAME_UTF16) == 0)
*charsetId = DPI_CHARSET_ID_UTF16;
else if (strcmp(name, DPI_CHARSET_NAME_ASCII) == 0)
*charsetId = DPI_CHARSET_ID_ASCII;
else if (strcmp(name, DPI_CHARSET_NAME_UTF16LE) == 0 ||
strcmp(name, DPI_CHARSET_NAME_UTF16BE) == 0)
return dpiError__set(error, "check encoding", DPI_ERR_NOT_SUPPORTED);
else {
if (dpiOci__nlsCharSetNameToId(dpiGlobalEnvHandle, name, charsetId,
error) < 0)
return DPI_FAILURE;
if (!*charsetId) {
if (dpiOci__nlsNameMap(dpiGlobalEnvHandle, oraCharsetName,
sizeof(oraCharsetName), name, DPI_OCI_NLS_CS_IANA_TO_ORA,
error) < 0)
return dpiError__set(error, "lookup charset",
DPI_ERR_INVALID_CHARSET, name);
dpiOci__nlsCharSetNameToId(dpiGlobalEnvHandle, oraCharsetName,
charsetId, error);
}
}
return DPI_SUCCESS;
}
int dpiGlobal__lookupEncoding(uint16_t charsetId, char *encoding,
dpiError *error)
{
char oracleName[DPI_OCI_NLS_MAXBUFSZ];
switch (charsetId) {
case DPI_CHARSET_ID_UTF8:
strcpy(encoding, DPI_CHARSET_NAME_UTF8);
return DPI_SUCCESS;
case DPI_CHARSET_ID_UTF16:
strcpy(encoding, DPI_CHARSET_NAME_UTF16);
return DPI_SUCCESS;
case DPI_CHARSET_ID_ASCII:
strcpy(encoding, DPI_CHARSET_NAME_ASCII);
return DPI_SUCCESS;
}
if (dpiOci__nlsCharSetIdToName(dpiGlobalEnvHandle, oracleName,
sizeof(oracleName), charsetId, error) < 0)
return dpiError__set(error, "lookup Oracle character set name",
DPI_ERR_INVALID_CHARSET_ID, charsetId);
if (dpiOci__nlsNameMap(dpiGlobalEnvHandle, encoding, DPI_OCI_NLS_MAXBUFSZ,
oracleName, DPI_OCI_NLS_CS_ORA_TO_IANA, error) < 0)
return dpiError__set(error, "lookup IANA name",
DPI_ERR_INVALID_CHARSET_ID, charsetId);
return DPI_SUCCESS;
}