📄 odbcclient.cpp
字号:
break; } } return ISACursor::InputBufferSize(Param);}/*virtual */SADataType_t IodbcCursor::CnvtNativeToStd( int dbtype, int/* dbsubtype*/, int/* dbsize*/, int prec, int scale) const{ SADataType_t eDataType = SA_dtUnknown; switch(dbtype) {#ifdef SQL_WCHAR case SQL_WCHAR: // Unicode character string of fixed length#endif // SQL_WCHAR#ifdef SQL_WVARCHAR case SQL_WVARCHAR: // Unicode variable-length character string#endif // SQL_WVARCHAR case SQL_CHAR: // Character string of fixed length case SQL_VARCHAR: // Variable-length character string eDataType = SA_dtString; break; case SQL_BINARY: case SQL_VARBINARY: eDataType = SA_dtBytes; break; case SQL_LONGVARCHAR: // Variable-length character data#ifdef SQL_WLONGVARCHAR case SQL_WLONGVARCHAR: // Variable-length character data#endif // SQL_WLONGVARCHAR eDataType = SA_dtLongChar; break; case SQL_LONGVARBINARY: // Variable-length binary data eDataType = SA_dtLongBinary; break; case SQL_DECIMAL: case SQL_NUMERIC: if(scale <= 0) { // check for exact type if(prec <= 5) eDataType = SA_dtShort; else if(prec <= 10) eDataType = SA_dtLong; else eDataType = SA_dtDouble; } else eDataType = SA_dtDouble; break; case SQL_SMALLINT: eDataType = SA_dtShort; break; case SQL_INTEGER: eDataType = SA_dtLong; break; case SQL_REAL: eDataType = SA_dtDouble; break; case SQL_FLOAT: eDataType = SA_dtDouble; break; case SQL_DOUBLE: eDataType = SA_dtDouble; break; case SQL_BIT: // Single bit binary data eDataType = SA_dtBool; break; case SQL_TINYINT: eDataType = SA_dtShort; break; case SQL_BIGINT: eDataType = SA_dtDouble; break; case SQL_TIME: case SQL_DATE: // == SQL_DATETIME case SQL_TIMESTAMP: case SQL_TYPE_DATE: case SQL_TYPE_TIME: case SQL_TYPE_TIMESTAMP: eDataType = SA_dtDateTime; break; default: assert(false); } return eDataType;}int IodbcCursor::CnvtStdToNativeValueType(SADataType_t eDataType) const{ SQLSMALLINT ValueType; switch(eDataType) { case SA_dtUnknown: throw SAException(SA_Library_Error, -1, -1, IDS_UNKNOWN_DATA_TYPE);
case SA_dtBool:
ValueType = SQL_C_BIT;
break; case SA_dtShort: ValueType = SQL_C_SSHORT; break; case SA_dtLong: ValueType = SQL_C_SLONG; break; case SA_dtDouble: ValueType = SQL_C_DOUBLE; break; case SA_dtDateTime: ValueType = SQL_C_TYPE_TIMESTAMP; break; case SA_dtString: ValueType = SQL_C_CHAR; break; case SA_dtBytes: ValueType = SQL_C_BINARY; break; case SA_dtLongBinary: case SA_dtBLob: ValueType = SQL_C_BINARY; break; case SA_dtLongChar: case SA_dtCLob: ValueType = SQL_C_CHAR; break; default: ValueType = 0; assert(false); } return ValueType;}/*virtual */int IodbcCursor::CnvtStdToNative(SADataType_t eDataType) const{ SQLSMALLINT dbtype; switch(eDataType) { case SA_dtUnknown: throw SAException(SA_Library_Error, -1, -1, IDS_UNKNOWN_DATA_TYPE);
case SA_dtBool:
dbtype = SQL_BIT;
break; case SA_dtShort: dbtype = SQL_SMALLINT; break; case SA_dtLong: dbtype = SQL_INTEGER; break; case SA_dtDouble: dbtype = SQL_DOUBLE; break; case SA_dtDateTime: dbtype = SQL_TYPE_TIMESTAMP; break; case SA_dtString: dbtype = SQL_CHAR; break; case SA_dtBytes: dbtype = SQL_BINARY; break; case SA_dtLongBinary: case SA_dtBLob: dbtype = SQL_LONGVARBINARY; break; case SA_dtLongChar: case SA_dtCLob: dbtype = SQL_LONGVARCHAR; break; default: dbtype = 0; assert(false); } return dbtype;}/*virtual */bool IodbcCursor::IsOpened(){ return m_handles.m_hstmt != NULL;}/*virtual */void IodbcCursor::Open(){ assert(m_handles.m_hstmt == NULL); IodbcConnection::Check( g_odbcAPI.SQLAllocHandle(SQL_HANDLE_STMT, ((IodbcConnection*)m_pISAConnection)->m_handles.m_hdbc, &m_handles.m_hstmt), SQL_HANDLE_DBC, ((IodbcConnection*)m_pISAConnection)->m_handles.m_hdbc); assert(m_handles.m_hstmt != NULL);
}/*virtual */void IodbcCursor::Close(){ assert(m_handles.m_hstmt != NULL); IodbcConnection::Check(g_odbcAPI.SQLFreeHandle(SQL_HANDLE_STMT, m_handles.m_hstmt), SQL_HANDLE_STMT, m_handles.m_hstmt); m_handles.m_hstmt = NULL;}/*virtual */ISACursor *IodbcConnection::NewCursor(SACommand *m_pCommand){ return new IodbcCursor(this, m_pCommand);}/*virtual */void IodbcCursor::Prepare( const SAString &sStmt, SACommandType_t eCmdType, int nPlaceHolderCount, saPlaceHolder** ppPlaceHolders){ SAString sStmtODBC; int nPos = 0; int i; switch(eCmdType) { case SA_CmdSQLStmt: // replace bind variables with '?' place holder for(i = 0; i < nPlaceHolderCount; i++) { sStmtODBC += sStmt.Mid(nPos, ppPlaceHolders[i]->getStart()-nPos); sStmtODBC += "?"; nPos = ppPlaceHolders[i]->getEnd() + 1; } // copy tail if(nPos < sStmt.GetLength()) sStmtODBC += sStmt.Mid(nPos); break; case SA_CmdStoredProc: sStmtODBC = CallSubProgramSQL(); break; default: assert(false); } // a bit of clean up IodbcConnection::Check(g_odbcAPI.SQLFreeStmt(m_handles.m_hstmt, SQL_CLOSE), SQL_HANDLE_STMT, m_handles.m_hstmt); IodbcConnection::Check(g_odbcAPI.SQLFreeStmt(m_handles.m_hstmt, SQL_UNBIND), SQL_HANDLE_STMT, m_handles.m_hstmt); IodbcConnection::Check(g_odbcAPI.SQLFreeStmt(m_handles.m_hstmt, SQL_RESET_PARAMS), SQL_HANDLE_STMT, m_handles.m_hstmt); IodbcConnection::Check(g_odbcAPI.SQLPrepare( m_handles.m_hstmt, (SQLCHAR*)(const char*)sStmtODBC, SQL_NTS), SQL_HANDLE_STMT, m_handles.m_hstmt);}SAString IodbcCursor::CallSubProgramSQL(){ int nParams = m_pCommand->ParamCount(); SAString sSQL = "{"; // check for Return parameter int i; for(i = 0; i < nParams; ++i) { SAParam &Param = m_pCommand->ParamByIndex(i); if(Param.ParamDirType() == SA_ParamReturn) { sSQL += "?="; break; } } sSQL += "call "; sSQL += m_pCommand->CommandText(); // specify parameters SAString sParams; for(i = 0; i < nParams; ++i) { SAParam &Param = m_pCommand->ParamByIndex(i); if(Param.ParamDirType() == SA_ParamReturn) continue; if(!sParams.IsEmpty()) sParams += ", "; sParams += "?"; } if(!sParams.IsEmpty()) { sSQL += "(";
sSQL += sParams; sSQL += ")";
} sSQL += "}"; return sSQL;}void IodbcCursor::BindLongs(){ SQLRETURN retcode; SQLPOINTER ValuePtr; try { while((retcode = g_odbcAPI.SQLParamData(m_handles.m_hstmt, &ValuePtr)) == SQL_NEED_DATA) { SAParam *pParam = (SAParam *)ValuePtr; unsigned int nActualWrite; SAPieceType_t ePieceType = SA_FirstPiece; void *pBuf; while((nActualWrite = pParam->InvokeWriter( ePieceType, IodbcConnection::MaxLongAtExecSize, pBuf)) != 0) { IodbcConnection::Check(g_odbcAPI.SQLPutData( m_handles.m_hstmt, pBuf, nActualWrite), SQL_HANDLE_STMT, m_handles.m_hstmt); if(ePieceType == SA_LastPiece) break; }
} } catch(SAException&) { g_odbcAPI.SQLCancel(m_handles.m_hstmt); throw; } IodbcConnection::Check(retcode, SQL_HANDLE_STMT, m_handles.m_hstmt);}
/*virtual */
void IodbcCursor::UnExecute()
{
m_bResultSetCanBe = false;
}
void IodbcCursor::Bind(
int nPlaceHolderCount,
saPlaceHolder** ppPlaceHolders)
{
// we should bind for every place holder ('?')
AllocBindBuffer(nPlaceHolderCount, ppPlaceHolders,
sizeof(SQLINTEGER), 0);
void *pBuf = m_pParamBuffer;
for(int i = 0; i < nPlaceHolderCount; ++i)
{
SAParam &Param = *ppPlaceHolders[i]->getParam();
void *pInd;
void *pSize;
unsigned int nDataBufSize;
void *pValue;
IncParamBuffer(pBuf, pInd, pSize, nDataBufSize, pValue);
SADataType_t eDataType = Param.DataType();
SQLSMALLINT ParameterType = (SQLSMALLINT)(eDataType == SA_dtUnknown?
SQL_CHAR : // some type should be set
CnvtStdToNative(eDataType));
SQLSMALLINT ValueType = (SQLSMALLINT)(eDataType == SA_dtUnknown?
SQL_C_CHAR : // some type should be set
CnvtStdToNativeValueType(eDataType));
SQLINTEGER *StrLen_or_IndPtr = (SQLINTEGER *)pInd;
SQLPOINTER ParameterValuePtr = (SQLPOINTER)pValue;
SQLINTEGER BufferLength = (SQLINTEGER)nDataBufSize;
SQLUINTEGER ColumnSize = Param.ParamSize();
if(!ColumnSize) // not set explicitly
ColumnSize = BufferLength;
SQLSMALLINT InputOutputType;
switch(Param.ParamDirType())
{
case SA_ParamInput:
InputOutputType = SQL_PARAM_INPUT;
break;
case SA_ParamOutput:
InputOutputType = SQL_PARAM_OUTPUT;
break;
case SA_ParamInputOutput:
InputOutputType = SQL_PARAM_INPUT_OUTPUT;
break;
default:
assert(Param.ParamDirType() == SA_ParamReturn);
InputOutputType = SQL_PARAM_OUTPUT;
}
if(isInputParam(Param))
{
if(Param.isNull())
*StrLen_or_IndPtr = SQL_NULL_DATA; // field is null
else
*StrLen_or_IndPtr = InputBufferSize(Param); // field is not null
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(*StrLen_or_IndPtr == (SQLINTEGER)sizeof(unsigned char));
*(unsigned char*)ParameterValuePtr = (unsigned char)Param.asBool();
break;
case SA_dtShort:
assert(*StrLen_or_IndPtr == (SQLINTEGER)sizeof(short));
*(short*)ParameterValuePtr = Param.asShort();
break;
case SA_dtLong:
assert(*StrLen_or_IndPtr == (SQLINTEGER)sizeof(long));
*(long*)ParameterValuePtr = Param.asLong();
break;
case SA_dtDouble:
assert(*StrLen_or_IndPtr == (SQLINTEGER)sizeof(double));
*(double*)ParameterValuePtr = Param.asDouble();
break;
case SA_dtDateTime:
assert(*StrLen_or_IndPtr == (SQLINTEGER)sizeof(TIMESTAMP_STRUCT));
IodbcConnection::CnvtDateTimeToInternal(
Param.asDateTime(),
*(TIMESTAMP_STRUCT*)ParameterValuePtr);
break;
case SA_dtString:
assert(*StrLen_or_IndPtr == Param.asString().GetLength());
memcpy(ParameterValuePtr, (const char*)Param.asString(), *StrLen_or_IndPtr);
break;
case SA_dtBytes:
assert(*StrLen_or_IndPtr == Param.asBytes().GetLength());
memcpy(ParameterValuePtr, (const char*)Param.asBytes(), *StrLen_or_IndPtr);
break;
case SA_dtLongBinary:
case SA_dtBLob:
case SA_dtLongChar:
case SA_dtCLob:
assert(*StrLen_or_IndPtr == 0);
break;
default:
ValueType = 0;
ParameterType = 0;
assert(false);
}
}
}
if(isLongOrLob(eDataType))
{
*StrLen_or_IndPtr = ((IodbcConnection*)m_pISAConnection)->LenDataAtExec();
IodbcConnection::Check(g_odbcAPI.SQLBindParameter(
m_handles.m_hstmt,
(SQLUSMALLINT)(i+1), InputOutputType,
ValueType,
ParameterType,
IodbcConnection::MaxLongAtExecSize, // ColumnSize
0, // DecimalDigits
&Param, // ParameterValuePtr - context
0, // Buffer length
StrLen_or_IndPtr), SQL_HANDLE_STMT, m_handles.m_hstmt);
}
else
{
// to avoid default (f.ex. SQLServer ODBC driver throws an error when binding "" string)
if(ColumnSize == 0 && isInputParam(Param))
ColumnSize = sa_max((unsigned int)1, InputBufferSize(Param));
IodbcConnection::Check(g_odbcAPI.SQLBindParameter(
m_handles.m_hstmt,
(SQLUSMALLINT)(i+1), InputOutputType,
ValueType,
ParameterType,
ColumnSize,
0,
ParameterValuePtr,
BufferLength,
StrLen_or_IndPtr), SQL_HANDLE_STMT, m_handles.m_hstmt);
}
}
}
void IodbcCursor::ProcessBatchUntilEndOrResultSet()
{
SQLRETURN rcMoreResults;
do
{
rcMoreResults = g_odbcAPI.SQLMoreResults(
m_handles.m_hstmt);
if(rcMoreResults != SQL_NO_DATA)
{
IodbcConnection::Check(rcMoreResults, SQL_HANDLE_STMT, m_handles.m_hstmt);
// cache affected rows count
// because it will not be available after SQL_NO_DATA
IodbcConnection::Check(g_odbcAPI.SQLRowCount(m_handles.m_hstmt, &m_nRowsAffected), SQL_HANDLE_STMT, m_handles.m_hstmt);
if(ResultSetExists())
break;
}
else
{
m_bResultSetCanBe = false;
// some drivers (e.g. Microsoft SQL Server)
// return output parameters only after SQLMoreResults returns SQL_NO_DATA
ConvertOutputParams(); // if any/if available
}
}
while(rcMoreResults != SQL_NO_DATA);
}
/*virtual */void IodbcCursor::Execute(
int nPlaceHolderCount,
saPlaceHolder **ppPlaceHolders){
if(nPlaceHolderCount)
Bind(nPlaceHolderCount, ppPlaceHolders);
SQLRETURN rc; IodbcConnection::Check(g_odbcAPI.SQLFreeStmt(m_handles.m_hstmt, SQL_CLOSE), SQL_HANDLE_STMT, m_handles.m_hstmt); rc = g_odbcAPI.SQLExecute(m_handles.m_hstmt); if(rc != SQL_NEED_DATA) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -