📄 statement.cpp
字号:
/* This file is part of libodbc++. Copyright (C) 1999-2000 Manush Dodunekov <manush@stendahls.net> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include <odbc++/statement.h>#include <odbc++/resultset.h>#include <odbc++/connection.h>#include "driverinfo.h"#include "dtconv.h"using namespace odbc;using namespace std;Statement::Statement(Connection* con, SQLHSTMT hstmt, int resultSetType, int resultSetConcurrency) :connection_(con), hstmt_(hstmt), lastExecute_(SQL_SUCCESS), currentResultSet_(NULL), fetchSize_(SQL_ROWSET_SIZE_DEFAULT), resultSetType_(resultSetType), resultSetConcurrency_(resultSetConcurrency), state_(STATE_CLOSED){ try { this->_applyResultSetType(); } catch(...) { // avoid a statement handle leak (the destructor will not be called)#if ODBCVER < 0x0300 SQLFreeStmt(hstmt_,SQL_DROP);#else SQLFreeHandle(SQL_HANDLE_STMT,hstmt_);#endif throw; }}Statement::~Statement(){ if(currentResultSet_!=NULL) { currentResultSet_->ownStatement_=false; delete currentResultSet_; currentResultSet_=NULL; }#if ODBCVER < 0x0300 SQLFreeStmt(hstmt_,SQL_DROP);#else SQLFreeHandle(SQL_HANDLE_STMT,hstmt_);#endif connection_->_unregisterStatement(this);}//privatevoid Statement::_registerResultSet(ResultSet* rs){ assert(currentResultSet_==NULL); currentResultSet_=rs;}void Statement::_unregisterResultSet(ResultSet* rs){ assert(currentResultSet_==rs); currentResultSet_=NULL;}//protectedSQLUINTEGER Statement::_getNumericOption(SQLINTEGER optnum){ SQLUINTEGER res; SQLRETURN r;#if ODBCVER < 0x0300 r=SQLGetStmtOption(hstmt_,optnum,(SQLPOINTER)&res);#else SQLINTEGER dummy; r=SQLGetStmtAttr(hstmt_,optnum,(SQLPOINTER)&res,SQL_IS_UINTEGER,&dummy);#endif this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error fetching numeric statement option")); return res;}//protectedvoid Statement::_setNumericOption(SQLINTEGER optnum, SQLUINTEGER value){ SQLRETURN r;#if ODBCVER < 0x0300 r=SQLSetStmtOption(hstmt_,optnum,value);#else r=SQLSetStmtAttr(hstmt_,optnum,(SQLPOINTER)value,SQL_IS_UINTEGER);#endif this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error setting numeric statement option"));}//protectedODBCXX_STRING Statement::_getStringOption(SQLINTEGER optnum){ SQLRETURN r;#if ODBCVER < 0x0300 ODBCXX_CHAR_TYPE buf[SQL_MAX_OPTION_STRING_LENGTH+1]; r=SQLGetStmtOption(hstmt_,optnum,(SQLPOINTER)buf); this->_checkStmtError(hstmt_,r,"Error fetching string statement option");#else ODBCXX_CHAR_TYPE buf[256]; SQLINTEGER dataSize; r=SQLGetStmtAttr(hstmt_,optnum,(SQLPOINTER)buf,255,&dataSize); this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error fetching string statement option")); if(dataSize>255) { // we have a longer attribute here ODBCXX_CHAR_TYPE* tmp=new ODBCXX_CHAR_TYPE[dataSize+1]; odbc::Deleter<ODBCXX_CHAR_TYPE> _tmp(tmp,true); r=SQLGetStmtAttr(hstmt_,optnum,(SQLPOINTER)tmp,dataSize,&dataSize); this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error fetching string statement option")); return ODBCXX_STRING_C(tmp); }#endif return ODBCXX_STRING_C(buf);}//protectedvoid Statement::_setStringOption(SQLINTEGER optnum, const ODBCXX_STRING& value){ SQLRETURN r;#if ODBCVER < 0x0300 r=SQLSetStmtOption(hstmt_,optnum, (SQLUINTEGER) ODBCXX_STRING_CSTR(value));#else r=SQLSetStmtAttr(hstmt_,optnum, (SQLPOINTER) ODBCXX_STRING_CSTR(value), ODBCXX_STRING_LEN(value));#endif this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error setting string statement option"));}#if ODBCVER >= 0x0300SQLPOINTER Statement::_getPointerOption(SQLINTEGER optnum){ SQLPOINTER ret; SQLINTEGER len; SQLRETURN r=SQLGetStmtAttr(hstmt_,optnum,(SQLPOINTER)&ret, SQL_IS_POINTER,&len); this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error fetching pointer statement option")); return ret;}void Statement::_setPointerOption(SQLINTEGER optnum, SQLPOINTER value){ SQLRETURN r=SQLSetStmtAttr(hstmt_,optnum,value,SQL_IS_POINTER); this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error setting pointer statement option"));}#endifvoid Statement::_applyResultSetType(){ const DriverInfo* di=this->_getDriverInfo(); int ct; switch(resultSetType_) { case ResultSet::TYPE_FORWARD_ONLY: ct=SQL_CURSOR_FORWARD_ONLY; break; case ResultSet::TYPE_SCROLL_INSENSITIVE: if(di->supportsStatic()) { ct=SQL_CURSOR_STATIC; } else { throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Datasource does not support ResultSet::TYPE_SCROLL_INSENSITIVE")); } break; case ResultSet::TYPE_SCROLL_SENSITIVE: if(di->supportsScrollSensitive()) { ct=di->getScrollSensitive(); } else { throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Datasource does not support ResultSet::TYPE_SCROLL_SENSITIVE")); } break; default: throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Invalid ResultSet type")); } if(ct!=SQL_CURSOR_FORWARD_ONLY) { this->_setNumericOption (ODBC3_C(SQL_ATTR_CURSOR_TYPE,SQL_CURSOR_TYPE),ct); } // concurrency: switch(resultSetConcurrency_) { case ResultSet::CONCUR_READ_ONLY: // we only apply this for non-default cursors if(ct!=SQL_CURSOR_FORWARD_ONLY) { if(di->supportsReadOnly(ct)) { this->_setNumericOption (ODBC3_C(SQL_ATTR_CONCURRENCY,SQL_CONCURRENCY),SQL_CONCUR_READ_ONLY); } else { throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: ResultSet::CONCUR_READ_ONLY not supported for given type")); } } break; case ResultSet::CONCUR_UPDATABLE: if(di->supportsUpdatable(ct)) { this->_setNumericOption (ODBC3_C(SQL_ATTR_CONCURRENCY,SQL_CONCURRENCY), di->getUpdatable(ct)); } else { throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: ResultSet::CONCUR_UPDATABLE not supported for given type")); } break; default: throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Invalid concurrency level")); }}//protectedbool Statement::_checkForResults(){ SQLSMALLINT nc; SQLRETURN r=SQLNumResultCols(hstmt_,&nc); return r==SQL_SUCCESS && nc>0;}//protectedResultSet* Statement::_getResultSet(bool hideMe){ ResultSet* rs=new ResultSet(this,hstmt_,hideMe); this->_registerResultSet(rs); return rs;}//protectedvoid Statement::_beforeExecute(){ this->clearWarnings(); if(currentResultSet_!=NULL) { throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Cannot re-execute; statement has an open resultset")); } if(state_==STATE_OPEN) { SQLRETURN r=SQLFreeStmt(hstmt_,SQL_CLOSE); this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error closing statement")); state_=STATE_CLOSED; }}//protectedvoid Statement::_afterExecute(){ state_=STATE_OPEN;}//private catalog stuff//this statement should be hidden behind a ResultSet//but since it can be obtained with ResultSet->getStatement()//we still track the state (before/afterExecute).inline ODBCXX_SQLCHAR* valueOrNull(const ODBCXX_STRING& str){ return (ODBCXX_SQLCHAR*)(ODBCXX_STRING_LEN(str)>0? ODBCXX_STRING_DATA(str):NULL);}ResultSet* Statement::_getTypeInfo(){ this->_beforeExecute(); SQLRETURN r=SQLGetTypeInfo(hstmt_,SQL_ALL_TYPES); this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error fetching type information")); this->_afterExecute(); ResultSet* rs=this->_getResultSet(true); return rs;}ResultSet* Statement::_getColumns(const ODBCXX_STRING& catalog, const ODBCXX_STRING& schema, const ODBCXX_STRING& tableName, const ODBCXX_STRING& columnName){ this->_beforeExecute(); SQLRETURN r=SQLColumns(hstmt_, valueOrNull(catalog), ODBCXX_STRING_LEN(catalog), valueOrNull(schema), ODBCXX_STRING_LEN(schema), valueOrNull(tableName), ODBCXX_STRING_LEN(tableName), valueOrNull(columnName), ODBCXX_STRING_LEN(columnName)); this->_checkStmtError(hstmt_,r,ODBCXX_STRING_CONST("Error fetching column information")); ResultSet* rs=this->_getResultSet(true); return rs;}ResultSet* Statement::_getTables(const ODBCXX_STRING& catalog, const ODBCXX_STRING& schema, const ODBCXX_STRING& tableName, const ODBCXX_STRING& types){ this->_beforeExecute(); SQLRETURN r=SQLTables(hstmt_, valueOrNull(catalog), ODBCXX_STRING_LEN(catalog), valueOrNull(schema), ODBCXX_STRING_LEN(schema), valueOrNull(tableName), ODBCXX_STRING_LEN(tableName),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -