📄 ibclient.cpp
字号:
cFields = m_pOutXSQLDA->sqld;
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);
assert(m_pOutXSQLDA->sqld == cFields);
}
for(int iField = 0; iField < cFields; ++iField)
{
XSQLVAR &var = m_pOutXSQLDA->sqlvar[iField];
int nFieldPrecision;
switch(var.sqltype & ~1)
{
case SQL_ARRAY:
nFieldPrecision = 0;
break;
case SQL_BLOB:
nFieldPrecision = 0;
break;
case SQL_TEXT:
nFieldPrecision = var.sqllen;
break;
case SQL_SHORT:
if(var.sqlscale != 0) // coerce to double
{
var.sqltype &= (~SQL_SHORT);
var.sqltype |= SQL_DOUBLE;
var.sqllen = sizeof(double);
nFieldPrecision = 15;
}
else
nFieldPrecision = 5;
break;
case SQL_LONG:
if(var.sqlscale != 0) // coerce to double
{
var.sqltype &= (~SQL_LONG);
var.sqltype |= SQL_DOUBLE;
var.sqllen = sizeof(double);
nFieldPrecision = 15;
}
else
nFieldPrecision = 10;
break;
case SQL_INT64:
// coerce to double
var.sqltype &= (~SQL_INT64);
var.sqltype |= SQL_DOUBLE;
var.sqllen = sizeof(double);
nFieldPrecision = 15;
break;
case SQL_FLOAT:
// coerce to double
var.sqltype &= (~SQL_FLOAT);
var.sqltype |= SQL_DOUBLE;
var.sqllen = sizeof(double);
nFieldPrecision = 15;
break;
case SQL_DOUBLE:
nFieldPrecision = 15;
break;
case SQL_VARYING:
nFieldPrecision = var.sqllen;
break;
case SQL_TYPE_DATE:
// coerce to TIMESTAMP
var.sqltype &= (~SQL_TYPE_DATE);
var.sqltype |= SQL_TIMESTAMP;
var.sqllen = sizeof(ISC_TIMESTAMP);
nFieldPrecision = var.sqllen;
break;
case SQL_TYPE_TIME:
// coerce to TIMESTAMP
var.sqltype &= (~SQL_TYPE_DATE);
var.sqltype |= SQL_TIMESTAMP;
var.sqllen = sizeof(ISC_TIMESTAMP);
nFieldPrecision = var.sqllen;
break;
case SQL_TIMESTAMP:
nFieldPrecision = var.sqllen;
break;
case SQL_D_FLOAT:
case SQL_QUAD:
default:
nFieldPrecision = 0;
assert(false); // unknown type
}
(m_pCommand->*fn)(
SAString(var.aliasname, var.aliasname_length),
CnvtNativeToStd(var.sqltype, var.sqlsubtype, var.sqllen, nFieldPrecision, var.sqlscale),
(int)var.sqltype,
var.sqllen,
var.sqlscale,
nFieldPrecision,
!(var.sqltype & 1));
}
}
/*
bool IibCursor::DescribeField(
unsigned int nField, // 1-based
SAString &sName,
SADataType_t &eFieldType,
int &nNativeType,
int &nFieldSize,
int &nFieldPrecision,
int &nFieldScale,
bool &bFieldRequired)
{
assert(nField == 1 || m_pOutXSQLDA != NULL);
if(nField == 1)
{
short nFields = 1;
DestroyXSQLDA(m_pOutXSQLDA);
m_pOutXSQLDA = AllocXSQLDA(nFields);
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)
{
nFields = m_pOutXSQLDA->sqld;
DestroyXSQLDA(m_pOutXSQLDA);
m_pOutXSQLDA = AllocXSQLDA(nFields);
IibConnection::Check(g_ibAPI.isc_dsql_describe(
m_StatusVector,
&m_handles.m_stmt_handle, 1, m_pOutXSQLDA), m_StatusVector);
assert(m_pOutXSQLDA->sqld == nFields);
}
}
if((unsigned int)m_pOutXSQLDA->sqld < nField)
return false;
XSQLVAR &var = m_pOutXSQLDA->sqlvar[nField-1];
sName = SAString(var.aliasname, var.aliasname_length);
switch(var.sqltype & ~1)
{
case SQL_ARRAY:
nFieldPrecision = 0;
break;
case SQL_BLOB:
nFieldPrecision = 0;
break;
case SQL_TEXT:
nFieldPrecision = var.sqllen;
break;
case SQL_SHORT:
if(var.sqlscale != 0) // coerce to double
{
var.sqltype &= (~SQL_SHORT);
var.sqltype |= SQL_DOUBLE;
var.sqllen = sizeof(double);
nFieldPrecision = 15;
}
else
nFieldPrecision = 5;
break;
case SQL_LONG:
if(var.sqlscale != 0) // coerce to double
{
var.sqltype &= (~SQL_LONG);
var.sqltype |= SQL_DOUBLE;
var.sqllen = sizeof(double);
nFieldPrecision = 15;
}
else
nFieldPrecision = 10;
break;
case SQL_INT64:
// coerce to double
var.sqltype &= (~SQL_INT64);
var.sqltype |= SQL_DOUBLE;
var.sqllen = sizeof(double);
nFieldPrecision = 15;
break;
case SQL_FLOAT:
// coerce to double
var.sqltype &= (~SQL_FLOAT);
var.sqltype |= SQL_DOUBLE;
var.sqllen = sizeof(double);
nFieldPrecision = 15;
break;
case SQL_DOUBLE:
nFieldPrecision = 15;
break;
case SQL_VARYING:
nFieldPrecision = var.sqllen;
break;
case SQL_TYPE_DATE:
// coerce to TIMESTAMP
var.sqltype &= (~SQL_TYPE_DATE);
var.sqltype |= SQL_TIMESTAMP;
var.sqllen = sizeof(ISC_TIMESTAMP);
nFieldPrecision = var.sqllen;
break;
case SQL_TYPE_TIME:
// coerce to TIMESTAMP
var.sqltype &= (~SQL_TYPE_DATE);
var.sqltype |= SQL_TIMESTAMP;
var.sqllen = sizeof(ISC_TIMESTAMP);
nFieldPrecision = var.sqllen;
break;
case SQL_TIMESTAMP:
nFieldPrecision = var.sqllen;
break;
case SQL_D_FLOAT:
case SQL_QUAD:
default:
assert(false); // unknown type
}
eFieldType = CnvtNativeToStd(
var.sqltype, var.sqlsubtype, var.sqllen, nFieldPrecision, var.sqlscale);
nNativeType = (int)var.sqltype;
nFieldSize = var.sqllen;
nFieldScale = var.sqlscale;
bFieldRequired = !(var.sqltype & 1);
return true;
}
*/
/*virtual */
long IibCursor::GetRowsAffected()
{
char type_item[1];
char res_buffer[1048];
type_item[0] = isc_info_sql_records;
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_records)
{
switch(readStmtType())
{
case isc_info_sql_stmt_update:
return g_ibAPI.isc_vax_integer(&res_buffer[6], 2);
case isc_info_sql_stmt_delete:
return g_ibAPI.isc_vax_integer(&res_buffer[13], 2);
case isc_info_sql_stmt_insert:
return g_ibAPI.isc_vax_integer(&res_buffer[27], 2);
}
}
return -1;
}
/*virtual */
unsigned int IibCursor::OutputBufferSize(
SADataType_t eDataType,
unsigned int nDataSize) const
{
switch(eDataType)
{
case SA_dtDateTime:
return sizeof(ISC_TIMESTAMP);
case SA_dtBLob:
case SA_dtCLob:
return sizeof(ISC_QUAD);
default:
break;
}
return ISACursor::OutputBufferSize(eDataType, nDataSize);
}
/*virtual */
void IibCursor::SetFieldBuffer(
int nCol, // 1-based
void *pInd,
unsigned int nIndSize,
void * /*pSize*/,
unsigned int nSizeSize,
void *pValue,
unsigned int nValueSize)
{
assert(m_pOutXSQLDA != NULL); // SetSelectBuffers should always be called after DescribeFields
assert(nIndSize == sizeof(short));
if(nIndSize != sizeof(short))
return;
assert(nSizeSize == sizeof(short));
if(nSizeSize != sizeof(short))
return;
short &sqltype = m_pOutXSQLDA->sqlvar[nCol-1].sqltype;
short *&sqlind = m_pOutXSQLDA->sqlvar[nCol-1].sqlind;
short &sqllen = m_pOutXSQLDA->sqlvar[nCol-1].sqllen;
char *&sqldata = m_pOutXSQLDA->sqlvar[nCol-1].sqldata;
assert((unsigned int)sqllen == nValueSize);
if((unsigned int)sqllen != nValueSize)
return;
assert(sqlind == NULL);
assert(sqldata == NULL);
if(!m_pCommand->Field(nCol).isFieldRequired())
{
assert((sqltype & 1) != 0);
sqlind = (short*)pInd;
}
else
assert((sqltype & 1) == 0);
if((sqltype & ~1) == SQL_VARYING)
{
// short is reserverd for size returning
// just before the actual string
sqldata = (char*)pValue - sizeof(short);
}
else
sqldata = (char*)pValue;
}
/*virtual */
bool IibCursor::IndicatorIsNull(
int nPos, // 1-based
SAValueRead &/*vr*/,
ValueType_t/* eValueType*/,
void * /*pInd*/,
unsigned int nIndSize,
void * /*pSize*/,
unsigned int nSizeSize,
unsigned int &nRealSize,
int/* nBulkReadingBufPos*/) const
{
assert(m_pOutXSQLDA != NULL); // should always be called after DescribeFields
assert(nIndSize == sizeof(short));
if(nIndSize != sizeof(short))
return true;
assert(nSizeSize == sizeof(short));
if(nSizeSize != sizeof(short))
return true;
XSQLVAR &var = m_pOutXSQLDA->sqlvar[nPos-1];
// no indicator, field can not be NULL, or it is not null
if(var.sqlind == NULL || *var.sqlind != -1)
{
if((var.sqltype & ~1) == SQL_VARYING)
{
// short is reserverd for size returning
// just before the actual string
nRealSize = *(short*)var.sqldata;
}
else
nRealSize = var.sqllen;
return false;
}
return true;
}
/*virtual */
void IibCursor::SetSelectBuffers()
{
// use default helpers
AllocSelectBuffer(sizeof(short), sizeof(short));
}
/*virtual */
bool IibCursor::FetchNext()
{
ISC_STATUS Status;
Status = g_ibAPI.isc_dsql_fetch(
m_StatusVector,
&m_handles.m_stmt_handle,
1, m_pOutXSQLDA);
if(Status != 100)
{
IibConnection::Check(Status, m_StatusVector);
// use default helpers
ConvertSelectBufferToFields(0);
}
return Status != 100;
}
/*static */
SAString IibConnection::FormatIdentifierValue(
unsigned short nSQLDialect,
const SAString &sValue)
{
if(nSQLDialect == 1)
{
SAString sTemp = sValue;
sTemp.TrimLeft();
sTemp.TrimRight();
return sTemp;
}
return sValue;
}
/*virtual */
void IibCursor::DescribeParamSP()
{
SAString sProcName = m_pCommand->CommandText();
SAString sStmtIB = "Execute Procedure ";
sStmtIB += sProcName;
// read sp parameters from system tables
SAString sSQL =
"SELECT RDB$PARAMETER_NAME, RDB$PARAMETER_TYPE "
"FROM RDB$PROCEDURE_PARAMETERS "
"WHERE UPPER(RDB$PROCEDURE_NAME) = UPPER('";
sSQL += IibConnection::FormatIdentifierValue(SQLDialect(), sProcName);
sSQL += "') ORDER BY RDB$PARAMETER_NUMBER";
SACommand cmd(m_pISAConnection->getSAConnection(), sSQL);
cmd.Execute();
int nTotal = 0;
int nInput = 0;
while(cmd.FetchNext())
{
SAString sName = cmd["RDB$PARAMETER_NAME"].asString();
sName.TrimRight(" ");
SAParamDirType_t eDirType = cmd["RDB$PARAMETER_TYPE"].asShort() == 0? SA_ParamInput : SA_ParamOutput;
if(eDirType == SA_ParamInput) // input
{
if(++nInput > 1)
sStmtIB += " ,?";
else
sStmtIB += " ?";
}
else
{
}
++nTotal;
m_pCommand->CreateParam(sName, SA_dtUnknown, -1, 0, eDirType);
}
// query and set output parameters datatypes, native datatypes and sizes
if(nTotal)
{
int nOutput = 0;
cmd.setCommandText(sStmtIB);
cmd.Prepare();
for(int i = 0; i < nTotal; ++i)
{
SAParam &Param = m_pCommand->ParamByIndex(i);
if(Param.ParamDirType() != SA_ParamOutput)
continue;
++nOutput;
Param.setParamType(cmd.Field(nOutput).FieldType());
Param.setParamNativeType(cmd.Field(nOutput).FieldNativeType());
Param.setParamSize(cmd.Field(nOutput).FieldSize());
}
cmd.Close();
}
}
/*virtual */
saAPI *IibConnection::NativeAPI() const
{
return &g_ibAPI;
}
/*virtual */
saConnectionHandles *IibConnection::NativeHandles()
{
return &m_handles;
}
/*virtual */
saCommandHandles *IibCursor::NativeHandles()
{
return &m_handles;
}
void IibConnection::ConstructTPB(
SAIsolationLevel_t eIsolationLevel,
SAAutoCommit_t eAutoCommit)
{
// Construct the transaction parameter buffer
char *tpb = m_TPB_buffer;
*tpb++ = isc_tpb_version3;
*tpb++ = isc_tpb_write;
switch(eIsolationLevel)
{
case SA_LevelUnknown:
// use default values
break;
case SA_ReadUncommitted:
*tpb++ = isc_tpb_read_committed;
*tpb++ = isc_tpb_rec_version;
break;
case SA_ReadCommitted:
*tpb++ = isc_tpb_read_committed;
*tpb++ = isc_tpb_no_rec_version;
break;
case SA_RepeatableRead:
*tpb++ = isc_tpb_consistency;
break;
case SA_Serializable:
*tpb++ = isc_tpb_concurrency;
break;
default:
assert(false);
}
*tpb++ = isc_tpb_wait;
if(eAutoCommit == SA_AutoCommitOn)
*tpb++ = isc_tpb_autocommit;
m_TPB_buffer_length = (short)(tpb - m_TPB_buffer);
}
/*virtual */
void IibConnection::setIsolationLevel(
SAIsolationLevel_t eIsolationLevel)
{
// adjust isolation level and start new transaction
ConstructTPB(
eIsolationLevel,
m_pSAConnection->AutoCommit());
// for new settings to take affect we should start new transaction
CommitTransaction(); // commit and close the transaction
StartTransaction(); // reopen
}
/*virtual */
void IibConnection::setAutoCommit(
SAAutoCommit_t eAutoCommit)
{
ConstructTPB(
m_pSAConnection->IsolationLevel(),
eAutoCommit);
// for new settings to take affect we should start new transaction
CommitTransaction(); // commit and close the transaction
StartTransaction(); // reopen
}
unsigned short IibCursor::SQLDialect() const
{
SAString s = m_pCommand->Option("SQLDialect");
if(s.IsEmpty())
return 3; // defaults to SQL dialect 3
return (unsigned short)atoi((const char*)s);
}
static void TransactionClosed(ISACursor *pCursor, void *pAddlData)
{
((IibCursor*)pCursor)->OnTransactionClosed(pAddlData);
}
void IibCursor::OnTransactionClosed(void * /*pAddlData*/)
{
m_bResultSet = false;
}
void IibConnection::CommitTransaction()
{
assert(m_handles.m_tr_handle != NULL);
Check(g_ibAPI.isc_commit_transaction(
m_StatusVector, &m_handles.m_tr_handle), m_StatusVector);
assert(m_handles.m_tr_handle == NULL);
EnumCursors(TransactionClosed, NULL);
}
void IibConnection::CommitRetaining()
{
assert(m_handles.m_tr_handle != NULL);
Check(g_ibAPI.isc_commit_retaining(
m_StatusVector, &m_handles.m_tr_handle), m_StatusVector);
assert(m_handles.m_tr_handle != NULL);
}
void IibConnection::RollbackTransaction()
{
assert(m_handles.m_tr_handle != NULL);
Check(g_ibAPI.isc_rollback_transaction(
m_StatusVector, &m_handles.m_tr_handle), m_StatusVector);
assert(m_handles.m_tr_handle == NULL);
EnumCursors(TransactionClosed, NULL);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -