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

📄 myclient.cpp

📁 通用的数据库中间库
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// myClient.cpp
//
//////////////////////////////////////////////////////////////////////

#include <SQLAPI.h>
#include "myClient.h"

#include <assert.h>
#include <stdlib.h>	// atoi
#include <string.h>	// strlen, memcpy

#include <myAPI.h>

#include "samisc.h"
#include "errmsg.h"

static void Check(MYSQL *mysql)
{
	assert(mysql);

	unsigned int nErr = g_myAPI.mysql_errno(mysql);
	if(nErr)
		throw SAException(
			SA_RDBMS_API_Error,
			nErr, 
			-1,
			g_myAPI.mysql_error(mysql));
}

//////////////////////////////////////////////////////////////////////
// ImyConnection Class
//////////////////////////////////////////////////////////////////////

class ImyConnection : public ISAConnection
{
	friend class ImyCursor;

	myConnectionHandles m_handles;

	enum {MaxLongPiece = (unsigned int)0x7FFFFFFF};

	static SADataType_t CnvtNativeToStd(
		enum enum_field_types type,
		unsigned int length,
		unsigned int decimals,
		unsigned int flags);
	static void CnvtInternalToDateTime(
		SADateTime &date_time,
		const char *sInternal);
	static int second(const char *sSecond);
	static int minute(const char *sMinute);
	static int shortHour(const char *sHour);
	static int longHour(const char *sHour);
	static int day(const char *sDay);
	static int month(const char *sMonth);
	static int longYear(const char *sYear);
	static int shortYear(const char *sYear);
	static void CnvtDateTimeToInternal(
		const SADateTime &date_time,
		SAString &sInternal);

protected:
	virtual ~ImyConnection();

public:
	ImyConnection(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 ImyConnection::CnvtNativeToStd(
	enum enum_field_types type,
	unsigned int length,
	unsigned int decimals,
	unsigned int flags)
{
	SADataType_t eDataType;

	switch(type)
	{
	case FIELD_TYPE_TINY:	// TINYINT field
		eDataType = SA_dtShort;
		break;
	case FIELD_TYPE_SHORT:	// SMALLINT field
		eDataType = SA_dtShort;
		break;
	case FIELD_TYPE_LONG:	// INTEGER field
		eDataType = SA_dtLong;
		break;
	case FIELD_TYPE_INT24:	// MEDIUMINT field
		eDataType = SA_dtLong;
		break;
	case FIELD_TYPE_LONGLONG:	// BIGINT field
		eDataType = SA_dtDouble;
		break;
	case FIELD_TYPE_DECIMAL:	// DECIMAL or NUMERIC field
		if(decimals == 0)
		{	
			unsigned int nPrec = length - 1;	// space for '-' sign
			// check for exact type
			if(nPrec <= 5)
				eDataType = SA_dtShort;
			else if(nPrec <= 10)
				eDataType = SA_dtLong;
			else
				eDataType = SA_dtDouble;
		}
		else
			eDataType = SA_dtDouble;
		break;
	case FIELD_TYPE_FLOAT:	// FLOAT field
		eDataType = SA_dtDouble;
		break;
	case FIELD_TYPE_DOUBLE:	// DOUBLE or REAL field
		eDataType = SA_dtDouble;
		break;
	case FIELD_TYPE_TIMESTAMP:	// TIMESTAMP field
		eDataType = SA_dtDateTime;
		break;
	case FIELD_TYPE_DATE:	// DATE field
	case FIELD_TYPE_NEWDATE:
		eDataType = SA_dtDateTime;
		break;
	case FIELD_TYPE_TIME:	// TIME field
		eDataType = SA_dtDateTime;
		break;
	case FIELD_TYPE_DATETIME:	// DATETIME field
		eDataType = SA_dtDateTime;
		break;
	case FIELD_TYPE_YEAR:	// YEAR field
		eDataType = SA_dtShort;
		break;
	case FIELD_TYPE_STRING:	// String (CHAR or VARCHAR) field, also SET and ENUM
	case FIELD_TYPE_VAR_STRING:
		if(flags & BINARY_FLAG)
			eDataType = SA_dtBytes;
		else
			eDataType = SA_dtString;
		break;
	case FIELD_TYPE_TINY_BLOB:
	case FIELD_TYPE_MEDIUM_BLOB:
	case FIELD_TYPE_LONG_BLOB:
	case FIELD_TYPE_BLOB:	// BLOB or TEXT field (use max_length to determine the maximum length)
		if(flags & BINARY_FLAG)
			eDataType = SA_dtLongBinary;
		else
			eDataType = SA_dtLongChar;
		break;
	case FIELD_TYPE_SET:	// SET field
		eDataType = SA_dtString;
		break;
	case FIELD_TYPE_ENUM:	// ENUM field
		eDataType = SA_dtString;
		break;
	case FIELD_TYPE_NULL:	// NULL-type field
		eDataType = SA_dtString;
		break;

	default:
		assert(false);
		eDataType = SA_dtString;
	}

	return eDataType;
}

//////////////////////////////////////////////////////////////////////
// ImyConnection Construction/Destruction
//////////////////////////////////////////////////////////////////////

ImyConnection::ImyConnection(
	SAConnection *pSAConnection) : ISAConnection(pSAConnection)
{
}

ImyConnection::~ImyConnection()
{
}

//////////////////////////////////////////////////////////////////////
// ImyClient Class
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

ImyClient::ImyClient()
{

}

ImyClient::~ImyClient()
{

}

ISAConnection *ImyClient::QueryConnectionInterface(
	SAConnection *pSAConnection)
{
	return new ImyConnection(pSAConnection);
}

//////////////////////////////////////////////////////////////////////
// ImyCursor Class
//////////////////////////////////////////////////////////////////////

class ImyCursor : public ISACursor
{
	myCommandHandles	m_handles;

	// private handles
	MYSQL_ROW m_mysql_row;
	unsigned long *m_lengths;
	bool m_bResultSetCanBe;

	SAString	m_sOriginalStmst;
	bool		m_bOpened;

	void ConvertMySQLRowToFields();
	SAString MySQLEscapeString(const char *sFrom, int nLen);
	SAString MySQLEscapeString(const SAString &sValue);
	void BindBLob(SAParam &Param, SAString &sBoundStmt);
	void BindText(SAParam &Param, SAString &sBoundStmt);

public:
	ImyCursor(
		ImyConnection *pImyConnection,
		SACommand *pCommand);
	virtual ~ImyCursor();

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 saCommandHandles *NativeHandles();
};

//////////////////////////////////////////////////////////////////////
// ImyCursor Construction/Destruction
//////////////////////////////////////////////////////////////////////

ImyCursor::ImyCursor(
	ImyConnection *pImyConnection,
	SACommand *pCommand) :
	ISACursor(pImyConnection, pCommand)
{
	m_bOpened = false;
	m_bResultSetCanBe = false;
}

/*virtual */
ImyCursor::~ImyCursor()
{
}


//////////////////////////////////////////////////////////////////////
// ImyConnection implementation
//////////////////////////////////////////////////////////////////////

/*virtual */
void ImyConnection::InitializeClient()
{
	::AddMySQLSupport();
}

/*virtual */
void ImyConnection::UnInitializeClient()
{
	::ReleaseMySQLSupport();
}

/*virtual */
void ImyConnection::CnvtInternalToDateTime(
	SADateTime &/*date_time*/,
	const void * /*pInternal*/,
	int/*	nInternalSize*/)
{
	assert(false);	// we do not use ISA... convertors
}

/*static */
int ImyConnection::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 ImyConnection::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 ImyConnection::shortHour(const char *sHour)
{
	char s[3] = "HH";
	strncpy(s, sHour, 2);

	int nHour = atoi(s);
	assert(nHour >= 0 && nHour <= 23);

	return nHour;
}

/*static */
int ImyConnection::longHour(const char *sHour)
{
	char s[4] = "HHH";
	strncpy(s, sHour, 3);

	int nHour = atoi(s);
	assert(nHour >= 0 && nHour <= 999);

	return nHour;
}

/*static */
int ImyConnection::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 ImyConnection::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 ImyConnection::longYear(const char *sYear)
{
	char s[5] = "YYYY";
	strncpy(s, sYear, 4);

	int nYear = atoi(s);
	assert(nYear >= 0 && nYear <= 9999);

	return nYear;
}

/*static */
int ImyConnection::shortYear(const char *sYear)
{
	char s[3] = "YY";
	strncpy(s, sYear, 2);

	int nYear = atoi(s);
	assert(nYear >= 0 && nYear <= 99);
	if(nYear <= 69)
		nYear += 2000;
	else
		nYear += 1900;

	return nYear;
}

/*static */
void ImyConnection::CnvtInternalToDateTime(
	SADateTime &date_time,
	const char *sInternal)
{
	// first initialize to default date/time values
	SADateTime dt;
	int nYear = dt.GetYear();
	int nMonth = 1;
	int nDay = 1;
	int nHour = 0;
	int nMinute = 0;
	int nSecond = 0;

	// then try to fill what we can
	int nLen = ::strlen(sInternal);

	// also check if date is invalid
	bool bTimeStamp = strchr(sInternal, '-') == NULL && strchr(sInternal, ':') == NULL;

	if(!bTimeStamp)
	{
		switch(nLen)
		{
		case 19:	//	"YYYY-MM-DD HH:MM:SS", DATETIME
			assert(sInternal[10] == ' ');
			assert(sInternal[13] == ':');
			assert(sInternal[16] == ':');
			nSecond = second(sInternal+17);
			nMinute = minute(sInternal+14);
			nHour = shortHour(sInternal+11);
		case 10:	//	"YYYY-MM-DD", DATE
			assert(sInternal[4] == '-');
			assert(sInternal[7] == '-');
			nDay = day(sInternal+8);
			nMonth = month(sInternal+5);
			nYear = longYear(sInternal);
			break;
		case 8:	//	"HH:MM:SS", TIME
			assert(sInternal[2] == ':');
			assert(sInternal[5] == ':');
			nSecond = second(sInternal+6);
			nMinute = minute(sInternal+3);
			nHour = shortHour(sInternal);
			break;
		case 9:	//	"HHH:MM:SS", TIME
			assert(sInternal[3] == ':');
			assert(sInternal[6] == ':');
			nSecond = second(sInternal+7);
			nMinute = minute(sInternal+4);
			nHour = longHour(sInternal);
			break;
		default:
			assert(false);
		}
	}
	else
	{
		// TIMESTAMP
		switch(nLen)
		{
		case 14:	//	"YYYYMMDDHHMMSS"
			nSecond = second(sInternal+12);
			nMinute = minute(sInternal+10);
			nHour = shortHour(sInternal+8);
		case 8:	//	"YYYYMMDD"
			nDay = day(sInternal+6);
			nMonth = month(sInternal+4);
			nYear = longYear(sInternal);
			break;
		case 12:	//	"YYMMDDHHMMSS";
			nSecond = second(sInternal+10);
		case 10:	//	"YYMMDDHHMM"
			nMinute = minute(sInternal+8);
			nHour = shortHour(sInternal+6);
		case 6:	//	"YYMMDD"
			nDay = day(sInternal+4);
		case 4:	//	"YYMM"
			nMonth = month(sInternal+2);
		case 2:	//	"YY";
			nYear = shortYear(sInternal);
			break;
		default:
			assert(false);
		}
	}

	if(nMonth != 0 && nDay != 0 && nHour <=23)	// simple test for validness
		date_time = SADateTime(nYear, nMonth, nDay, nHour, nMinute, nSecond);
	else
		date_time = dt;

	// no milli, micro or nano seconds in MySQL now
	date_time.Fraction() = 0;
}

/*static */
void ImyConnection::CnvtDateTimeToInternal(
	const SADateTime &date_time,
	SAString &sInternal)
{
	// format should be YYYY-MM-DD HH:MM:SS.fraction
	sInternal.Format("%.4d-%.2d-%.2d %.2d:%.2d:%.2d.%.9ld",
		date_time.GetYear(), date_time.GetMonth(), date_time.GetDay(),
		date_time.GetHour(), date_time.GetMinute(), date_time.GetSecond(),
		date_time.Fraction());
}

/*virtual */
void ImyConnection::CnvtInternalToCursor(
	SACommand * /*pCursor*/,
	const void * /*pInternal*/)
{
	assert(false);
}

/*virtual */
long ImyConnection::GetClientVersion() const
{
	char *sClientVer = g_myAPI.mysql_get_client_info();
	char *sPoint;
	short nMajor = (short)strtol(sClientVer, &sPoint, 10);
	assert(*sPoint == '.');
	sPoint++;
	short nMinor = (short)strtol(sPoint, &sPoint, 10);
	return nMinor + (nMajor << 16);
}

/*virtual */
long ImyConnection::GetServerVersion() const
{
	char *sServerVer = g_myAPI.mysql_get_server_info(m_handles.mysql);
	char *sPoint;
	short nMajor = (short)strtol(sServerVer, &sPoint, 10);
	assert(*sPoint == '.');
	sPoint++;
	short nMinor = (short)strtol(sPoint, &sPoint, 10);
	return nMinor + (nMajor << 16);
}

/*virtual */
SAString ImyConnection::GetServerVersionString() const
{
	return  SAString(g_myAPI.mysql_get_server_info(m_handles.mysql));
}

/*virtual */
bool ImyConnection::IsConnected() const
{
	return m_handles.mysql != NULL;
}

/*virtual */
void ImyConnection::Connect(
	const SAString &sDBString,
	const SAString &sUserID,
	const SAString &sPassword)
{
	assert(m_handles.mysql == NULL);

	// dbstring as: [server_name][@][dbname]
	// server_name as: hostname[:port], or unix_socket path
	// for connection to server without dbname use 'server_name@'

	unsigned int port = 0;
	SAString sServerName, sDatabase, sHost, sUnixSocket;

	int iPos = sDBString.Find('@');
	if(iPos >= 0) // Database is present in connection string
	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -