blob: 7f3950f58c50c66bf4b8133bec38bce25938e71d [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
********************************************************************/
/*************************************************************************
**************************************************************************/
//
//
#include "DrvrGlobal.h"
#include "tdm_odbcDrvMsg.h"
#include "DiagFunctions.h"
#include <errno.h>
#include "StaticLocking.h"
#include "DrvrSrvr.h"
// Declare the global variable
typedef unsigned long* (SQL_API *FPGetODBCSharedData) ();
extern FPGetODBCSharedData pGetODBCSharedData = NULL;
CRITICAL_SECTION gCollectionCSObject;
CDrvrGlobal gDrvrGlobal;
DWORD *pdwGlobalTraceVariable = NULL;
DWORD gTraceFlags = 0;
HMODULE g_hOdbcDM = NULL;
HMODULE g_hTraceDLL = NULL;
DWORD gTlsIndex_ErrorBuffer = TLS_OUT_OF_INDEXES;
DATATYPE_TABLE gSQLDatatypeMap[] =
{
// conciseType, verboseType, datetimeIntervalCode, columnSizeAttr, decimalDigitsAttr, displaySizeAttr, octetLength, defaultType, typeName
{TYPE_BLOB, SQL_CHAR, 0, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, SQL_DESC_LENGTH, SQL_C_CHAR, "BLOB" },
{TYPE_CLOB, SQL_CHAR, 0, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, SQL_DESC_LENGTH, SQL_C_CHAR, "CLOB" },
{SQL_CHAR, SQL_CHAR, 0, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, SQL_DESC_LENGTH, SQL_C_CHAR, "CHAR"},
{SQL_VARCHAR, SQL_VARCHAR, 0, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, SQL_DESC_LENGTH, SQL_C_CHAR, "VARCHAR"},
{SQL_LONGVARCHAR, SQL_LONGVARCHAR, 0, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, SQL_DESC_LENGTH, SQL_C_CHAR, "LONG VARCHAR"},
{SQL_DECIMAL, SQL_DECIMAL, 0, SQL_DESC_PRECISION, SQL_DESC_SCALE, SQL_DESC_PRECISION, SQL_DESC_PRECISION, SQL_C_CHAR, "DECIMAL"},
{SQL_NUMERIC, SQL_NUMERIC, 0, SQL_DESC_PRECISION, SQL_DESC_SCALE, SQL_DESC_PRECISION, SQL_DESC_PRECISION, SQL_C_CHAR, "NUMERIC"},
{SQL_SMALLINT, SQL_SMALLINT, 0, SQL_DESC_PRECISION, SQL_DESC_SCALE, 6, sizeof(SHORT), SQL_C_SHORT, "SMALLINT"},
{SQL_INTEGER, SQL_INTEGER, 0, SQL_DESC_PRECISION, SQL_DESC_SCALE, 11, sizeof(LONG), SQL_C_LONG, "INTEGER"},
{SQL_REAL, SQL_REAL, 0, SQL_DESC_PRECISION, 0, 13, sizeof(FLOAT), SQL_C_FLOAT, "REAL"},
{SQL_FLOAT, SQL_FLOAT, 0, SQL_DESC_PRECISION, 0, 22, sizeof(DOUBLE), SQL_C_DOUBLE, "FLOAT"},
{SQL_DOUBLE, SQL_DOUBLE, 0, SQL_DESC_PRECISION, 0, 22, sizeof(DOUBLE), SQL_C_DOUBLE, "DOUBLE PRECISION"},
{SQL_BIT, SQL_BIT, 0, SQL_DESC_LENGTH, 0, 1, sizeof(SCHAR), SQL_C_BIT, "BIT"},
{SQL_TINYINT, SQL_TINYINT, 0, SQL_DESC_PRECISION, SQL_DESC_SCALE, 4, sizeof(CHAR), SQL_C_TINYINT, "TINYINT"},
{SQL_BIGINT, SQL_BIGINT, 0, SQL_DESC_PRECISION, SQL_DESC_SCALE, 20, 20, SQL_C_SBIGINT, "BIGINT"},
{SQL_BINARY, SQL_BINARY, 0, SQL_DESC_LENGTH, 0, -1, SQL_DESC_LENGTH, SQL_C_BINARY, "BINARY"},
{SQL_VARBINARY, SQL_VARBINARY, 0, SQL_DESC_LENGTH, 0, -1, SQL_DESC_LENGTH, SQL_C_BINARY, "VARBINARY"},
{SQL_LONGVARBINARY, SQL_LONGVARBINARY, 0, SQL_DESC_LENGTH, 0, -1, SQL_DESC_LENGTH, SQL_C_BINARY, "LONG VARBINARY"},
{SQL_WCHAR, SQL_WCHAR, 0, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, SQL_DESC_LENGTH, SQL_C_WCHAR, "NCHAR"},
{SQL_WVARCHAR, SQL_WVARCHAR, 0, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, SQL_DESC_LENGTH, SQL_C_WCHAR, "NCHAR VARYING"},
{SQL_WLONGVARCHAR, SQL_WLONGVARCHAR, 0, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, SQL_DESC_LENGTH, SQL_C_WCHAR, "NCHAR VARYING"},
{SQL_DATE, SQL_DATETIME, SQL_CODE_DATE, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_DATE_STRUCT), SQL_C_TYPE_DATE, "DATE"},
{SQL_TIME, SQL_DATETIME, SQL_CODE_TIME, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_TIME_STRUCT), SQL_C_TYPE_TIME, "TIME"},
{SQL_TIMESTAMP, SQL_DATETIME, SQL_CODE_TIMESTAMP, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_TIMESTAMP_STRUCT), SQL_C_TYPE_TIMESTAMP, "TIMESTAMP"},
{SQL_TYPE_DATE, SQL_DATETIME, SQL_CODE_DATE, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_DATE_STRUCT), SQL_C_TYPE_DATE, "DATE"},
{SQL_TYPE_TIME, SQL_DATETIME, SQL_CODE_TIME, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_TIME_STRUCT), SQL_C_TYPE_TIME, "TIME"},
{SQL_TYPE_TIMESTAMP, SQL_DATETIME, SQL_CODE_TIMESTAMP, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_TIMESTAMP_STRUCT), SQL_C_TYPE_TIMESTAMP, "TIMESTAMP"},
// Make sure you check the values before uncommenting, This is not kept in sync with the structure changes
{SQL_INTERVAL_MONTH, SQL_INTERVAL, SQL_CODE_MONTH, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_MONTH, "INTERVAL MONTH"},
{SQL_INTERVAL_YEAR, SQL_INTERVAL, SQL_CODE_YEAR, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_YEAR, "INTERVAL YEAR"},
{SQL_INTERVAL_YEAR_TO_MONTH, SQL_INTERVAL, SQL_CODE_YEAR_TO_MONTH, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_YEAR_TO_MONTH, "INTERVAL YEAR TO MONTH"},
{SQL_INTERVAL_DAY, SQL_INTERVAL, SQL_CODE_DAY, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_DAY, "INTERVAL DAY"},
{SQL_INTERVAL_HOUR, SQL_INTERVAL, SQL_CODE_HOUR, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_HOUR, "INTERVAL HOUR"},
{SQL_INTERVAL_MINUTE, SQL_INTERVAL, SQL_CODE_MINUTE, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_MINUTE, "INTERVAL MINUTE"},
{SQL_INTERVAL_SECOND, SQL_INTERVAL, SQL_CODE_SECOND, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_SECOND, "INTERVAL SECOND"},
{SQL_INTERVAL_DAY_TO_HOUR, SQL_INTERVAL, SQL_CODE_DAY_TO_HOUR, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_DAY_TO_HOUR, "INTERVAL DAY TO HOUR"},
{SQL_INTERVAL_DAY_TO_MINUTE, SQL_INTERVAL, SQL_CODE_DAY_TO_MINUTE, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_DAY_TO_MINUTE, "INTERVAL DAY TO MINUTE"},
{SQL_INTERVAL_DAY_TO_SECOND, SQL_INTERVAL, SQL_CODE_DAY_TO_SECOND, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_DAY_TO_SECOND, "INTERVAL DAY TO SECOND"},
{SQL_INTERVAL_HOUR_TO_MINUTE, SQL_INTERVAL, SQL_CODE_HOUR_TO_MINUTE, SQL_DESC_LENGTH, 0, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_HOUR_TO_MINUTE, "INTERVAL HOUR TO MINUTE"},
{SQL_INTERVAL_HOUR_TO_SECOND, SQL_INTERVAL, SQL_CODE_HOUR_TO_SECOND, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_HOUR_TO_SECOND, "INTERVAL HOUR TO SECOND"},
{SQL_INTERVAL_MINUTE_TO_SECOND, SQL_INTERVAL, SQL_CODE_MINUTE_TO_SECOND, SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_LENGTH, sizeof(SQL_INTERVAL_STRUCT), SQL_C_INTERVAL_MINUTE_TO_SECOND,"INTERVAL MINUTE TO SECOND"},
{SQL_DEFAULT, SQL_DEFAULT, 0, 0, 0}
};
DATATYPE_TABLE gCDatatypeMap[] =
{
// conciseType, verboseType, datetimeIntervalCode
{SQL_C_CHAR, SQL_C_CHAR, 0, 0, 0, 0, SQL_DESC_LENGTH, SQL_C_CHAR, "CHAR"},
{SQL_C_SHORT, SQL_C_SHORT, 0, 0, 0, 0, sizeof(short), SQL_C_SHORT, "SMALLINT"},
{SQL_C_SSHORT, SQL_C_SSHORT, 0, 0, 0, 0, sizeof(short), SQL_C_SSHORT, "SMALLINT"},
{SQL_C_USHORT, SQL_C_USHORT, 0, 0, 0, 0, sizeof(unsigned short), SQL_C_USHORT, "SMALLINT"},
{SQL_C_LONG, SQL_C_LONG, 0, 0, 0, 0, sizeof(long), SQL_C_LONG, "INTEGER"},
{SQL_C_SLONG, SQL_C_SLONG, 0, 0, 0, 0, sizeof(long), SQL_C_SLONG, "INTEGER"},
{SQL_C_ULONG, SQL_C_ULONG, 0, 0, 0, 0, sizeof(unsigned long), SQL_C_ULONG, "INTEGER"},
{SQL_C_FLOAT, SQL_C_FLOAT, 0, 0, 0, 0, sizeof(float), SQL_C_FLOAT, "FLOAT"},
{SQL_C_DOUBLE, SQL_C_DOUBLE, 0, 0, 0, 0, sizeof(double), SQL_C_DOUBLE, "DOUBLE"},
{SQL_C_BIT, SQL_C_BIT, 0, 0, 0, 0, sizeof(unsigned char), SQL_C_BIT, "BIT"},
{SQL_C_TINYINT, SQL_C_TINYINT, 0, 0, 0, 0, sizeof(signed char), SQL_C_TINYINT, "TINYINT"},
{SQL_C_STINYINT, SQL_C_STINYINT, 0, 0, 0, 0, sizeof(signed char), SQL_C_STINYINT, "TINYINT"},
{SQL_C_UTINYINT, SQL_C_UTINYINT, 0, 0, 0, 0, sizeof(unsigned char), SQL_C_UTINYINT, "TINYINT"},
{SQL_C_SBIGINT, SQL_C_SBIGINT, 0, 0, 0, 0, sizeof(_int64), SQL_C_SBIGINT, "BIGINT"},
{SQL_C_UBIGINT, SQL_C_UBIGINT, 0, 0, 0, 0, sizeof(unsigned _int64), SQL_C_UBIGINT, "BIGINT"},
{SQL_C_BINARY, SQL_C_BINARY, 0, 0, 0, 0, SQL_DESC_LENGTH, SQL_C_BINARY, "BINARY"},
{SQL_C_BOOKMARK, SQL_C_BOOKMARK, 0, 0, 0, 0, sizeof(unsigned long), SQL_C_BOOKMARK, "BOOKMARK"},
{SQL_C_VARBOOKMARK, SQL_C_VARBOOKMARK, 0, 0, 0, 0, SQL_DESC_LENGTH, SQL_C_VARBOOKMARK, "VARBOOKMARK"},
{SQL_C_NUMERIC, SQL_C_NUMERIC, 0, 0, 0, 0, sizeof(SQL_NUMERIC_STRUCT), SQL_C_NUMERIC, "NUMERIC"},
{SQL_C_WCHAR, SQL_C_WCHAR, 0, 0, 0, 0, SQL_DESC_LENGTH, SQL_C_WCHAR, "NCHAR"},
{SQL_C_DATE, SQL_DATETIME, SQL_CODE_DATE, 0, 0, 0, sizeof(DATE_STRUCT), SQL_TYPE_DATE, "DATE"},
{SQL_C_TIME, SQL_DATETIME, SQL_CODE_TIME, 0, 0, 0, sizeof(TIME_STRUCT), SQL_TYPE_TIME, "TIME"},
{SQL_C_TIMESTAMP, SQL_DATETIME, SQL_CODE_TIMESTAMP, 0, 0, 0, sizeof(TIMESTAMP_STRUCT), SQL_TYPE_TIMESTAMP, "TIMESTAMP"},
{SQL_C_TYPE_DATE, SQL_DATETIME, SQL_CODE_DATE, 0, 0, 0, sizeof(DATE_STRUCT), SQL_TYPE_DATE, "DATE"},
{SQL_C_TYPE_TIME, SQL_DATETIME, SQL_CODE_TIME, 0, 0, 0, sizeof(TIME_STRUCT), SQL_TYPE_TIME, "TIME"},
{SQL_C_TYPE_TIMESTAMP, SQL_DATETIME, SQL_CODE_TIMESTAMP, 0, 0, 0, sizeof(TIMESTAMP_STRUCT), SQL_TYPE_TIMESTAMP, "TIMESTAMP"},
{SQL_C_INTERVAL_MONTH, SQL_INTERVAL, SQL_CODE_MONTH, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_MONTH, "INTERVAL MONTH"},
{SQL_C_INTERVAL_YEAR, SQL_INTERVAL, SQL_CODE_YEAR, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_YEAR, "INTERVAL YEAR"},
{SQL_C_INTERVAL_YEAR_TO_MONTH, SQL_INTERVAL, SQL_CODE_YEAR_TO_MONTH, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_YEAR_TO_MONTH, "INTERVAL YEAR TO MONTH"},
{SQL_C_INTERVAL_DAY, SQL_INTERVAL, SQL_CODE_DAY, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_DAY, "INTERVAL DAY"},
{SQL_C_INTERVAL_HOUR, SQL_INTERVAL, SQL_CODE_HOUR, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_HOUR, "INTERVAL HOUR"},
{SQL_C_INTERVAL_MINUTE, SQL_INTERVAL, SQL_CODE_MINUTE, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_MINUTE, "INTERVAL MINUTE"},
{SQL_C_INTERVAL_SECOND, SQL_INTERVAL, SQL_CODE_SECOND, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_SECOND, "INTERVAL SECOND"},
{SQL_C_INTERVAL_DAY_TO_HOUR, SQL_INTERVAL, SQL_CODE_DAY_TO_HOUR, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_DAY_TO_HOUR, "INTERVAL DAY TO HOUR"},
{SQL_C_INTERVAL_DAY_TO_MINUTE, SQL_INTERVAL, SQL_CODE_DAY_TO_MINUTE, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_DAY_TO_MINUTE, "INTERVAL DAY TO MINUTE"},
{SQL_C_INTERVAL_DAY_TO_SECOND, SQL_INTERVAL, SQL_CODE_DAY_TO_SECOND, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_DAY_TO_SECOND, "INTERVAL DAY TO SECOND"},
{SQL_C_INTERVAL_HOUR_TO_MINUTE, SQL_INTERVAL, SQL_CODE_HOUR_TO_MINUTE, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_HOUR_TO_MINUTE, "INTERVAL HOUR TO MINUTE"},
{SQL_C_INTERVAL_HOUR_TO_SECOND, SQL_INTERVAL, SQL_CODE_HOUR_TO_SECOND, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_HOUR_TO_SECOND, "INTERVAL HOUR TO SECOND"},
{SQL_C_INTERVAL_MINUTE_TO_SECOND, SQL_INTERVAL, SQL_CODE_MINUTE_TO_SECOND, 0, 0, 0, sizeof(SQL_INTERVAL_STRUCT),SQL_INTERVAL_MINUTE_TO_SECOND, "INTERVAL MINUTE TO SECOND"},
{SQL_C_DEFAULT}
};
char *ConnectKeywords[] =
{
"DRIVER",
"DSN",
"FILEDSN",
"SERVER",
"SAVEFILE",
"UID",
"PWD",
"CATALOG",
"SCHEMA",
"FETCHBUFFERSIZE",
"SQL_ATTR_CONNECTION_TIMEOUT",
"SQL_LOGIN_TIMEOUT",
"SQL_QUERY_TIMEOUT",
"DATALANG",
"ERRORMSGLANG",
"CTRLINFERNCHAR",
"TRANSLATIONDLL",
"TRANSLATIONOPTION",
"REPLACEMENTCHAR",
"SERVERDSN",
"SERVICE",
"SESSION",
"APPLICATION",
"ROLENAME",
"CERTIFICATEDIR",
"CERTIFICATEFILE",
"CERTIFICATEFILE_ACTIVE",
"COMPRESSION",
"COMPRESSIONTHRESHOLD",
NULL
};
char *ConnectLocalizedIdentifier[] =
{
"Driver",
"Data Source Name",
"File Data Source Name",
"Server ID",
"Save File",
"Login ID",
"Password",
"Catalog",
"Schema",
"Fetch Buffer Size (kbytes)",
"Connection Timeout (seconds)",
"Login Timeout (seconds)",
"Query Timeout (seconds)",
"Client/Server Character Set",
"Client Error Message Language",
"Infer NCHAR",
"Translate DLL Name",
"Translate Option",
"Replacement Character",
"Server Data Source Name",
"Service Name",
"Session Name",
"Application Name",
"Role Name",
"Certificate Directory",
"Certificate File",
"Certificate File Active",
"Compression",
"CompressionThreshold",
NULL
};
DESC_SET_TYPE gDescSetTypes[] =
{
// FieldIdentifier ARD APD IRD IPD
{SQL_DESC_ALLOC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE},
{SQL_DESC_ARRAY_SIZE, RW_DESC_TYPE, RW_DESC_TYPE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_ARRAY_STATUS_PTR, RW_DESC_TYPE, RW_DESC_TYPE, RW_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_BIND_OFFSET_PTR, RW_DESC_TYPE, RW_DESC_TYPE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_BIND_TYPE, RW_DESC_TYPE, RW_DESC_TYPE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_COUNT, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_ROWS_PROCESSED_PTR, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, RW_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_AUTO_UNIQUE_VALUE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_BASE_COLUMN_NAME, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_BASE_TABLE_NAME, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_CASE_SENSITIVE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE},
{SQL_DESC_CATALOG_NAME, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_CONCISE_TYPE, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_DATA_PTR, RW_DESC_TYPE, RW_DESC_TYPE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_DATETIME_INTERVAL_CODE, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_DATETIME_INTERVAL_PRECISION, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_DISPLAY_SIZE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_FIXED_PREC_SCALE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE},
{SQL_DESC_INDICATOR_PTR, RW_DESC_TYPE, RW_DESC_TYPE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_LABEL, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_LENGTH, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_LITERAL_PREFIX, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_LITERAL_SUFFIX, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_LOCAL_TYPE_NAME, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE},
{SQL_DESC_NAME, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_NULLABLE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE},
{SQL_DESC_NUM_PREC_RADIX, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE},
{SQL_DESC_OCTET_LENGTH, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_OCTET_LENGTH_PTR, RW_DESC_TYPE, RW_DESC_TYPE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_PARAMETER_TYPE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_PRECISION, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_SCALE, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_SCHEMA_NAME, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_SEARCHABLE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_TABLE_NAME, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{SQL_DESC_TYPE, RW_DESC_TYPE, RW_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_TYPE_NAME, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE},
{SQL_DESC_UNNAMED, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, RW_DESC_TYPE},
{SQL_DESC_UNSIGNED, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, READ_DESC_TYPE},
{SQL_DESC_UPDATABLE, UNUSED_DESC_TYPE, UNUSED_DESC_TYPE, READ_DESC_TYPE, UNUSED_DESC_TYPE},
{9999}
};
// Global Handle Initialization
CDrvrGlobal::CDrvrGlobal() : gOdbcMsg(DRVRMSG_DLL)
{
OSVERSIONINFO VersionInformation;
void *pVersionInfo;
VS_FIXEDFILEINFO *pInfo;
UINT wInfoLen;
DWORD dwVersionInfoSz;
DWORD hFile;
unsigned long len;
WORD* langInfo;
UINT cbLang;
TCHAR tszVerStrName[128];
LPVOID lpt;
InitializeCriticalSection(&gCSObject);
InitializeCriticalSection(&gHandleCSObject);
InitializeCriticalSection(&gCollectionCSObject);
strcpy(gCapsuleName, "TRAF ODBC Driver");
len = sizeof(gComputerName);
if (GetComputerName(gComputerName, &len) == 0)
strcpy(gComputerName, "UNKNOWN");
gProcessId = GetCurrentProcessId();
//referer to the enum cnv_charset in csconvert.h
//TranslateOption <4bytes from charset,4 bytes to charset>
gUTF8_To_UTF16_TranslateOption = ((DWORD)0x00010002L);
gUTF16_To_UTF8_TranslateOption = ((DWORD)0x00020001L);
VersionInformation.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
if (GetVersionEx( &VersionInformation ) == 0)
{
gPlatformId = 0;
gMinorVersion = 0;
}
else
{
gPlatformId = VersionInformation.dwPlatformId;
gMinorVersion = VersionInformation.dwMinorVersion;
}
gClientVersion.componentId = 0; // Unknown
strcpy(gDriverDLLName, DRIVER_DLL_NAME);
if ((gModuleHandle = GetModuleHandle(DRIVER_DLL_NAME)) != NULL)
{
if (GetModuleFileName(gModuleHandle, gDriverDLLName, sizeof(gDriverDLLName)))
{
if ((dwVersionInfoSz = GetFileVersionInfoSize(gDriverDLLName, &hFile)) != 0)
{
pVersionInfo = (void *)new char[dwVersionInfoSz];
if (GetFileVersionInfo(gDriverDLLName, hFile, dwVersionInfoSz, (LPVOID)pVersionInfo)
&& VerQueryValue((LPVOID)pVersionInfo, "\\",(LPVOID *)&pInfo, &wInfoLen) )
{
gClientVersion.componentId = WIN_UNICODE_DRVR_COMPONENT;
gClientVersion.majorVersion = HIWORD(pInfo->dwProductVersionMS);
gClientVersion.minorVersion = LOWORD(pInfo->dwProductVersionMS);
gClientVersion.buildId = LOWORD(pInfo->dwFileVersionLS);
// Get the vproc in the Comments field
strncpy(gClientVproc, VprocString, sizeof(gClientVproc)-1);
gClientVproc[sizeof(gClientVproc)-1] = '\0';
}
delete[] pVersionInfo;
}
}
}
if (gClientVersion.componentId == 0)
{
gClientVersion.componentId = DRVR_COMPONENT;
gClientVersion.majorVersion = 3;
gClientVersion.minorVersion = 51;
gClientVersion.buildId = 0;
}
gCEEInitialized = FALSE;
gCEESyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
gCEEExecuteThread = NULL;
gDefaultTxnIsolation = SQL_TXN_READ_COMMITTED;
gWaitCursor = LoadCursor(NULL, IDC_WAIT);
gCEEMessageFilter = TRUE;
ghWindow = NULL;
gSpecial_1 = false;
loadTransportAndTranslateDll();
SecurityInitialize();
noSchemaInDSN = false; // Assume that DSN has a schema value
char envValue[STRICT_SCHEMA_ENV_VAL_SIZE];
size_t valueSize = STRICT_SCHEMA_ENV_VAL_SIZE ;
size_t returnLen=0 ;
RestrictSchema = false;
if (getenv_s(&returnLen, envValue, valueSize, "TRAFODBC-SQLTABLES-RESTRICT-DSNSCHEMA") == 0) //success
if(returnLen != 0)
RestrictSchema = true;
#ifdef TRACE_COMPRESSION
char *envTraceCompression=NULL;
gTraceCompression=false;
if( (envTraceCompression = getenv("TRAFODBC_TRACE_COMPRESSION")) != NULL)
{
if(strcmp(envTraceCompression,"1")==0)
{
gTraceCompression=true;
}
}
#endif
}
CDrvrGlobal::~CDrvrGlobal()
{
CloseHandle(gCEESyncEvent);
DeleteCriticalSection(&gCSObject);
DeleteCriticalSection(&gHandleCSObject);
DeleteCriticalSection(&gCollectionCSObject);
if (gTCPIPHandle != NULL && fpTCPIPExitIO != NULL)
{
(fpTCPIPExitIO)();
//
// keep dll in the memory as long as posible because of the memory leaks when free/load?
// FreeLibrary(gTCPIPHandle);
}
// if (gTranslateLibrary != NULL)
// FreeLibrary(gTranslateLibHandle);
}
void CDrvrGlobal::loadTransportAndTranslateDll()
{
strcpy(gTCPIPLibrary, gDriverDLLName);
strstr(_strlwr(gTCPIPLibrary),DRIVER_DLL_NAME)[0] = 0;
if (gPlatformId != VER_PLATFORM_WIN32_NT)
strcat(gTCPIPLibrary, TCPIPV4_DLL_NAME);
else
strcat(gTCPIPLibrary, TCPIPV6_DLL_NAME);
gTCPIPHandle = NULL;
gTCPIPLoadError = 0;
if ((gTCPIPHandle = GetModuleHandle(gTCPIPLibrary)) != NULL || (gTCPIPHandle = LoadLibrary(gTCPIPLibrary)) != NULL )
{
fpTCPIPInitIO = (FPTCPIPInitIO)GetProcAddress( gTCPIPHandle, TCPIPINITIO_PROCNAME);
fpTCPIPExitIO = (FPTCPIPExitIO)GetProcAddress( gTCPIPHandle, TCPIPEXITIO_PROCNAME);
fpTCPIPOpenSession = (FPTCPIPOpenSession)GetProcAddress( gTCPIPHandle, TCPIPOPENSESSION_PROCNAME);
fpTCPIPCloseSession = (FPTCPIPCloseSession)GetProcAddress( gTCPIPHandle, TCPIPCLOSESESSION_PROCNAME);
fpTCPIPDoWriteRead = (FPTCPIPDoWriteRead)GetProcAddress( gTCPIPHandle, TCPIPDOWRITEREAD_PROCNAME);
if (fpTCPIPInitIO != NULL &&
fpTCPIPExitIO != NULL &&
fpTCPIPOpenSession != NULL &&
fpTCPIPCloseSession != NULL &&
fpTCPIPDoWriteRead != NULL )
gTCPIPLoadError = (fpTCPIPInitIO)(gModuleHandle);
else
gTCPIPLoadError = 990;
}
else
{
gTCPIPLoadError = GetLastError();
fpTCPIPInitIO = NULL;
fpTCPIPExitIO = NULL;
fpTCPIPOpenSession = NULL;
fpTCPIPCloseSession = NULL;
fpTCPIPDoWriteRead = NULL;
}
//Load Translation DLL
//Get the absolute directory of system32 and append the dll name
strcpy(gTranslateLibrary, gDriverDLLName);
strstr(_strlwr(gTranslateLibrary),DRIVER_DLL_NAME)[0] = 0;
strcat(gTranslateLibrary, TRANSLATE_DLL_NAME);
gTranslateLibHandle = NULL;
gTranslateLoadError = 0;
if ((gTranslateLibHandle = GetModuleHandle(gTranslateLibrary)) != NULL ||
(gTranslateLibHandle = LoadLibrary(gTranslateLibrary)) != NULL )
{
fpSQLDriverToDataSource = (FPSQLDriverToDataSource)GetProcAddress( gTranslateLibHandle, SQL_DRIVER_TO_DATASOURCE);
fpSQLDataSourceToDriver = (FPSQLDataSourceToDriver)GetProcAddress( gTranslateLibHandle, SQL_DATASOURCE_TO_DRIVER);
if (fpSQLDriverToDataSource != NULL &&
fpSQLDataSourceToDriver != NULL)
gTranslateLoadError = 890;
}
else
{
gTranslateLoadError = GetLastError();
fpSQLDriverToDataSource = NULL;
fpSQLDriverToDataSource = NULL;
}
}
SQLRETURN returnAttrValue(BOOL reportError,
CHandle *pHandle,
RETURN_VALUE_STRUCT *retValues,
SQLPOINTER ValuePtr,
SQLINTEGER BufferLength,
SQLINTEGER *StringLengthPtr)
{
SQLINTEGER strLen = DRVR_PENDING;
SQLRETURN rc = SQL_SUCCESS;
SQLINTEGER translateLength = 0;
SQLINTEGER translateLengthMax = 0;
UCHAR errorMsg[MAX_TRANSLATE_ERROR_MSG_LEN];
errorMsg[0] = '\0';
if (ValuePtr != NULL)
{
switch (retValues->dataType)
{
case SQL_C_SBIGINT:
*(IDL_long_long*)ValuePtr = retValues->u.s64Value;
strLen = sizeof(IDL_long_long);
break;
case SQL_C_UBIGINT:
*(IDL_unsigned_long_long*)ValuePtr = retValues->u.u64Value;
strLen = sizeof(IDL_unsigned_long_long);
break;
case SQL_IS_POINTER:
*(SQLPOINTER *)ValuePtr = retValues->u.pValue;
strLen = sizeof(SQLPOINTER);
break;
case SQL_IS_INTEGER:
*(SQLINTEGER *)ValuePtr = retValues->u.s32Value;
strLen = sizeof(SQLINTEGER);
break;
case SQL_IS_UINTEGER:
*(SQLUINTEGER *)ValuePtr = retValues->u.u32Value;
strLen = sizeof(SQLUINTEGER);
break;
case SQL_IS_SMALLINT:
*(SQLSMALLINT *)ValuePtr = retValues->u.s16Value;
strLen = sizeof(SQLSMALLINT);
break;
case SQL_IS_USMALLINT:
*(SQLUSMALLINT *)ValuePtr = retValues->u.u16Value;
strLen = sizeof(SQLUSMALLINT);
break;
default:
{
if (retValues->u.strPtr != NULL)
{
strLen = strlen(retValues->u.strPtr);
if ((BufferLength <= 0 && BufferLength != SQL_NTS) || (BufferLength % 2 != 0))
{
if (reportError)
pHandle->setDiagRec(DRIVER_ERROR, IDS_HY_090);
rc = SQL_ERROR;
}
else
{
if(strLen > 0) // && BufferLength > 2)
{
translateLengthMax = (BufferLength == SQL_NTS) ? strLen : BufferLength;
if((rc = UTF8ToWChar(retValues->u.strPtr, strLen, (wchar_t *)ValuePtr, translateLengthMax/2,
(int *)(&translateLength), (char *)errorMsg)) != SQL_SUCCESS)
{
if (errorMsg && errorMsg[0] != '\0')
{
if (reportError)
pHandle->setDiagRec(DRIVER_ERROR, IDS_186_DSTODRV_TRUNC, 0, (char *)errorMsg);
}
else
{
if (reportError)
pHandle->setDiagRec(DRIVER_ERROR, IDS_186_DSTODRV_TRUNC);
}
strLen = translateLength * 2;
}
else
strLen = translateLength * 2;
}
else
*((wchar_t *)ValuePtr) = L'\0';
}
}
} //default
break;
}
}
else
{
switch (retValues->dataType)
{
case SQL_IS_POINTER:
strLen = sizeof(SQLPOINTER);
break;
case SQL_IS_INTEGER:
strLen = sizeof(SQLINTEGER);
break;
case SQL_IS_UINTEGER:
strLen = sizeof(SQLUINTEGER);
break;
case SQL_IS_SMALLINT:
strLen = sizeof(SQLSMALLINT);
break;
case SQL_IS_USMALLINT:
strLen = sizeof(SQLUSMALLINT);
break;
default:
if (retValues->u.strPtr != NULL)
strLen = strlen(retValues->u.strPtr);
break;
}
}
if (strLen != DRVR_PENDING)
if (StringLengthPtr != NULL)
*StringLengthPtr = strLen;
return rc;
}
void ScanConnectString(char *InConnectionString, SQLSMALLINT StringLength1, CONNECT_KEYWORD_TREE *KeywordTree)
{
short i;
short iStartPos;
short KeyAttrNo;
short AttrRank;
char delimiter;
BOOL found;
for (i = 0 ; i <= KEY_MAX ; i++)
{
KeywordTree[i].AttrValue = NULL;
KeywordTree[i].AttrLength = 0;
KeywordTree[i].AttrRank = 0;
}
AttrRank = KEY_MAX;
for (i =0; i < StringLength1 ; i++ )
{
// skip leading noise characters; if any
for ( ; i < StringLength1 && ( InConnectionString[i] == ';' || InConnectionString[i] == ' ' ); i++ );
if( i>=StringLength1) break;
// get the key name; is terminated by an '='
for( iStartPos = i; i < StringLength1 && InConnectionString[i] != '=' ; i++ );
if( i>=StringLength1) break;
//
for (KeyAttrNo = 0, found = FALSE; ConnectKeywords[KeyAttrNo] != NULL ; KeyAttrNo++)
{
if (_strnicmp(ConnectKeywords[KeyAttrNo], (const char *)(InConnectionString + iStartPos), (i-iStartPos)) == 0)
{
found = TRUE;
break;
}
}
delimiter = ';';
if (found)
{
if (InConnectionString[i+1] == '{')
delimiter = '}';
}
else
KeyAttrNo = KEY_MAX;
if( delimiter != '}' )
for (iStartPos = i ; i < StringLength1 && InConnectionString[i] != delimiter ; i++ );
else if (KeyAttrNo == KEY_PWD || KeyAttrNo == KEY_SCHEMA || KeyAttrNo == KEY_UID) {
for (iStartPos = i ; i < StringLength1; i++ )
if(InConnectionString[i] == delimiter && InConnectionString[i+1] == ';') break;
}
else {
int level = 0;
for (iStartPos = i ; i < StringLength1; i++ ){
if(InConnectionString[i] == delimiter && --level==0) break;
if(InConnectionString[i] == '{') level++;
}
}
KeywordTree[KeyAttrNo].AttrValue = (char *)(InConnectionString + iStartPos+1); //+1 Skip '='
if( delimiter != '}' )
KeywordTree[KeyAttrNo].AttrLength = i-iStartPos-1; //-1 skip the delimiter
else
KeywordTree[KeyAttrNo].AttrLength = i-iStartPos; //do not skip the delimiter
KeywordTree[KeyAttrNo].AttrRank = AttrRank--;
#if 0
{
char buff[1024];
int length = KeywordTree[KeyAttrNo].AttrLength;
strncpy(buff, KeywordTree[KeyAttrNo].AttrValue, length);
buff[length] = '\0';
}
#endif
}
return;
}
unsigned long getCDefault(SQLSMALLINT SQLDataType, SQLINTEGER ODBCAppVersion, SQLSMALLINT &DataType)
{
short i;
BOOL found = FALSE;
switch (SQLDataType)
{
case SQL_BIGINT:
if (ODBCAppVersion >= SQL_OV_ODBC3)
DataType = SQL_C_SBIGINT;
else
DataType = SQL_C_CHAR;
break;
default:
for (i = 0, found = FALSE; gSQLDatatypeMap[i].conciseType != SQL_DEFAULT ; i++)
{
// Compare with SQL data type given in SQLBindParameter
if (gSQLDatatypeMap[i].conciseType == SQLDataType)
{
found = TRUE;
DataType = gSQLDatatypeMap[i].defaultType;
break;
}
}
if (! found)
return IDS_HY_003;
break;
}
return SQL_SUCCESS;
}
unsigned long getOctetLength(SQLSMALLINT SQLDataType,
SQLINTEGER ODBCAppVersion,
SQLPOINTER DataPtr,
SQLINTEGER StrLen,
SQLSMALLINT &DataType,
SQLINTEGER &OctetLength)
{
unsigned long retCode;
short i;
BOOL found;
switch (DataType)
{
case SQL_C_DEFAULT:
// Get the corresponding C DataType and fall thru
// No Break;
if ((retCode = getCDefault(SQLDataType, ODBCAppVersion, DataType)) != SQL_SUCCESS)
return retCode;
// Note No Break
case SQL_C_CHAR:
case SQL_C_BINARY:
if (StrLen == SQL_NTS)
OctetLength = strlen((const char *)DataPtr);
else
OctetLength = StrLen;
break;
default:
for (i = 0, found = FALSE; gCDatatypeMap[i].conciseType != SQL_C_DEFAULT ; i++)
{
if (gCDatatypeMap[i].conciseType == DataType)
{
found = TRUE;
OctetLength = gCDatatypeMap[i].octetLength;
break;
}
}
if (! found)
return IDS_HY_003;
}
return SQL_SUCCESS;
}
char *rTrim(char *string)
{
char *strPtr;
for (strPtr = string + strlen(string) - 1;
strPtr >= string && (*strPtr == ' ' || *strPtr == '\t') ;
*(strPtr--) = '\0');
return(string);
}
char* trim(char *string)
{
char sep[] = " ";
char *token;
char *assembledStr;
assembledStr = (char*)malloc( strlen(string) + 1);
if (assembledStr == NULL ) return string;
assembledStr[0]=0;
token = strtok( string, sep );
while( token != NULL ) {
strcat(assembledStr, token);
token = strtok( NULL, sep );
if(token != NULL)
strcat(assembledStr, sep);
}
strcpy( string, assembledStr);
free( assembledStr);
return string;
}
char* wmstrim(char *string)
{
char *tmp;
char *p;
for (p = string + strlen(string) - 1; p >= string && isspace(*p); *(p--) = '\0');
tmp = (char*)malloc( strlen(string) + 1);
if (tmp == NULL ) return string;
strcpy(tmp,string);
for (p = tmp; *p != 0 && isspace(*p); p++);
strcpy( string, p);
free( tmp);
return string;
}
char* trimInterval(char *string)
{
char sep[] = " ";
char *token;
char *assembledStr;
assembledStr = (char*)malloc( strlen(string) + 1);
if (assembledStr == NULL ) return string;
assembledStr[0]=0;
token = strtok( string, sep );
if (strcmp(token, "-") == 0) {
strcat(assembledStr, token);
token = strtok( NULL, sep );
}
while( token != NULL ) {
strcat(assembledStr, token);
token = strtok( NULL, sep );
if(token != NULL)
strcat(assembledStr, sep);
}
strcpy( string, assembledStr);
free( assembledStr);
return string;
}
char* trimInterval(char *string, SQLINTEGER length)
{
char sep[] = " ";
char *token;
char *tmpStr, *assembledStr;
// We can use *string, as '\0' will overwrite the null indicator for the next field
// So make a copy of it.
tmpStr = (char*)malloc(length+1);
memset(tmpStr,'\0',length+1);
strncpy(tmpStr, string, length);
assembledStr = (char*)malloc(length + 1);
if (assembledStr == NULL ) return string;
assembledStr[0]=0;
token = strtok( tmpStr, sep );
if (strcmp(token, "-") == 0) {
strcat(assembledStr, token);
token = strtok( NULL, sep );
}
while( token != NULL ) {
strcat(assembledStr, token);
token = strtok( NULL, sep );
if(token != NULL)
strcat(assembledStr, sep);
}
strcpy(string, assembledStr);
free(assembledStr);
free(tmpStr);
return string;
}
char* rSup( char* string )
{
if (*string == 0 ) return string;
if (strchr(string, '.') == NULL) return string;
for(int i=strlen(string)-1; i >= 0; i--)
{
if (string[i] == '0') {
if ( i - 1 >= 0 && string[i-1] == '.') break;
else {
string[i]=0;
continue;
}
}
break;
}
return string;
}
bool use_gcvt(double number, char* string, short size)
{
char *buffer,*temp ;
int length;
temp = _gcvt (number, size, string);
length = strlen(temp);
buffer = (char *) malloc (length + 2);
if (buffer==NULL)
return false;
strcpy(buffer,temp);
if (temp[length-1] == '.')
{
strcpy(buffer,temp);
strcat(buffer,"0");
}
if (temp[0] == '.')
{
strcpy( buffer, "0");
strcat( buffer, temp);
}
strcpy(string,buffer);
free (buffer);
if (strlen(string)>size)
return false;
else
return true;
}
bool double_to_char (double number, int precision, char* string, short size)
{
bool rc = false;
char format[16] = { '\0' };
size_t actualLen = 0;
// make sure any precision of possible double value can be format to the buf.
char buf[MAX_DOUBLE_TO_CHAR_LEN] = { '\0' };
// precision should less than size
precision = precision < size ? precision : size - 1;
// precission should be limit to a reasonable range.
if ((precision < 0) || (precision >(DBL_MANT_DIG - DBL_MIN_EXP))) {
goto fun_exit;
}
// we want to return reasonable value even when caller didn't provide sufficiently buffer.
// here using loop because actualLen may increase even precision decrease when fix-point
// notation to exponential notation. for example:
// for double d = 12345678.9, the caller only provide size=8.
// d will first convert to "1.234568e+07", actualLen == 12. then convert to "1.2e+07".
do {
if (sprintf(format, "%%.%dlg", precision) < 0) {
goto fun_exit;
}
if ((actualLen = sprintf(buf, format, number)) < 0) {
goto fun_exit;
}
if (size > actualLen) {
strcpy(string, buf);
rc = true;
break;
}
else {
precision -= (actualLen - size + 1);
}
} while ((precision >= 0));
fun_exit:
return rc;
}
bool ctoi64(char* string, __int64& out, bool* truncation)
{
int len;
out = 0;
char* buff;
double dTmp;
char *errorCharPtr = NULL;
*truncation = false; // initialize anyway
buff = (char*)malloc(100 + 1);
if (buff == NULL ) return false;
memset(buff,0,100 + 1);
strncpy( buff, string, 100);
trim(buff);
len = strlen(buff);
if (len != (int)strspn(buff, "+-1234567890"))
{
if (len != (int)strspn(buff, "+-1234567890.eE"))
{
free (buff);
return false;
}
else
{
dTmp = strtod(buff, &errorCharPtr);
if (errno == ERANGE || (strlen(errorCharPtr) > 0))
{
free (buff);
return false;
}
sprintf(buff,"%lf",dTmp);
rSup( buff );
char* cptr = strchr(buff,'.');
if (cptr != NULL) // data truncation: JoyJ
{
*cptr = 0;
if ((++cptr != NULL) && (_atoi64(cptr) > 0)) //No truncation if '0's after '.' are truncated.
*truncation = true;
}
len = strlen(buff);
}
}
if (buff[0] == '+')
{
if (len - 1 > 19 )
{
free (buff);
return false;
}
if (len - 1 == 19)
{
if (strcmp( buff, "+9223372036854775807") > 0 )
{
free (buff);
return false;
}
}
}
else if (buff[0] == '-')
{
if (len - 1 > 19 )
{
free (buff);
return false;
}
if (len - 1 == 19)
{
if (strcmp( buff, "-9223372036854775808") > 0 )
{
free (buff);
return false;
}
}
}
else
{
//now there should't be any "+-.eE" in "buff"(other than the first byte): JoyJ
if ((len-1) != (int)strspn(buff+1, "1234567890"))
return false;
if (len > 19 )
{
free (buff);
return false;
}
if (len == 19)
{
if (strcmp( buff, "9223372036854775807") > 0 )
{
free (buff);
return false;
}
}
}
out = _atoi64(buff);
free (buff);
return true;
}
bool ctoi64(char* string, __int64& out)
{
int len;
out = 0;
char* buff;
double dTmp;
char *errorCharPtr;
buff = (char*)malloc(100 + 1);
if (buff == NULL ) return false;
memset(buff,0,100 + 1);
strncpy( buff, string, 100);
trim(buff);
len = strlen(buff);
if (len != (int)strspn(buff, "+-1234567890"))
{
if (len != (int)strspn(buff, "+-1234567890.eE"))
{
free (buff);
return false;
}
else
{
dTmp = strtod(buff, &errorCharPtr);
if (errno == ERANGE )
{
free (buff);
return false;
}
sprintf(buff,"%lf",dTmp);
rSup( buff );
char* cptr = strchr(buff,'.');
if (cptr != NULL) *cptr = 0;
len = strlen(buff);
}
}
if (buff[0] == '+')
{
if (len - 1 > 19 )
{
free (buff);
return false;
}
if (len - 1 == 19)
{
if (strcmp( buff, "+9223372036854775807") > 0 )
{
free (buff);
return false;
}
}
}
else if (buff[0] == '-')
{
if (len - 1 > 19 )
{
free (buff);
return false;
}
if (len - 1 == 19)
{
if (strcmp( buff, "-9223372036854775808") > 0 )
{
free (buff);
return false;
}
}
}
else
{
if (len > 19 )
{
free (buff);
return false;
}
if (len == 19)
{
if (strcmp( buff, "9223372036854775807") > 0 )
{
free (buff);
return false;
}
}
}
out = _atoi64(buff);
free (buff);
return true;
}
BOOL checkDatetimeValue(short *datetime_parts)
{
short DaysArray[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (datetime_parts[1] < 1 || datetime_parts[1] > 12)
return FALSE;
if (datetime_parts[3] < 0 || datetime_parts[3] > 23)
return FALSE;
if (datetime_parts[4] < 0 || datetime_parts[4] > 59)
return FALSE;
if (datetime_parts[5] < 0 || datetime_parts[5] > 59)
return FALSE;
if (datetime_parts[1] == 2)
{
if ((datetime_parts[0] % 4 == 0) && ((datetime_parts[0] % 100 != 0) || (datetime_parts[0] % 400 == 0)))
DaysArray[1] = 29;
else
DaysArray[1] = 28;
}
if (datetime_parts[2] < 1 || datetime_parts[2] > DaysArray[datetime_parts[1]-1])
return FALSE;
return TRUE;
}
__int64 pow(short base, short scale)
{
__int64 retValue = 1;
scale = scale > 18?18:scale;
for(int i = 0; i < scale; i++)
retValue *= 10;
return retValue;
}
BOOL WINAPI DllMain(HANDLE hInst,
DWORD ul_reason_being_called,
LPVOID lpReserved)
{
int error;
WORD wVersionRequested = MAKEWORD(2,0);
WSADATA wsaData;
void* lpszStr;
switch (ul_reason_being_called)
{
case DLL_PROCESS_ATTACH:
if ((error = WSAStartup(wVersionRequested, &wsaData))!=0)
return false;
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )
{
WSACleanup();
return false;
}
gTlsIndex_ErrorBuffer = TlsAlloc();
if (gTlsIndex_ErrorBuffer == TLS_OUT_OF_INDEXES)
return FALSE;
// DisableThreadLibraryCalls((HINSTANCE)hInst);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
if (gTlsIndex_ErrorBuffer != TLS_OUT_OF_INDEXES)
{
lpszStr = TlsGetValue(gTlsIndex_ErrorBuffer);
if (lpszStr != NULL)
HeapFree(GetProcessHeap(), 0, lpszStr);
}
break;
case DLL_PROCESS_DETACH:
WSACleanup();
if (gTlsIndex_ErrorBuffer != TLS_OUT_OF_INDEXES)
{
lpszStr = TlsGetValue(gTlsIndex_ErrorBuffer);
if (lpszStr != NULL)
HeapFree(GetProcessHeap(), 0, lpszStr);
TlsFree(gTlsIndex_ErrorBuffer);
}
break;
default:
break;
}
return 1;
UNREFERENCED_PARAMETER(lpReserved);
}