📄 pgclient.cpp
字号:
// pgClient.cpp
//
//////////////////////////////////////////////////////////////////////
#include <SQLAPI.h>
#include "pgClient.h"
#include <assert.h>
#include <stdlib.h> // atoi
#include <string.h> // strlen, memcpy
#include <ctype.h>
#include <pgAPI.h>
#include "pgType.h" // Result of the "cat include/catalog/pg_type.h | grep '#define'"
#include "samisc.h"
#include "errmsg.h"
static void Check(PGresult *res)
{
int nErr = 0;
if( !res || !((nErr = g_pgAPI.PQresultStatus(res)) == PGRES_COMMAND_OK
|| nErr == PGRES_TUPLES_OK) )
{
if( res )
throw SAException(SA_RDBMS_API_Error, nErr, -1, "%s", g_pgAPI.PQresultErrorMessage(res));
else
throw SAException(SA_RDBMS_API_Error, nErr, -1, "%s", "Unknown error occured");
}
}
extern long g_nPostgreSQLDLLVersionLoaded;
//////////////////////////////////////////////////////////////////////
// IpgConnection Class
//////////////////////////////////////////////////////////////////////
class IpgConnection : public ISAConnection
{
friend class IpgCursor;
pgConnectionHandles m_handles;
enum {MaxBlobPiece = (unsigned int)4096, MaxLongPiece = (unsigned int)0x7FFFFFFF};
static SADataType_t CnvtNativeToStd(
Oid NativeType,
int Length,
int Mod,
bool bOidAsBlob);
static void CnvtInternalToDateTime(
SADateTime &date_time,
const char *sInternal);
static int second(const char *sSecond);
static int minute(const char *sMinute);
static int hour(const char *sHour);
static int day(const char *sDay);
static int month(const char *sMonth);
static int year(const char *sYear);
static void CnvtDateTimeToInternal(
const SADateTime &date_time,
SAString &sInternal);
static void ParseInternalTime(const char* sTime, int& nHour, int& nMinute, int& nSecond, int& nNanoSecond, int& nZoneHour);
static void ParseInternalDate(const char* sDate, int& nYear, int& nMonth, int& nDay);
static char* byte2string(const void* pByte, int nBufLen);
static void* string2byte(const char* szInputText, int &nOutBufLen);
static SAString EscapeString(const char* szString);
protected:
virtual ~IpgConnection();
public:
IpgConnection(SAConnection *pSAConnection);
virtual void InitializeClient();
virtual void UnInitializeClient();
virtual long GetClientVersion() const;
virtual long GetServerVersion() const;
virtual SAString GetServerVersionString() const;
virtual bool IsConnected() const;
virtual void Connect(
const SAString &sDBString,
const SAString &sUserID,
const SAString &sPassword);
virtual void Disconnect();
virtual void setIsolationLevel(
SAIsolationLevel_t eIsolationLevel);
virtual void setAutoCommit(
SAAutoCommit_t eAutoCommit);
virtual void Commit();
virtual void Rollback();
virtual saAPI *NativeAPI() const;
virtual saConnectionHandles *NativeHandles();
virtual ISACursor *NewCursor(SACommand *m_pCommand);
virtual void CnvtInternalToDateTime(
SADateTime &date_time,
const void *pInternal,
int nInternalSize);
virtual void CnvtInternalToCursor(
SACommand *pCursor,
const void *pInternal);
};
/*static */
SADataType_t IpgConnection::CnvtNativeToStd(
Oid NativeType,
int/* Length*/,
int/* Mod*/,
bool bOidAsBlob)
{
SADataType_t eDataType;
switch(NativeType)
{
case BOOLOID: // BOOLEAN|BOOL
eDataType = SA_dtBool;
break;
case BYTEAOID: // BYTEA - variable-length string, binary values escaped
eDataType = SA_dtLongBinary;
break;
case TEXTOID: // TEXT - variable-length string, no limit specified
eDataType = SA_dtLongChar;
break;
case CHAROID: // CHAR - single character
case BPCHAROID: // BPCHAR - char(length), blank-padded string, fixed storage length
case NAMEOID: // NAME - 31-character type for storing system identifiers
case VARCHAROID: // VARCHAR(?) - varchar(length), non-blank-padded string, variable storage length
eDataType = SA_dtString;
break;
case INT8OID: // INT8|BIGINT - ~18 digit integer, 8-byte storage
case FLOAT4OID: // FLOAT4 - single-precision floating point number, 4-byte storage
case FLOAT8OID: // FLOAT8 - double-precision floating point number, 8-byte storage
case NUMERICOID: // NUMERIC(x,y) - numeric(precision, decimal), arbitrary precision number
case CASHOID: // $d,ddd.cc, money
eDataType = SA_dtDouble;
break;
case INT2OID: // INT2|SMALLINT - -32 thousand to 32 thousand, 2-byte storage
eDataType = SA_dtShort;
break;
case INT4OID: // INT4|INTEGER - -2 billion to 2 billion integer, 4-byte storage
case XIDOID: // transaction id
case CIDOID: // command identifier type, sequence in transaction id
eDataType = SA_dtLong;
break;
case OIDOID: // OID - object identifier(oid), maximum 4 billion
eDataType = bOidAsBlob ? SA_dtBLob:SA_dtLong;
break;
case ABSTIMEOID: // ABSTIME - absolute, limited-range date and time (Unix system time)
case DATEOID: // DATE - ANSI SQL date
case TIMEOID: // TIME - hh:mm:ss, ANSI SQL time
case TIMESTAMPOID: // TIMESTAMP - date and time
case TIMETZOID: // TIME WITH TIMEZONE - hh:mm:ss, ANSI SQL time
eDataType = SA_dtDateTime;
break;
case 705: // Unknown
case INT2VECTOROID: // array of INDEX_MAX_KEYS int2 integers, used in system tables
case REGPROCOID: // registered procedure
case TIDOID: // (Block, offset), physical location of tuple
case OIDVECTOROID: // array of INDEX_MAX_KEYS oids, used in system tables
case POINTOID: // geometric point '(x, y)'
case LSEGOID: // geometric line segment '(pt1,pt2)'
case PATHOID: // geometric path '(pt1,...)'
case BOXOID: // geometric box '(lower left,upper right)'
case POLYGONOID: // geometric polygon '(pt1,...)'
case LINEOID: // geometric line '(pt1,pt2)'
// TODO: ???
case RELTIMEOID: // relative, limited-range time interval (Unix delta time)
case TINTERVALOID: // (abstime,abstime), time interval
case INTERVALOID: // @ <number> <units>, time interval
case CIRCLEOID: // geometric circle '(center,radius)'
// locale specific
case INETOID: // IP address/netmask, host address, netmask optional
case CIDROID: // network IP address/netmask, network address
case 829: // XX:XX:XX:XX:XX:XX, MAC address
case ZPBITOID: // BIT(?) - fixed-length bit string
case VARBITOID: // BIT VARING(?) - variable-length bit string
eDataType = SA_dtString;
break;
default:
assert(false);
eDataType = SA_dtString;
}
return eDataType;
}
//////////////////////////////////////////////////////////////////////
// IpgConnection Construction/Destruction
//////////////////////////////////////////////////////////////////////
IpgConnection::IpgConnection(
SAConnection *pSAConnection) : ISAConnection(pSAConnection)
{
}
IpgConnection::~IpgConnection()
{
}
//////////////////////////////////////////////////////////////////////
// ImyClient Class
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IpgClient::IpgClient()
{
}
IpgClient::~IpgClient()
{
}
ISAConnection *IpgClient::QueryConnectionInterface(
SAConnection *pSAConnection)
{
return new IpgConnection(pSAConnection);
}
//////////////////////////////////////////////////////////////////////
// IpgCursor Class
//////////////////////////////////////////////////////////////////////
class IpgCursor : public ISACursor
{
pgCommandHandles m_handles;
// private handles
int m_nCurrentTuple;
int m_nTuplesCount;
bool m_bResultSetCanBe;
bool m_bOpened;
void ConvertPGTupleToFields(int nTuple);
void BindBLob(SAParam &Param, SAString &sBoundStmt);
void BindLongChar(SAParam &Param, SAString &sBoundStmt);
void BindLongBinary(SAParam &Param, SAString &sBoundStmt);
void ReadBLOB(
ValueType_t eValueType,
SAValueRead &vr,
void *pValue,
unsigned int nFieldBufSize,
saLongOrLobReader_t fnReader,
unsigned int nReaderWantedPieceSize,
void *pAddlData);
void ReadLongBinary(
ValueType_t eValueType,
SAValueRead &vr,
void *pValue,
unsigned int nFieldBufSize,
saLongOrLobReader_t fnReader,
unsigned int nReaderWantedPieceSize,
void *pAddlData);
void ReadLongChar(
ValueType_t eValueType,
SAValueRead &vr,
void *pValue,
unsigned int nFieldBufSize,
saLongOrLobReader_t fnReader,
unsigned int nReaderWantedPieceSize,
void *pAddlData);
public:
IpgCursor(
IpgConnection *pImyConnection,
SACommand *pCommand);
virtual ~IpgCursor();
protected:
virtual bool IsOpened();
virtual void Open();
virtual void Close();
// prepare statement (also convert to native format if needed)
virtual void Prepare(
const SAString &sStmt,
SACommandType_t eCmdType,
int nPlaceHolderCount,
saPlaceHolder **ppPlaceHolders);
// executes statement (also binds parameters if needed)
virtual void Execute(
int nPlaceHolderCount,
saPlaceHolder **ppPlaceHolders);
// cleans up after execute if needed, so the statement can be reexecuted
virtual void UnExecute();
virtual void Cancel();
virtual bool ResultSetExists();
virtual void DescribeFields(
DescribeFields_cb_t fn);
virtual void SetSelectBuffers();
virtual void SetFieldBuffer(
int nCol, // 1-based
void *pInd,
unsigned int nIndSize,
void *pSize,
unsigned int nSizeSize,
void *pValue,
unsigned int nValueSize);
virtual bool FetchNext();
virtual long GetRowsAffected();
virtual void ReadLongOrLOB(
ValueType_t eValueType,
SAValueRead &vr,
void *pValue,
unsigned int nFieldBufSize,
saLongOrLobReader_t fnReader,
unsigned int nReaderWantedPieceSize,
void *pAddlData);
virtual void DescribeParamSP();
virtual bool FetchParamsNext();
virtual saCommandHandles *NativeHandles();
};
//////////////////////////////////////////////////////////////////////
// IpgCursor Construction/Destruction
//////////////////////////////////////////////////////////////////////
IpgCursor::IpgCursor(
IpgConnection *pIpgConnection,
SACommand *pCommand) :
ISACursor(pIpgConnection, pCommand)
{
m_bOpened = false;
m_bResultSetCanBe = false;
m_nCurrentTuple = 0;
m_nTuplesCount = 0;
}
/*virtual */
IpgCursor::~IpgCursor()
{
}
//////////////////////////////////////////////////////////////////////
// IpgConnection implementation
//////////////////////////////////////////////////////////////////////
/*virtual */
void IpgConnection::InitializeClient()
{
::AddPostgreSQLSupport(m_pSAConnection);
}
/*virtual */
void IpgConnection::UnInitializeClient()
{
::ReleasePostgreSQLSupport();
}
/*virtual */
void IpgConnection::CnvtInternalToDateTime(
SADateTime &/*date_time*/,
const void * /*pInternal*/,
int/* nInternalSize*/)
{
assert(false); // we do not use ISA... convertors
}
/*static */
int IpgConnection::second(const char *sSecond)
{
char s[3] = "SS";
strncpy(s, sSecond, 2);
int nSecond = atoi(s);
assert(nSecond >= 0 && nSecond <= 59);
return nSecond;
}
/*static */
int IpgConnection::minute(const char *sMinute)
{
char s[3] = "MM";
strncpy(s, sMinute, 2);
int nMinute = atoi(s);
assert(nMinute >= 0 && nMinute <= 59);
return nMinute;
}
/*static */
int IpgConnection::hour(const char *sHour)
{
char s[3] = "HH";
strncpy(s, sHour, 2);
int nHour = atoi(s);
assert(nHour >= 0 && nHour <= 23);
return nHour;
}
/*static */
int IpgConnection::day(const char *sDay)
{
char s[3] = "DD";
strncpy(s, sDay, 2);
int nDay = atoi(s);
assert(nDay >= 0 && nDay <= 31);
return nDay;
}
/*static */
int IpgConnection::month(const char *sMonth)
{
char s[3] = "MM";
strncpy(s, sMonth, 2);
int nMonth = atoi(s);
assert(nMonth >= 0 && nMonth <= 12);
return nMonth;
}
/*static */
int IpgConnection::year(const char *sYear)
{
char s[5] = "YYYY";
strncpy(s, sYear, 4);
int nYear = atoi(s);
assert(nYear >= 0 && nYear <= 9999);
return nYear;
}
/*static*/
void IpgConnection::ParseInternalTime(const char* sTime, int& nHour, int& nMinute, int& nSecond, int& nNanoSecond, int& nZoneHour)
{
// 07:37:16-08, 07:37:16.00 PST, 07:37:16 PST
assert( sTime[2] == ':' );
assert( sTime[5] == ':' );
nHour = hour(sTime);
nMinute = minute(sTime+3);
nSecond = second(sTime+6);
char *sTZ = (char*)(sTime+8);
if( sTZ[0] == '.' ) // 07:37:16.00
{
char s[3] = "SS";
strncpy(s, sTZ+1, 2);
nNanoSecond = atoi(s) * 10000000;
sTZ = sTZ+3;
}
if( sTZ[0] == ' ' ) // 07:37:16 PST
{
// TODO: PST like timezone
assert(false);
}
else if( sTZ[0] == '-' || sTZ[0] == '+' ) // 07:37:16-08
nZoneHour = atoi(sTZ);
}
/*static*/
void IpgConnection::ParseInternalDate(const char* sDate, int& nYear, int& nMonth, int& nDay)
{
// 1997-12-17, 12/17/1997, 17.12.1997
if( sDate[4] == '-' ) // 1997-12-17
{
assert(sDate[7] == '-');
nYear = year(sDate);
nMonth = month(sDate+5);
nDay = day(sDate+8);
}
else if( sDate[2] == '/' ) // 12/17/1997
{
assert(sDate[5] == '/');
// TODO: Date format may be MM/DD/YYYY(American) or DD/MM/YYYY(European).
// Can't detect it correctly in some cases. But...
if( atoi(sDate) > 12 ) // European
{
nDay = day(sDate);
nMonth = month(sDate+3);
nYear = year(sDate+6);
}
else // American
{
nMonth = month(sDate);
nDay = day(sDate+3);
nYear = year(sDate+6);
}
}
else if( sDate[2] == '.' ) // 17.12.1997
{
assert(sDate[5] == '.');
nDay = day(sDate);
nMonth = month(sDate+3);
nYear = year(sDate+6);
}
else
assert(false);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -