📄 databasemetadata.cpp.svn-base
字号:
/* 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++/databasemetadata.h>#include <odbc++/connection.h>#include <odbc++/resultset.h>#include <odbc++/statement.h>#include "dtconv.h"#include "driverinfo.h"using namespace odbc;using namespace std;#define FETCH_STEP 64namespace odbc { // returns the actual ODBC cursor type this datasource would // use for a given ResultSet typeinline int getODBCCursorTypeFor(int rsType, const DriverInfo* di){ int r; switch(rsType) { case ResultSet::TYPE_FORWARD_ONLY: r=SQL_CURSOR_FORWARD_ONLY; break; case ResultSet::TYPE_SCROLL_INSENSITIVE: r=SQL_CURSOR_STATIC; break; case ResultSet::TYPE_SCROLL_SENSITIVE: if(di->getCursorMask()&SQL_SO_DYNAMIC) { r=SQL_CURSOR_DYNAMIC; } else { r=SQL_CURSOR_KEYSET_DRIVEN; } break; default: throw SQLException(ODBCXX_STRING_CONST("[libodbc++]: Invalid ResultSet type ")+intToString(rsType)); } return r;}#if ODBCVER >= 0x0300inline int getCursorAttributes1For(int odbcType){ int infoType; switch(odbcType) { case SQL_CURSOR_FORWARD_ONLY: infoType=SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1; break; case SQL_CURSOR_STATIC: infoType=SQL_STATIC_CURSOR_ATTRIBUTES1; break; case SQL_CURSOR_KEYSET_DRIVEN: infoType=SQL_KEYSET_CURSOR_ATTRIBUTES1; break; case SQL_CURSOR_DYNAMIC: default: infoType=SQL_DYNAMIC_CURSOR_ATTRIBUTES1; break; } return infoType;}inline int getCursorAttributes2For(int odbcType){ int infoType; switch(odbcType) { case SQL_CURSOR_FORWARD_ONLY: infoType=SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2; break; case SQL_CURSOR_STATIC: infoType=SQL_STATIC_CURSOR_ATTRIBUTES2; break; case SQL_CURSOR_KEYSET_DRIVEN: infoType=SQL_KEYSET_CURSOR_ATTRIBUTES2; break; case SQL_CURSOR_DYNAMIC: default: infoType=SQL_DYNAMIC_CURSOR_ATTRIBUTES2; break; } return infoType;}#endif // ODBCVER >= 0x0300// for _ownXXXAreVisibleenum { INSERTS,UPDATES,DELETES};}; // namespace odbcDatabaseMetaData::DatabaseMetaData(Connection* c) :connection_(c){}DatabaseMetaData::~DatabaseMetaData(){}SQLUSMALLINT DatabaseMetaData::_getNumeric16(int what){ SQLUSMALLINT res; SQLSMALLINT t; SQLRETURN r=SQLGetInfo(connection_->hdbc_, (SQLUSMALLINT)what, &res, sizeof(res), //ignored, but what the heck.. &t); connection_->_checkConError(connection_->hdbc_, r,ODBCXX_STRING_CONST("Error fetching information")); return res;}SQLUINTEGER DatabaseMetaData::_getNumeric32(int what){ SQLUINTEGER res; SQLSMALLINT t; SQLRETURN r=SQLGetInfo(connection_->hdbc_, (SQLUSMALLINT)what, &res, sizeof(res), //ignored, but what the heck.. &t); connection_->_checkConError(connection_->hdbc_,r,ODBCXX_STRING_CONST("Error fetching information")); return res;}//privateODBCXX_STRING DatabaseMetaData::_getStringInfo(int what){ ODBCXX_STRING res; SQLSMALLINT len1; SQLSMALLINT len2=FETCH_STEP; ODBCXX_CHAR_TYPE* buf=NULL; // ODBCXX_CERR << ODBCXX_STRING_CONST("Entering _getStringInfo()") << endl; do { len1=len2; buf=new ODBCXX_CHAR_TYPE[len1+1]; // ODBCXX_CERR << ODBCXX_STRING_CONST("Calling SQLGetInfo: len1=") // << len1 << ODBCXX_STRING_CONST(", len2=") << len2 << endl; SQLRETURN r=SQLGetInfo(connection_->hdbc_, (SQLUSMALLINT)what, buf, len1+1, &len2); try { connection_->_checkConError(connection_->hdbc_,r,ODBCXX_STRING_CONST("Error fetching information")); } catch(...) { delete[] buf; throw; } } while(len2>len1); // ODBCXX_CERR << ODBCXX_STRING_CONST("Exiting _getStringInfo()") << endl; res=ODBCXX_STRING_C(buf); delete[] buf; return res;}#if ODBCVER >= 0x0300SQLUINTEGER DatabaseMetaData::_getAllCursorAttributes1(){ SQLUINTEGER r=0; int cm=this->_getDriverInfo()->getCursorMask(); if(cm&SQL_SO_FORWARD_ONLY) { r|=this->_getNumeric32(SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1); } if(cm&SQL_SO_STATIC) { r|=this->_getNumeric32(SQL_STATIC_CURSOR_ATTRIBUTES1); } if(cm&SQL_SO_KEYSET_DRIVEN) { r|=this->_getNumeric32(SQL_KEYSET_CURSOR_ATTRIBUTES1); } if(cm&SQL_SO_DYNAMIC) { r|=this->_getNumeric32(SQL_DYNAMIC_CURSOR_ATTRIBUTES1); } return r;}#endifbool DatabaseMetaData::supportsBatchUpdates(){ // we don't, yet return false;}bool DatabaseMetaData::supportsIntegrityEnhancementFacility(){ return this->_getStringInfo(SQL_ODBC_SQL_OPT_IEF)==ODBCXX_STRING_CONST("Y");}bool DatabaseMetaData::supportsPositionedDelete(){ // with ODBC 2, we can simply check SQL_POSITIONED_STATEMENTS // for ODBC 3, we have to check if any cursor type supports this#if ODBCVER >= 0x0300 if(this->_getDriverInfo()->getMajorVersion()<3) {#endif return (this->_getNumeric32 (SQL_POSITIONED_STATEMENTS)&SQL_PS_POSITIONED_DELETE)!=0;#if ODBCVER >= 0x0300 } // the ODBC 3 way return (this->_getAllCursorAttributes1()&SQL_CA1_POSITIONED_DELETE)!=0;#endif}bool DatabaseMetaData::supportsPositionedUpdate(){#if ODBCVER >= 0x0300 if(this->_getDriverInfo()->getMajorVersion()<3) {#endif return (this->_getNumeric32 (SQL_POSITIONED_STATEMENTS)&SQL_PS_POSITIONED_UPDATE)!=0;#if ODBCVER >= 0x0300 } // the ODBC 3 way return (this->_getAllCursorAttributes1()&SQL_CA1_POSITIONED_UPDATE)!=0;#endif}bool DatabaseMetaData::supportsSelectForUpdate(){#if ODBCVER >= 0x0300 if(this->_getDriverInfo()->getMajorVersion()<3) {#endif return (this->_getNumeric32 (SQL_POSITIONED_STATEMENTS)&SQL_PS_SELECT_FOR_UPDATE)!=0;#if ODBCVER >= 0x0300 } // the ODBC 3 way return (this->_getAllCursorAttributes1()&SQL_CA1_SELECT_FOR_UPDATE)!=0;#endif}bool DatabaseMetaData::supportsTransactions(){ return this->_getNumeric16(SQL_TXN_CAPABLE)!=SQL_TC_NONE;}bool DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions(){ return this->_getNumeric16 (SQL_TXN_CAPABLE)==SQL_TC_ALL;}bool DatabaseMetaData::supportsDataManipulationTransactionsOnly(){ return this->_getNumeric16 (SQL_TXN_CAPABLE)==SQL_TC_DML;}bool DatabaseMetaData::dataDefinitionCausesTransactionCommit(){ return this->_getNumeric16 (SQL_TXN_CAPABLE)==SQL_TC_DDL_COMMIT;}bool DatabaseMetaData::dataDefinitionIgnoredInTransactions(){ return this->_getNumeric16 (SQL_TXN_CAPABLE)==SQL_TC_DDL_IGNORE;}ODBCXX_STRING DatabaseMetaData::getDatabaseProductName(){ return this->_getStringInfo(SQL_DBMS_NAME);}ODBCXX_STRING DatabaseMetaData::getDatabaseProductVersion(){ return this->_getStringInfo(SQL_DBMS_VER);}ODBCXX_STRING DatabaseMetaData::getDriverName(){ return this->_getStringInfo(SQL_DRIVER_NAME);}ODBCXX_STRING DatabaseMetaData::getDriverVersion(){ return this->_getStringInfo(SQL_DRIVER_VER);}int DatabaseMetaData::getDriverMajorVersion(){ ODBCXX_STRING s=this->_getStringInfo(SQL_DRIVER_ODBC_VER); if(s.length()==5) { return stringToInt(#if defined(ODBCXX_QT) s.left(2)#else s.substr(0,2)#endif ); } throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Invalid ODBC version string received from driver: ")+s); ODBCXX_DUMMY_RETURN(0);}int DatabaseMetaData::getDriverMinorVersion(){ ODBCXX_STRING s=this->_getStringInfo(SQL_DRIVER_ODBC_VER); if(s.length()==5) { return stringToInt(#if defined(ODBCXX_QT) s.mid(3,2)#else s.substr(3,2)#endif ); } throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Invalid ODBC version string received from driver: ")+s); ODBCXX_DUMMY_RETURN(0);}ODBCXX_STRING DatabaseMetaData::getIdentifierQuoteString(){ return this->_getStringInfo(SQL_IDENTIFIER_QUOTE_CHAR);}ODBCXX_STRING DatabaseMetaData::getCatalogTerm(){ return this->_getStringInfo(ODBC3_C(SQL_CATALOG_TERM,SQL_QUALIFIER_TERM));}ODBCXX_STRING DatabaseMetaData::getSchemaTerm(){ return this->_getStringInfo(ODBC3_C(SQL_SCHEMA_TERM,SQL_OWNER_TERM));}ODBCXX_STRING DatabaseMetaData::getTableTerm(){ return this->_getStringInfo(SQL_TABLE_TERM);}ODBCXX_STRING DatabaseMetaData::getProcedureTerm(){ return this->_getStringInfo(SQL_PROCEDURE_TERM);}ODBCXX_STRING DatabaseMetaData::getUserName(){ return this->_getStringInfo(SQL_USER_NAME);}ODBCXX_STRING DatabaseMetaData::getCatalogSeparator(){ return this->_getStringInfo(ODBC3_C(SQL_CATALOG_NAME_SEPARATOR, SQL_QUALIFIER_NAME_SEPARATOR));}bool DatabaseMetaData::isCatalogAtStart(){ return this->_getNumeric16(ODBC3_C(SQL_CATALOG_LOCATION, SQL_QUALIFIER_LOCATION))==SQL_QL_START;}ODBCXX_STRING DatabaseMetaData::getSQLKeywords(){ return this->_getStringInfo(SQL_KEYWORDS);}int DatabaseMetaData::getDefaultTransactionIsolation(){ SQLUINTEGER r=this->_getNumeric32(SQL_DEFAULT_TXN_ISOLATION); switch(r) { case SQL_TXN_READ_UNCOMMITTED: return Connection::TRANSACTION_READ_UNCOMMITTED; case SQL_TXN_READ_COMMITTED: return Connection::TRANSACTION_READ_COMMITTED; case SQL_TXN_REPEATABLE_READ: return Connection::TRANSACTION_REPEATABLE_READ; case SQL_TXN_SERIALIZABLE:#if defined(SQL_TXN_VERSIONING) case SQL_TXN_VERSIONING:#endif return Connection::TRANSACTION_SERIALIZABLE; } return Connection::TRANSACTION_NONE;}bool DatabaseMetaData::supportsTransactionIsolationLevel(int lev){ SQLUINTEGER r=this->_getNumeric32(SQL_TXN_ISOLATION_OPTION); SQLUINTEGER ret=0; switch(lev) { case Connection::TRANSACTION_READ_UNCOMMITTED: ret=r&SQL_TXN_READ_UNCOMMITTED; break; case Connection::TRANSACTION_READ_COMMITTED: ret=r&SQL_TXN_READ_COMMITTED; break; case Connection::TRANSACTION_REPEATABLE_READ: ret=r&SQL_TXN_REPEATABLE_READ; break; case Connection::TRANSACTION_SERIALIZABLE: ret=(r&SQL_TXN_SERIALIZABLE)#if defined(SQL_TXN_VERSIONING) || (r&SQL_TXN_VERSIONING)#endif ; break; } return ret!=0;}bool DatabaseMetaData::supportsOpenCursorsAcrossCommit(){ return this->_getNumeric16(SQL_CURSOR_COMMIT_BEHAVIOR)==SQL_CB_PRESERVE;}bool DatabaseMetaData::supportsOpenCursorsAcrossRollback(){ return this->_getNumeric16(SQL_CURSOR_ROLLBACK_BEHAVIOR)==SQL_CB_PRESERVE;}bool DatabaseMetaData::supportsOpenStatementsAcrossCommit(){ return this->_getNumeric16(SQL_CURSOR_COMMIT_BEHAVIOR)==SQL_CB_PRESERVE;}bool DatabaseMetaData::supportsOpenStatementsAcrossRollback(){ return this->_getNumeric16(SQL_CURSOR_ROLLBACK_BEHAVIOR)==SQL_CB_PRESERVE;}bool DatabaseMetaData::supportsResultSetType(int type){ const DriverInfo* di=this->_getDriverInfo(); switch(type) { case ResultSet::TYPE_FORWARD_ONLY: return di->supportsForwardOnly(); break; case ResultSet::TYPE_SCROLL_INSENSITIVE: return di->supportsStatic(); break; case ResultSet::TYPE_SCROLL_SENSITIVE: return di->supportsScrollSensitive(); break; default: throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Invalid ResultSet type ")+ intToString(type)); } ODBCXX_DUMMY_RETURN(false);}bool DatabaseMetaData::supportsResultSetConcurrency(int type, int concurrency){ const DriverInfo* di=this->_getDriverInfo(); if(!this->supportsResultSetType(type)) { // no need to bother return false; } int ct; switch(type) { case ResultSet::TYPE_SCROLL_SENSITIVE: ct=di->getScrollSensitive(); break; case ResultSet::TYPE_SCROLL_INSENSITIVE: ct=SQL_CURSOR_STATIC; break; case ResultSet::TYPE_FORWARD_ONLY: // forward only cursors are read-only by definition return concurrency==ResultSet::CONCUR_READ_ONLY; break; default: throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Invalid ResultSet type ")+intToString(type)); } switch(concurrency) { case ResultSet::CONCUR_READ_ONLY: return di->supportsReadOnly(ct); break; case ResultSet::CONCUR_UPDATABLE: return di->supportsUpdatable(ct); break; default: throw SQLException (ODBCXX_STRING_CONST("[libodbc++]: Invalid ResultSet concurrency ")+intToString(type)); } ODBCXX_DUMMY_RETURN(false);}bool DatabaseMetaData::nullPlusNonNullIsNull(){ return this->_getNumeric16 (SQL_CONCAT_NULL_BEHAVIOR)==SQL_CB_NULL;}bool DatabaseMetaData::supportsColumnAliasing(){ return this->_getStringInfo(SQL_COLUMN_ALIAS)==ODBCXX_STRING_CONST("Y");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -