⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgclient.cpp

📁 通用的数据库中间库
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// 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 + -