📄 myclient.cpp
字号:
// 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 + -