📄 sqlapi.cpp
字号:
// SQLAPI.cpp : Defines the entry point for the DLL application.
//
#include <SQLAPI.h>
#include "ISAClient.h"
#include "errmsg.h"
#ifdef SQLAPI_AllClients
#define SQLAPI_odbcClient
#define SQLAPI_oraClient
#define SQLAPI_ssClient
#define SQLAPI_ibClient
#define SQLAPI_sbClient
#define SQLAPI_db2Client
#define SQLAPI_infClient
#define SQLAPI_sybClient
#define SQLAPI_myClient
#define SQLAPI_pgClient
#endif
#ifdef SQLAPI_odbcClient
#include "odbcClient.h"
#endif
#ifdef SQLAPI_oraClient
#include "oraClient.h"
#endif
#ifdef SQLAPI_ssClient
#include "ssClient.h"
#endif
#ifdef SQLAPI_ibClient
#include "ibClient.h"
#endif
#ifdef SQLAPI_sbClient
#include "sbClient.h"
#endif
#ifdef SQLAPI_db2Client
#include "db2Client.h"
#endif
#ifdef SQLAPI_infClient
#include "infClient.h"
#endif
#ifdef SQLAPI_sybClient
#include "sybClient.h"
#endif
#ifdef SQLAPI_myClient
#include "myClient.h"
#endif
#ifdef SQLAPI_pgClient
#include "pgClient.h"
#endif
#include <malloc.h>
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#ifdef LINUX
#include <wchar.h>
#include <wctype.h>
#endif
#ifdef SQLAPI_odbcClient
static IodbcClient odbcClient; // ODBC client
#endif
#ifdef SQLAPI_oraClient
static IoraClient oraClient; // Oracle client
#endif
#ifdef SQLAPI_ssClient
static IssClient ssClient; // Microsoft SQL Server client
#endif
#ifdef SQLAPI_ibClient
static IibClient ibClient; // InterBase client
#endif
#ifdef SQLAPI_sbClient
static IsbClient sbClient; // Centura SqlBase client
#endif
#ifdef SQLAPI_db2Client
static Idb2Client db2Client; // DB2 client
#endif
#ifdef SQLAPI_infClient
static IinfClient infClient; // Informix client
#endif
#ifdef SQLAPI_sybClient
static IsybClient sybClient; // Sybase client
#endif
#ifdef SQLAPI_myClient
static ImyClient myClient; // MySQL client
#endif
#ifdef SQLAPI_pgClient
static IpgClient pgClient; // MySQL client
#endif
static ISAClient *stat_SAClients[] =
{
NULL,
#ifdef SQLAPI_odbcClient
&odbcClient,
#else
NULL,
#endif
#ifdef SQLAPI_oraClient
&oraClient,
#else
NULL,
#endif
#ifdef SQLAPI_ssClient
&ssClient,
#else
NULL,
#endif
#ifdef SQLAPI_ibClient
&ibClient,
#else
NULL,
#endif
#ifdef SQLAPI_sbClient
&sbClient,
#else
NULL,
#endif
#ifdef SQLAPI_db2Client
&db2Client,
#else
NULL,
#endif
#ifdef SQLAPI_infClient
&infClient,
#else
NULL,
#endif
#ifdef SQLAPI_sybClient
&sybClient,
#else
NULL,
#endif
#ifdef SQLAPI_myClient
&myClient,
#else
NULL,
#endif
#ifdef SQLAPI_pgClient
&pgClient
#else
NULL
#endif
};
struct sa_Commands
{
SACommand *pCommand;
ISACursor *pISACursor;
sa_Commands *Next;
};
saLongOrLobWriter_t saDefaultLongOrLobWriter = NULL;
saLongOrLobReader_t saDefaultLongOrLobReader = NULL;
#if !defined(SA_NO_TRIAL)
const char *sTrialText =
"Thank you for trying SQLAPI++ Library.\n"
"\n"
"This version is for evaluation purpose only.\n"
"You can register SQLAPI++ using online registration service.\n"
"\n"
"For additional information visit:\n"
" SQLAPI++ Home (http://www.sqlapi.com)\n"
"For help on using the Library e-mail to:\n"
" howto@sqlapi.com";
const char *sTrialCaption =
"SQLAPI++ Registration Reminder";
static void CheckTrial()
{
static bool bCheckedTrial = false;
if(!bCheckedTrial)
{
#if defined(WIN32) || defined(_WINDOWS)
::MessageBox(NULL,
sTrialText,
sTrialCaption, 0);
bCheckedTrial = true;
#else // never set bCheckedTrial = true; in Linux/Unix
srand((unsigned)time(NULL));
int nRand = rand();
if(nRand % 5 == 0)
SAException::throwUserException(-1, "Trial version exception:\n%s", sTrialText);
printf("%s\n\n", sTrialText);
#endif // defined(WIN32) || defined(_WINDOWS)
}
}
#endif // !defined(SA_NO_TRIAL)
//////////////////////////////////////////////////////////////////////
// SAString Class
//////////////////////////////////////////////////////////////////////
// For an empty string, m_pchData will point here
// (note: avoids special case of checking for NULL m_pchData)
// empty string data (and locked)
static int _saInitData[] = {
0, // pConvertedData
#ifdef SA_UNICODE
0, // nBinaryDataLengthDiff
#endif // SA_UNICODE
-1, // nRefs
0, // nDataLength
0, // nAllocLength
0 // SAChar data[nAllocLength]
};
static SAStringData *_saDataNil = (SAStringData *)&_saInitData;
static const SAChar *_saPchNil = (const SAChar *)(((unsigned char*)&_saInitData)+sizeof(SAStringData));
// special function to make saEmptyString work even during initialization
static const SAString &saGetEmptyString()
{
return *(SAString *)&_saPchNil;
}
#define saEmptyString saGetEmptyString()
void SAString::AllocBuffer(int nLen)
// always allocate one extra character for '\0' termination
// assumes [optimistically] that data length will equal allocation length
{
assert(nLen >= 0);
assert(nLen <= INT_MAX-1); // max size (enough room for 1 extra)
if (nLen == 0)
Init();
else
{
SAStringData *pData;
pData = (SAStringData*)
new unsigned char[sizeof(SAStringData) + (nLen+1)*sizeof(SAChar)];
pData->nAllocLength = nLen;
// start of SAString special
pData->pConvertedData = NULL;
#ifdef SA_UNICODE
pData->nBinaryDataLengthDiff = 0;
#endif // SA_UNICODE
// end of SAString special
pData->nRefs = 1;
pData->data()[nLen] = _SA('\0');
pData->nDataLength = nLen;
m_pchData = pData->data();
}
}
/*static */
void SAString::FreeData(SAStringData *pData)
{
delete [] (unsigned char*)pData->pConvertedData;
delete[] (unsigned char*)pData;
}
//////////////////////////////////////////////////////////////////////////////
// concatenate in place
#ifdef SA_UNICODE
void SAString::ConcatBinaryInPlace(int nSrcLenInBytes, const void *pSrcData)
{
// concatenating an empty string is a no-op!
if (nSrcLenInBytes == 0)
return;
// if a conversion has been made already, it is not valid any more
delete [] (unsigned char*)GetData()->pConvertedData;
GetData()->pConvertedData = NULL;
// if the buffer is too small, or we have a width mis-match, just
// allocate a new buffer (slow but sure)
int nNewLenInBytes = GetBinaryLength() + nSrcLenInBytes;
int nBinaryDataLengthDiff = nNewLenInBytes % sizeof(SAChar);
// allocate at least so many characters that all binary data could be stored (round up if necessary)
int nNewLenInChars = nNewLenInBytes / sizeof(SAChar) + (nBinaryDataLengthDiff? 1 : 0);
if (GetData()->nRefs > 1 || nNewLenInChars > GetData()->nAllocLength)
{
// we have to grow the buffer, use the ConcatCopy routine
SAStringData *pOldData = GetData();
ConcatBinaryCopy(GetBinaryLength(), (const void*)m_pchData, nSrcLenInBytes, pSrcData);
assert(pOldData != NULL);
SAString::Release(pOldData);
}
else
{
// fast concatenation when buffer big enough
memcpy((unsigned char*)m_pchData+GetBinaryLength(), pSrcData, nSrcLenInBytes);
GetData()->nDataLength = nNewLenInChars;
GetData()->nBinaryDataLengthDiff = nBinaryDataLengthDiff;
assert(GetData()->nDataLength <= GetData()->nAllocLength);
m_pchData[GetData()->nDataLength] = _SA('\0');
}
}
#endif // SA_UNICODE
void SAString::ConcatInPlace(int nSrcLen, const SAChar *lpszSrcData)
{
// -- the main routine for += operators
// concatenating an empty string is a no-op!
if (nSrcLen == 0)
return;
// if a conversion has been made already, it is not valid any more
delete [] (unsigned char*)GetData()->pConvertedData;
GetData()->pConvertedData = NULL;
// whether we have binary data or not
// it will no longer be binary after we apply SAChar* concatenation
#ifdef SA_UNICODE
GetData()->nBinaryDataLengthDiff = 0;
#endif
// if the buffer is too small, or we have a width mis-match, just
// allocate a new buffer (slow but sure)
if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
{
// we have to grow the buffer, use the ConcatCopy routine
SAStringData *pOldData = GetData();
ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
assert(pOldData != NULL);
SAString::Release(pOldData);
}
else
{
// fast concatenation when buffer big enough
memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(SAChar));
GetData()->nDataLength += nSrcLen;
assert(GetData()->nDataLength <= GetData()->nAllocLength);
m_pchData[GetData()->nDataLength] = '\0';
}
}
const SAString &SAString::operator+=(const SAChar *lpsz)
{
ConcatInPlace(SafeStrlen(lpsz), lpsz);
return *this;
}
const SAString &SAString::operator+=(SAChar ch)
{
ConcatInPlace(1, &ch);
return *this;
}
#ifdef SA_UNICODE
const SAString &SAString::operator+=(char ch)
{
*this += (SAChar)ch;
return *this;
}
#endif // SA_UNICODE
const SAString& SAString::operator+=(const SAString &string)
{
#ifdef SA_UNICODE
// Under Unicode we should be aware that *this or string (or both)
// can be binary string with length not being multiply of sizeof(SAChar),
// so we should concatinate bytes, not characters
ConcatBinaryInPlace(string.GetBinaryLength(), (const void*)string);
return *this;
#else // !SA_UNICODE
// byte == character in non-Unicode build
ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
return *this;
#endif // !SA_UNICODE
}
///////////////////////////////////////////////////////////////////////////////
// Advanced direct buffer access
SAChar *SAString::GetBuffer(int nMinBufLength)
{
assert(nMinBufLength >= 0);
if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
{
// we have to grow the buffer
SAStringData *pOldData = GetData();
int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
if (nMinBufLength < nOldLen)
nMinBufLength = nOldLen;
AllocBuffer(nMinBufLength);
memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(SAChar));
GetData()->nDataLength = nOldLen;
SAString::Release(pOldData);
}
assert(GetData()->nRefs <= 1);
// return a pointer to the character storage for this string
assert(m_pchData != NULL);
return m_pchData;
}
void SAString::ReleaseBuffer(int nNewLength)
{
CopyBeforeWrite(); // just in case GetBuffer was not called
if (nNewLength == -1)
nNewLength = sa_strlen(m_pchData); // zero terminated
assert(nNewLength <= GetData()->nAllocLength);
GetData()->nDataLength = nNewLength;
m_pchData[nNewLength] = '\0';
#ifdef SA_UNICODE
GetData()->nBinaryDataLengthDiff = 0;
#endif // SA_UNICODE
}
SAChar *SAString::LockBuffer()
{
SAChar *lpsz = GetBuffer(0);
GetData()->nRefs = -1;
return lpsz;
}
void SAString::UnlockBuffer()
{
assert(GetData()->nRefs == -1);
if (GetData() != _saDataNil)
GetData()->nRefs = 1;
}
void SAString::CopyBeforeWrite()
{
if (GetData()->nRefs > 1)
{
SAStringData *pData = GetData();
Release();
AllocBuffer(pData->nDataLength);
memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(SAChar));
}
// start of SAString special
else
{
// if a conversion has been made already, it is not valid any more
delete [] (unsigned char*)GetData()->pConvertedData;
GetData()->pConvertedData = NULL;
#ifdef SA_UNICODE
GetData()->nBinaryDataLengthDiff = 0;
#endif // SA_UNICODE
}
// end of SAString special
assert(GetData()->nRefs <= 1);
}
void SAString::AllocBeforeWrite(int nLen)
{
if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
{
Release();
AllocBuffer(nLen);
}
// start of SAString special
else
{
// if a conversion has been made already, it is not valid any more
delete [] (unsigned char*)GetData()->pConvertedData;
GetData()->pConvertedData = NULL;
#ifdef SA_UNICODE
GetData()->nBinaryDataLengthDiff = 0;
#endif // SA_UNICODE
}
// end of SAString special
assert(GetData()->nRefs <= 1);
}
void SAString::Release()
{
if (GetData() != _saDataNil)
{
assert(GetData()->nRefs != 0);
if(--GetData()->nRefs <= 0)
FreeData(GetData());
Init();
}
}
/*static */
void SAString::Release(SAStringData *pData)
{
if (pData != _saDataNil)
{
assert(pData->nRefs != 0);
if (--pData->nRefs <= 0)
FreeData(pData);
}
}
void SAString::Init()
{
m_pchData = saEmptyString.m_pchData;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
SAStringData *SAString::GetData() const
{
assert(m_pchData != NULL);
return ((SAStringData *)m_pchData)-1;
}
SAString::SAString()
{
Init();
}
SAString::SAString(const SAString &stringSrc)
{
assert(stringSrc.GetData()->nRefs != 0);
if (stringSrc.GetData()->nRefs >= 0)
{
assert(stringSrc.GetData() != _saDataNil);
m_pchData = stringSrc.m_pchData;
++GetData()->nRefs;
}
else
{
Init();
*this = stringSrc; //*this = stringSrc.m_pchData; - not right, will not copy strings with embedded '\0'
}
}
SAString::SAString(const SAChar *lpsz)
{
Init();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -