📄 ibclient.cpp
字号:
&blob_handle,
sizeof(blob_items), blob_items,
sizeof(blob_info), blob_info), m_StatusVector);
int i = 0;
unsigned long nBlobSize = 0; // unknown
while(blob_info[i] != isc_info_end)
{
char item = blob_info[i];
++i;
ISC_LONG item_length = g_ibAPI.isc_vax_integer(&blob_info[i], 2); i += 2;
if(item == isc_info_blob_total_length)
{
nBlobSize = g_ibAPI.isc_vax_integer(&blob_info[i], (short)item_length);
break;
}
i += item_length;
}
// Read and process nReaderWantedPieceSize bytes at a time.
unsigned char* pBuf;
unsigned int nPieceSize = vr.PrepareReader(
nBlobSize,
IibConnection::MaxBlobPiece,
pBuf,
fnReader,
nReaderWantedPieceSize,
pAddlData);
assert(nPieceSize <= IibConnection::MaxBlobPiece);
unsigned int nCnvtPieceSize = nPieceSize;
// InterBase can return pieces of less size than asked,
// so we might need buffering
SABufferConverter BufferConverter;
ISADataConverter *pIConverter = &BufferConverter;
// read all the BLOB data by calling isc_get_segment() repeatedly to get each BLOB
// segment and its length
SAPieceType_t ePieceType = SA_FirstPiece;
unsigned long nTotalRead = 0;
unsigned long nTotalPassedToReader = 0;
do
{
if(nBlobSize) // known
nPieceSize = sa_min(nPieceSize, nBlobSize - nTotalRead);
unsigned short actual_seg_length;
ISC_STATUS status = g_ibAPI.isc_get_segment(
m_StatusVector,
&blob_handle,
&actual_seg_length, // length of segment read
(unsigned short)nPieceSize, // length of segment buffer
(char*)pBuf); // segment buffer
if(status != 0 && m_StatusVector[1] != isc_segment && m_StatusVector[1] != isc_segstr_eof)
IibConnection::Check(status, m_StatusVector);
assert(!(m_StatusVector[1] == isc_segstr_eof) || (actual_seg_length == 0));
nTotalRead += actual_seg_length;
if(nBlobSize) // known
assert(nTotalRead <= nBlobSize);
if(nBlobSize) // known
{
if(nTotalRead == nBlobSize)
{
if(ePieceType == SA_NextPiece)
ePieceType = SA_LastPiece;
else // the whole BLob was read in one piece
{
assert(ePieceType == SA_FirstPiece);
ePieceType = SA_OnePiece;
}
}
}
else
{
if(m_StatusVector[1] == isc_segstr_eof)
{
if(ePieceType == SA_NextPiece)
ePieceType = SA_LastPiece;
else // the whole Long was read in one piece
{
assert(ePieceType == SA_FirstPiece);
ePieceType = SA_OnePiece;
}
}
}
pIConverter->PutStream(pBuf, actual_seg_length, ePieceType);
unsigned int nCnvtSize;
SAPieceType_t eCnvtPieceType;
// smart while: initialize nCnvtPieceSize before calling pIConverter->GetStream
while(nCnvtPieceSize = (nBlobSize? // known
sa_min(nCnvtPieceSize, nBlobSize - nTotalPassedToReader) : nCnvtPieceSize),
pIConverter->GetStream(pBuf, nCnvtPieceSize, nCnvtSize, eCnvtPieceType))
{
vr.InvokeReader(eCnvtPieceType, pBuf, nCnvtSize);
nTotalPassedToReader += nCnvtSize;
if(nBlobSize) // known
nCnvtPieceSize = sa_min(nCnvtPieceSize, nBlobSize - nTotalPassedToReader);
}
if(ePieceType == SA_FirstPiece)
ePieceType = SA_NextPiece;
}
while(ePieceType != SA_OnePiece && ePieceType != SA_LastPiece);
assert(pIConverter->IsEmpty());
}
catch(SAException &) // try to clean-up
{
g_ibAPI.isc_close_blob(m_StatusVector, &blob_handle);
throw;
}
// close the Blob
IibConnection::Check(g_ibAPI.isc_close_blob(
m_StatusVector, &blob_handle), m_StatusVector);
}
/*virtual */
unsigned int IibCursor::InputBufferSize(
const SAParam &Param) const
{
if(!Param.isNull())
{
switch(Param.DataType())
{
case SA_dtBool:
// there is no "native" boolean type in InterBase,
// so treat boolean as SQL_SHORT in InterBase
return sizeof(short);
case SA_dtDateTime:
return sizeof(ISC_TIMESTAMP);
case SA_dtLongBinary:
case SA_dtLongChar:
case SA_dtBLob:
case SA_dtCLob:
return sizeof(ISC_QUAD);
default:
break;
}
}
return ISACursor::InputBufferSize(Param);
}
XSQLDA *IibCursor::AllocXSQLDA(short nVars)
{
int nSize = XSQLDA_LENGTH(nVars);
XSQLDA *pXSQLDA = (XSQLDA *)malloc(nSize);
memset(pXSQLDA, 0, nSize);
pXSQLDA->version = SQLDA_VERSION1;
pXSQLDA->sqln = nVars;
pXSQLDA->sqld = nVars;
return pXSQLDA;
}
void IibCursor::DestroyXSQLDA(XSQLDA *&pXSQLDA)
{
if(pXSQLDA == NULL)
return;
free(pXSQLDA);
pXSQLDA = NULL;
}
/*virtual */
bool IibCursor::IsOpened()
{
return m_handles.m_stmt_handle != NULL;
}
/*virtual */
void IibCursor::Open()
{
assert(m_handles.m_stmt_handle == NULL);
IibConnection::Check(g_ibAPI.isc_dsql_allocate_statement(
m_StatusVector,
&((IibConnection*)m_pISAConnection)->m_handles.m_db_handle,
&m_handles.m_stmt_handle), m_StatusVector);
assert(m_handles.m_stmt_handle != NULL);
}
/*virtual */
void IibCursor::Close()
{
assert(m_handles.m_stmt_handle != NULL);
IibConnection::Check(g_ibAPI.isc_dsql_free_statement(
m_StatusVector,
&m_handles.m_stmt_handle,
DSQL_drop), m_StatusVector);
assert(m_handles.m_stmt_handle == NULL);
}
/*virtual */
ISACursor *IibConnection::NewCursor(SACommand *m_pCommand)
{
return new IibCursor(this, m_pCommand);
}
/*virtual */
void IibCursor::Prepare(
const SAString &sCmd,
SACommandType_t eCmdType,
int nPlaceHolderCount,
saPlaceHolder **ppPlaceHolders)
{
// replace bind variables with '?' place holder
SAString sStmtIB;
int nPos = 0;
int i;
// these counts can be overiden in case of a stored proc
short nInputParamCount = 0;
short nOutputParamCount = 0;
switch(eCmdType)
{
case SA_CmdSQLStmt:
for(i = 0; i < nPlaceHolderCount; ++i)
{
sStmtIB += sCmd.Mid(nPos, ppPlaceHolders[i]->getStart()-nPos);
sStmtIB += "?";
nPos = ppPlaceHolders[i]->getEnd() + 1;
}
// copy tail
if(nPos < sCmd.GetLength())
sStmtIB += sCmd.Mid(nPos);
break;
case SA_CmdStoredProc:
sStmtIB = "Execute Procedure ";
sStmtIB += sCmd;
for(i = 0; i < m_pCommand->ParamCount(); ++i)
{
SAParam &Param = m_pCommand->ParamByIndex(i);
if(Param.ParamDirType() == SA_ParamInput
|| Param.ParamDirType() == SA_ParamInputOutput)
{
if(++nInputParamCount > 1)
sStmtIB += " ,?";
else
sStmtIB += " ?";
}
if(Param.ParamDirType() == SA_ParamOutput
|| Param.ParamDirType() == SA_ParamInputOutput)
++nOutputParamCount;
}
break;
default:
assert(false);
}
DestroyXSQLDA(m_pOutXSQLDA);
if(nOutputParamCount)
m_pOutXSQLDA = AllocXSQLDA(nOutputParamCount);
IibConnection::Check(g_ibAPI.isc_dsql_prepare(
m_StatusVector,
&((IibConnection*)m_pISAConnection)->m_handles.m_tr_handle,
&m_handles.m_stmt_handle,
0,
(char*)(const char*)sStmtIB,
SQLDialect(), m_pOutXSQLDA), m_StatusVector);
}
/*virtual */
void IibCursor::UnExecute()
{
if(m_bResultSet)
closeResultSet();
}
void IibCursor::BindBlob(ISC_QUAD &BlobID, SAParam &Param)
{
BlobID.gds_quad_high = 0;
BlobID.gds_quad_low = 0;
isc_blob_handle blob_handle = NULL; // set handle to NULL before using it
IibConnection::Check(g_ibAPI.isc_create_blob(
m_StatusVector,
&((IibConnection*)m_pISAConnection)->m_handles.m_db_handle,
&((IibConnection*)m_pISAConnection)->m_handles.m_tr_handle,
&blob_handle, &BlobID), m_StatusVector);
unsigned int nActualWrite;
SAPieceType_t ePieceType = SA_FirstPiece;
void *pBuf;
while((nActualWrite = Param.InvokeWriter(
ePieceType,
IibConnection::MaxBlobPiece, pBuf)) != 0)
{
IibConnection::Check(g_ibAPI.isc_put_segment(
m_StatusVector, &blob_handle,
(unsigned short)nActualWrite, (char*)pBuf), m_StatusVector);
if(ePieceType == SA_LastPiece)
break;
}
// Close the Blob
IibConnection::Check(g_ibAPI.isc_close_blob(
m_StatusVector,
&blob_handle), m_StatusVector);
assert(blob_handle == NULL);
}
void IibCursor::Bind(
int nPlaceHolderCount,
saPlaceHolder** ppPlaceHolders)
{
// we should bind for every place holder ('?') associated with input or input/output param
short nInputCount = ParamDirCount(
nPlaceHolderCount, ppPlaceHolders, 1, SA_ParamInput);
short nOutputCount = ParamDirCount(
nPlaceHolderCount, ppPlaceHolders, 1, SA_ParamOutput);
assert(nInputCount + nOutputCount == nPlaceHolderCount);
if(nInputCount + nOutputCount != nPlaceHolderCount)
return;
AllocBindBuffer(nPlaceHolderCount, ppPlaceHolders, sizeof(short), sizeof(short));
void *pBuf = m_pParamBuffer;
DestroyXSQLDA(m_pInXSQLDA);
m_pInXSQLDA = AllocXSQLDA(nInputCount);
assert(!nOutputCount || (nOutputCount == m_pOutXSQLDA->sqld));
assert(!nOutputCount || (nOutputCount == m_pOutXSQLDA->sqln));
int nInput = 0;
int nOutput = 0;
for(int i = 0; i < nPlaceHolderCount; ++i)
{
SAParam &Param = *ppPlaceHolders[i]->getParam();
void *pNull;
void *pSize;
unsigned int nDataBufSize;
void *pValue;
IncParamBuffer(pBuf, pNull, pSize, nDataBufSize, pValue);
if(Param.ParamDirType() == SA_ParamInput)
{
short &sqltype = m_pInXSQLDA->sqlvar[nInput].sqltype;
short &sqlsubtype = m_pInXSQLDA->sqlvar[nInput].sqlsubtype;
short *&sqlind = m_pInXSQLDA->sqlvar[nInput].sqlind;
short &sqllen = m_pInXSQLDA->sqlvar[nInput].sqllen;
char *&sqldata = m_pInXSQLDA->sqlvar[nInput].sqldata;
assert(sqlind == NULL);
assert(sqldata == NULL);
sqldata = (char*)pValue;
sqllen = (short)nDataBufSize;
if(Param.isNull())
{
sqlind = (short*)pNull;
sqltype = SQL_TEXT+1; // some type should be set
assert(sqllen == 0);
*sqlind = -1;
}
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:
// there is no "native" boolean type in InterBase,
// so treat boolean as SQL_SHORT in InterBase
sqltype = SQL_SHORT;
assert(sqllen == sizeof(short));
*(short*)sqldata = (short)Param.asBool();
break;
case SA_dtShort:
sqltype = SQL_SHORT;
assert(sqllen == sizeof(short));
*(short*)sqldata = Param.asShort();
break;
case SA_dtLong:
sqltype = SQL_LONG;
assert(sqllen == sizeof(long));
*(long*)sqldata = Param.asLong();
break;
case SA_dtDouble:
sqltype = SQL_DOUBLE;
assert(sqllen == sizeof(double));
*(double*)sqldata = Param.asDouble();
break;
case SA_dtDateTime:
sqltype = SQL_DATE;
assert(sqllen == sizeof(ISC_QUAD));
IibConnection::CnvtDateTimeToInternal(
Param.asDateTime(), *(ISC_QUAD*)sqldata);
break;
case SA_dtString:
sqltype = SQL_TEXT;
assert(sqllen == Param.asString().GetLength());
memcpy(sqldata, (const char*)Param.asString(), sqllen);
break;
case SA_dtBytes:
sqltype = SQL_TEXT;
assert(sqllen == Param.asBytes().GetLength());
memcpy(sqldata, (const char*)Param.asBytes(), sqllen);
break;
case SA_dtLongBinary:
case SA_dtBLob:
sqltype = SQL_BLOB;
sqlsubtype = 0; // binary
assert(sqllen == sizeof(ISC_QUAD));
BindBlob(*(ISC_QUAD*)sqldata, Param);
break;
case SA_dtLongChar:
case SA_dtCLob:
sqltype = SQL_BLOB;
sqlsubtype = 1; // text
assert(sqllen == sizeof(ISC_QUAD));
BindBlob(*(ISC_QUAD*)sqldata, Param);
break;
default:
assert(false);
}
}
++nInput;
}
else
{
assert(Param.ParamDirType() == SA_ParamOutput);
short &sqltype = m_pOutXSQLDA->sqlvar[nOutput].sqltype;
short *&sqlind = m_pOutXSQLDA->sqlvar[nOutput].sqlind;
short &sqllen = m_pOutXSQLDA->sqlvar[nOutput].sqllen;
char *&sqldata = m_pOutXSQLDA->sqlvar[nOutput].sqldata;
assert(sqlind == NULL);
assert(sqldata == NULL);
assert((sqltype & 1) != 0);
sqlind = (short*)pNull;
if((sqltype & ~1) == SQL_VARYING)
sqldata = (char*)pSize;
else
sqldata = (char*)pValue;
if((sqltype & ~1) == SQL_FLOAT)
{
assert(sqllen == sizeof(float));
// coerce to double
sqltype &= (~SQL_FLOAT);
sqltype |= SQL_DOUBLE;
sqllen = sizeof(double);
}
assert(sqllen == Param.ParamSize());
++nOutput;
}
}
}
/*virtual */
void IibCursor::Execute(
int nPlaceHolderCount,
saPlaceHolder **ppPlaceHolders)
{
if(nPlaceHolderCount)
Bind(nPlaceHolderCount, ppPlaceHolders);
XSQLDA *pOutXSQLDA =
m_pCommand->CommandType() == SA_CmdStoredProc? m_pOutXSQLDA : NULL;
IibConnection::Check(g_ibAPI.isc_dsql_execute2(
m_StatusVector,
&((IibConnection*)m_pISAConnection)->m_handles.m_tr_handle,
&m_handles.m_stmt_handle,
1,
m_pInXSQLDA,
pOutXSQLDA), m_StatusVector);
m_bResultSet = ResultSetExists();
if(readStmtType() == isc_info_sql_stmt_exec_procedure && m_pOutXSQLDA)
ConvertOutputParams();
}
/*virtual */
void IibCursor::Cancel()
{
}
ISC_LONG IibCursor::readStmtType()
{
char type_item[1];
char res_buffer[8];
ISC_LONG nLength;
type_item[0] = isc_info_sql_stmt_type;
IibConnection::Check(g_ibAPI.isc_dsql_sql_info(
m_StatusVector,
&m_handles.m_stmt_handle,
sizeof(type_item)/sizeof(char), type_item,
sizeof(res_buffer)/sizeof(char), res_buffer), m_StatusVector);
if(res_buffer[0] == isc_info_sql_stmt_type)
{
nLength = g_ibAPI.isc_vax_integer(&res_buffer[1], 2);
return g_ibAPI.isc_vax_integer(&res_buffer[3], (short)nLength);
}
return 0;
}
void IibCursor::closeResultSet()
{
assert(m_bResultSet);
IibConnection::Check(g_ibAPI.isc_dsql_free_statement(
m_StatusVector,
&m_handles.m_stmt_handle,
DSQL_close), m_StatusVector);
m_bResultSet = false;
DestroyXSQLDA(m_pOutXSQLDA);
}
/*virtual */
bool IibCursor::ResultSetExists()
{
switch(readStmtType())
{
case isc_info_sql_stmt_select:
case isc_info_sql_stmt_select_for_upd:
return true;
case isc_info_sql_stmt_insert:
return false;
case isc_info_sql_stmt_update:
return false;
case isc_info_sql_stmt_delete:
return false;
case isc_info_sql_stmt_ddl:
return false;
case isc_info_sql_stmt_get_segment:
case isc_info_sql_stmt_put_segment:
case isc_info_sql_stmt_exec_procedure:
case isc_info_sql_stmt_start_trans:
case isc_info_sql_stmt_commit:
case isc_info_sql_stmt_rollback:
case isc_info_sql_stmt_set_generator:
return false;
}
return false;
}
/*virtual */
SADataType_t IibCursor::CnvtNativeToStd(
int nNativeType,
int nNativeSubType,
int/* nSize*/,
int/* nPrec*/,
int/* nScale*/) const
{
switch(nNativeType & ~1)
{
case SQL_ARRAY:
return SA_dtBLob;
case SQL_BLOB:
if(nNativeSubType == 1)
return SA_dtCLob;
else
return SA_dtBLob;
case SQL_TEXT:
return SA_dtString;
case SQL_SHORT:
return SA_dtShort;
case SQL_LONG:
return SA_dtLong;
case SQL_FLOAT:
return SA_dtDouble;
case SQL_DOUBLE:
return SA_dtDouble;
case SQL_VARYING:
return SA_dtString;
case SQL_TYPE_DATE:
return SA_dtDateTime;
case SQL_TYPE_TIME:
return SA_dtDateTime;
case SQL_TIMESTAMP:
return SA_dtDateTime;
default:
assert(false); // unknown type
}
return SA_dtUnknown;
}
/*virtual */
void IibCursor::DescribeFields(
DescribeFields_cb_t fn)
{
short cFields = 1;
DestroyXSQLDA(m_pOutXSQLDA);
m_pOutXSQLDA = AllocXSQLDA(cFields);
IibConnection::Check(g_ibAPI.isc_dsql_describe(
m_StatusVector,
&m_handles.m_stmt_handle, 1, m_pOutXSQLDA), m_StatusVector);
if(m_pOutXSQLDA->sqld > m_pOutXSQLDA->sqln)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -