📄 sybclient.cpp
字号:
{
// no preparing in OpenClient
// all is beeing done in Execute()
}
// process command batch or stored proc results
// stop if all commands processed or result set encounted
void IsybCursor::ProcessBatchUntilEndOrResultSet()
{
bool bParamResult = false;
bool bStatusResult = false;
CS_RETCODE rcd;
CS_INT res_type;
while((rcd = ((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_results(
m_handles.m_command, &res_type))) == CS_SUCCEED)
{
bool bResultSet = false;
switch(res_type)
{
case CS_CMD_SUCCEED: // Command returning no rows completed sucessfully
break;
case CS_CMD_DONE: // This means we're done with one result set
((IsybConnection *)m_pISAConnection)->Check(g_sybAPI.ct_res_info(
m_handles.m_command,
CS_ROW_COUNT,
&m_nRowsAffected, CS_UNUSED, NULL));
break;
case CS_CMD_FAIL: // This means that the server encountered an error while processing our command
((IsybConnection *)m_pISAConnection)->Check(CS_FAIL);
break;
case CS_ROW_RESULT:
bResultSet = true;
break;
case CS_STATUS_RESULT:
FetchStatusResult();
bStatusResult = true;
break;
case CS_PARAM_RESULT:
FetchParamResult();
bParamResult = true;
break;
case CS_COMPUTE_RESULT:
assert(false);
break;
default:
assert(false);
}
if(bResultSet)
{
m_bResultsPending = true;
return;
}
}
// We've finished processing results. Let's check the
// return value of ct_results() to see if everything
// went ok.
switch(rcd)
{
case CS_END_RESULTS: // Everything went fine
m_bResultsPending = false;
if(bStatusResult || bParamResult)
ConvertOutputParams();
break;
case CS_FAIL: // Something went wrong
((IsybConnection*)m_pISAConnection)->Check(rcd);
break;
default: // We got an unexpected return value
assert(false);
}
}
/*virtual */
void IsybCursor::UnExecute()
{
CheckAndCancelPendingResults();
}
/*virtual */
void IsybCursor::Execute(
int nPlaceHolderCount,
saPlaceHolder **ppPlaceHolders)
{
// some kind of Prepare() first
if(m_pCommand->CommandType() == SA_CmdStoredProc)
{
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_command(
m_handles.m_command,
CS_RPC_CMD,
(CS_CHAR*)(const char*)m_pCommand->CommandText(),
CS_NULLTERM,
CS_NO_RECOMPILE));
}
// always bind, even if no parameters
// because Bind() does ct_command for non SP
Bind(nPlaceHolderCount, ppPlaceHolders);
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_send(
m_handles.m_command));
try
{
ProcessBatchUntilEndOrResultSet();
}
catch(SAException &) // clean up after ct_send
{
// cancel any results pending
assert(!m_bResultsPending);
g_sybAPI.ct_cancel(NULL, m_handles.m_command, CS_CANCEL_ALL);
throw;
}
}
/*virtual */
void IsybCursor::Cancel()
{
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_cancel(
NULL, m_handles.m_command, CS_CANCEL_ALL));
}
void IsybCursor::BindImage(SAParam &Param, SAString *pValue)
{
*pValue += "0x";
unsigned int nActualWrite;
SAPieceType_t ePieceType = SA_FirstPiece;
void *pBuf;
while((nActualWrite = Param.InvokeWriter(
ePieceType, 0xffff, pBuf)) != 0)
{
*pValue += ((IsybConnection*)m_pISAConnection)->ConvertToString(
CS_IMAGE_TYPE, (CS_VOID*)pBuf, nActualWrite);
if(ePieceType == SA_LastPiece)
break;
}
}
void IsybCursor::BindText(SAParam &Param, SAString *pValue)
{
*pValue += "'";
unsigned int nActualWrite;
SAPieceType_t ePieceType = SA_FirstPiece;
void *pBuf;
while((nActualWrite = Param.InvokeWriter(
ePieceType, 0xffff, pBuf)) != 0)
{
SAString sTemp((const char *)pBuf, nActualWrite);
sTemp.Replace("'", "''");
*pValue += sTemp;
if(ePieceType == SA_LastPiece)
break;
}
*pValue += "'";
}
void IsybCursor::Bind(
int nPlaceHolderCount,
saPlaceHolder** ppPlaceHolders)
{
// always alloc bind buffer, even if we will not use it
// 'exec SP' to work
AllocBindBuffer(sizeof(CS_SMALLINT), sizeof(CS_INT));
SAString sOriginalStmst = m_pCommand->CommandText();
if(m_pCommand->CommandType() == SA_CmdSQLStmt)
{
// we will bind directly to command buffer
CancelPendingResults();
SAString sBoundStmt;
// change ':' param markers to bound values
unsigned int nPos = 0;
for(int i = 0; i < nPlaceHolderCount; ++i)
{
SAParam &Param = *ppPlaceHolders[i]->getParam();
sBoundStmt += sOriginalStmst.Mid(nPos, ppPlaceHolders[i]->getStart()-nPos);
SAString sBoundValue;
SAString sTemp;
CS_BIT bitTemp;
if(Param.isNull())
{
sBoundStmt += "NULL";
}
else
{
switch(Param.DataType())
{
case SA_dtUnknown:
throw SAException(SA_Library_Error, -1, -1, IDS_UNKNOWN_PARAMETER_TYPE, (const char*)Param.Name());
case SA_dtBool:
bitTemp = (CS_BIT)Param.setAsBool();
sBoundValue = ((IsybConnection*)m_pISAConnection)->ConvertToString(
CS_BIT_TYPE, (CS_VOID*)&bitTemp, sizeof(CS_BIT));
break;
case SA_dtShort:
sBoundValue = ((IsybConnection*)m_pISAConnection)->ConvertToString(
CS_SMALLINT_TYPE, (CS_VOID*)&Param.setAsShort(), sizeof(short));
break;
case SA_dtLong:
sBoundValue = ((IsybConnection*)m_pISAConnection)->ConvertToString(
CS_INT_TYPE, (CS_VOID*)&Param.setAsLong(), sizeof(long));
break;
case SA_dtDouble:
sBoundValue = ((IsybConnection*)m_pISAConnection)->ConvertToString(
CS_FLOAT_TYPE, (CS_VOID*)&Param.setAsDouble(), sizeof(double));
break;
case SA_dtDateTime:
IsybConnection::CnvtDateTimeToInternal(
Param.setAsDateTime(), sTemp);
sBoundValue = "'";
sBoundValue += sTemp;
sBoundValue += "'";
break;
case SA_dtString:
sTemp = Param.asString();
sTemp.Replace("'", "''");
sBoundValue = "'";
sBoundValue += sTemp;
sBoundValue += "'";
break;
case SA_dtBytes:
sBoundValue = "0x";
sBoundValue += ((IsybConnection*)m_pISAConnection)->ConvertToString(
CS_BINARY_TYPE, (CS_VOID*)(const char*)Param.asBytes(), Param.asBytes().GetLength());
break;
case SA_dtLongBinary:
case SA_dtBLob:
BindImage(Param, &sBoundStmt);
break;
case SA_dtLongChar:
case SA_dtCLob:
BindText(Param, &sBoundStmt);
break;
default:
assert(false);
}
switch(Param.DataType())
{
case SA_dtLongBinary:
case SA_dtLongChar:
case SA_dtBLob:
case SA_dtCLob:
break; // was already written
default:
sBoundStmt += sBoundValue;
}
}
nPos = ppPlaceHolders[i]->getEnd() + 1;
}
// copy tail
if(nPos < strlen(sOriginalStmst))
sBoundStmt += sOriginalStmst.Mid(nPos);
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_command(
m_handles.m_command,
CS_LANG_CMD, (CS_CHAR*)(const char*)sBoundStmt, CS_NULLTERM,
CS_UNUSED));
}
else
{
assert(m_pCommand->CommandType() == SA_CmdStoredProc);
void *pBuf = m_pParamBuffer;
for(int i = 0; i < m_pCommand->ParamCount(); ++i)
{
SAParam &Param = m_pCommand->ParamByIndex(i);
void *pInd;
void *pSize;
unsigned int nDataBufSize;
void *pValue;
IncParamBuffer(pBuf, pInd, pSize, nDataBufSize, pValue);
if(Param.ParamDirType() == SA_ParamReturn)
continue;
assert(isInputParam(Param)); // all params can be input in ASE and ASA
SAString sName = "@";
sName += Param.Name();
SADataType_t eDataType = Param.DataType();
CS_INT type = (CS_INT)CnvtStdToNative(eDataType);
unsigned int nInputBufSize = InputBufferSize(Param);
assert(nInputBufSize <= nDataBufSize);
CS_SMALLINT &indicator = *(CS_SMALLINT*)pInd;
CS_INT &datalen = *(CS_INT*)pSize;
CS_VOID *data;
if(Param.isNull())
{
indicator = -1;
datalen = CS_UNUSED;
data = NULL;
}
else
{
indicator = 0;
datalen = (CS_INT)nInputBufSize;
data = (CS_VOID*)pValue;
}
if(!Param.isNull())
{
switch(eDataType)
{
case SA_dtUnknown:
throw SAException(SA_Library_Error, -1, -1, IDS_UNKNOWN_PARAMETER_TYPE, (const char*)Param.Name());
case SA_dtBool:
assert(nInputBufSize == sizeof(CS_BIT));
*(CS_BIT*)data = (CS_BIT)Param.asBool();
break;
case SA_dtShort:
assert(nInputBufSize == sizeof(short));
*(short*)data = Param.asShort();
break;
case SA_dtLong:
assert(nInputBufSize == sizeof(long));
*(long*)data = Param.asLong();
break;
case SA_dtDouble:
assert(nInputBufSize == sizeof(double));
*(double*)data = Param.asDouble();
break;
case SA_dtDateTime:
assert(nInputBufSize == sizeof(CS_DATETIME)); // Sybase internal date/time representation
((IsybConnection*)m_pISAConnection)->CnvtDateTimeToInternal(
Param.asDateTime(),
(CS_DATETIME*)data);
break;
case SA_dtString:
assert((int)nInputBufSize == Param.asString().GetLength());
memcpy(data, (const char*)Param.asString(), nInputBufSize);
break;
case SA_dtBytes:
assert((int)nInputBufSize == Param.asBytes().GetLength());
memcpy(data, (const char*)Param.asBytes(), nInputBufSize);
break;
case SA_dtLongBinary:
case SA_dtBLob:
case SA_dtLongChar:
case SA_dtCLob:
if(Param.m_fnWriter != saDefaultLongOrLobWriter) // use internal buffer as temp
{
Param.m_pString->Empty();
unsigned int nActualWrite;
SAPieceType_t ePieceType = SA_FirstPiece;
void *pBuf;
while((nActualWrite = Param.InvokeWriter(
ePieceType, 0xffff, pBuf)) != 0)
{
(*Param.m_pString) += SAString((const char*)pBuf, nActualWrite);
if(ePieceType == SA_LastPiece)
break;
}
}
pValue = (void*)(const char*)(*Param.m_pString);
datalen = (CS_INT)Param.m_pString->GetLength();
break;
default:
assert(false);
}
}
CS_DATAFMT df;
strcpy(df.name, sName);
df.namelen = sName.GetLength();
df.datatype = type;
df.maxlength = (CS_INT)nDataBufSize;
df.status = isOutputParam(Param)? CS_RETURN : CS_INPUTVALUE;
df.locale = NULL;
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_param(
m_handles.m_command,
&df,
(CS_VOID*)pValue,
datalen,
indicator));
}
}
}
/*virtual */
bool IsybCursor::ResultSetExists()
{
return m_bResultsPending;
}
/*virtual */
void IsybCursor::DescribeFields(
DescribeFields_cb_t fn)
{
CS_INT nNumData;
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_res_info(
m_handles.m_command,
CS_NUMDATA,
&nNumData,
CS_UNUSED,
NULL));
for(CS_INT iField = 1; iField <= nNumData; ++iField)
{
CS_DATAFMT df;
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_describe(
m_handles.m_command,
(CS_INT)iField,
&df));
(m_pCommand->*fn)(
SAString(df.name, df.namelen),
CnvtNativeToStd(
df.datatype, 0,
df.maxlength,
df.precision,
df.scale),
(int)df.datatype,
df.maxlength,
df.precision,
df.scale,
(df.status & CS_CANBENULL) == 0);
}
}
/*virtual */
long IsybCursor::GetRowsAffected()
{
return m_nRowsAffected;
}
void IsybCursor::ct_bind_Buffer(
int nCol, // 1-based
void *pInd,
unsigned int nIndSize,
void *pSize,
unsigned int nSizeSize,
void *pValue,
unsigned int nValueSize,
SADataType_t eDataType,
SAString sName,
CS_INT count)
{
assert(nIndSize == sizeof(CS_SMALLINT));
if(nIndSize != sizeof(CS_SMALLINT))
return;
assert(nSizeSize == sizeof(CS_INT));
if(nSizeSize != sizeof(CS_INT))
return;
CS_DATAFMT datafmt;
datafmt.datatype = (CS_INT)CnvtStdToNative(eDataType);
datafmt.count = count;
datafmt.format = CS_FMT_UNUSED;
datafmt.maxlength = nValueSize;
datafmt.scale = CS_SRC_VALUE;
datafmt.precision = CS_SRC_VALUE;
datafmt.locale = NULL;
bool bLong = false;
switch(eDataType)
{
case SA_dtUnknown:
throw SAException(SA_Library_Error, -1, -1, IDS_UNKNOWN_COLUMN_TYPE, (const char*)sName);
case SA_dtBool:
assert(datafmt.maxlength == (CS_INT)sizeof(CS_BIT));
break;
case SA_dtShort:
assert(datafmt.maxlength == (CS_INT)sizeof(short));
break;
case SA_dtLong:
assert(datafmt.maxlength == (CS_INT)sizeof(long));
break;
case SA_dtDouble:
assert(datafmt.maxlength == (CS_INT)sizeof(double));
break;
case SA_dtDateTime:
assert(datafmt.maxlength == (CS_INT)sizeof(CS_DATETIME));
break;
case SA_dtString:
break;
case SA_dtBytes:
break;
case SA_dtLongBinary:
case SA_dtLongChar:
assert(datafmt.maxlength == 0);
bLong = true;
break;
default:
assert(false); // unknown type
}
if(!bLong)
{
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_bind(
m_handles.m_command,
nCol,
&datafmt,
(CS_VOID*)pValue,
(CS_INT*)pSize,
(CS_SMALLINT*)pInd));
}
}
/*virtual */
void IsybCursor::SetFieldBuffer(
int nCol, // 1-based
void *pInd,
unsigned int nIndSize,
void *pSize,
unsigned int nSizeSize,
void *pValue,
unsigned int nValueSize)
{
SAField &Field = m_pCommand->Field(nCol);
ct_bind_Buffer(
nCol,
pInd, nIndSize,
pSize, nSizeSize,
pValue, nValueSize,
Field.FieldType(), Field.Name(),
m_cRowsToPrefetch);
}
/*virtual */
void IsybCursor::SetSelectBuffers()
{
SAString sOption = m_pCommand->Option(
"PreFetchRows");
if(!sOption.IsEmpty())
{
int cLongs = FieldCount(4, SA_dtLongBinary, SA_dtLongChar, SA_dtBLob, SA_dtCLob);
if(cLongs) // do not use bulk fetch if there are text or image columns
m_cRowsToPrefetch = 1;
else
m_cRowsToPrefetch = atol(sOption);
}
else
m_cRowsToPrefetch = 1;
m_cRowsObtained = 0;
m_cRowCurrent = 0;
// use default helpers
AllocSelectBuffer(sizeof(CS_SMALLINT), sizeof(CS_INT), m_cRowsToPrefetch);
}
/*virtual */
bool IsybCursor::IndicatorIsNull(
int nPos, // 1-based, can be field or param pos
SAValueRead &vr,
ValueType_t eValueType,
void *pInd, unsigned int nIndSize,
void *pSize, unsigned int nSizeSize,
unsigned int &nRealSize,
int nBulkReadingBufPos) const
{
if(!isLongOrLob(vr.DataType()))
return ISACursor::IndicatorIsNull(
nPos, vr, eValueType,
pInd, nIndSize,
pSize, nSizeSize,
nRealSize,
nBulkReadingBufPos);
char pBuf[1];
CS_RETCODE rcd = ((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_get_data(
m_handles.m_command,
nPos,
pBuf, 0,
NULL));
if(rcd == CS_END_ITEM || rcd == CS_END_DATA)
return true;
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -