diff --git a/Data/ODBC/include/Poco/Data/ODBC/ODBC.h b/Data/ODBC/include/Poco/Data/ODBC/ODBC.h index 647e4b8f0..e23f1787b 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/ODBC.h +++ b/Data/ODBC/include/Poco/Data/ODBC/ODBC.h @@ -52,9 +52,15 @@ #endif - #include "Poco/Data/ODBC/Unicode.h" +#if (__cplusplus >= 201703L) + #if __has_include() + #include + #define POCO_DATA_ODBC_HAVE_SQL_SERVER_EXT + #endif +#endif + // // Automatically link Data library. diff --git a/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h b/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h index 2e04a137a..0e3e9479f 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h +++ b/Data/ODBC/include/Poco/Data/ODBC/SessionImpl.h @@ -81,6 +81,9 @@ public: Poco::SharedPtr createStatementImpl(); /// Returns an ODBC StatementImpl + void addFeatures(); + /// Adds the ODBC session features and properties. + void open(const std::string& connect = ""); /// Opens a connection to the Database @@ -189,6 +192,14 @@ public: const std::string& dbEncoding() const; /// Returns the database encoding. + void setMultiActiveResultset(const std::string&, bool value); + /// Sets the multiple active resultset capability, if available. + /// Does nothing, if feature is not available. + + bool getMultiActiveResultset(const std::string&) const; + /// Returns the multiple active resultset capability, if available. + /// Returns false, if feature is not available. + const ConnectionHandle& dbc() const; /// Returns the connection handle. diff --git a/Data/ODBC/src/SessionImpl.cpp b/Data/ODBC/src/SessionImpl.cpp index 644be1f3e..365f0c419 100644 --- a/Data/ODBC/src/SessionImpl.cpp +++ b/Data/ODBC/src/SessionImpl.cpp @@ -42,10 +42,14 @@ SessionImpl::SessionImpl(const std::string& connect, _queryTimeout(-1), _dbEncoding("UTF-8") { + addFeatures(); setFeature("bulk", true); + setFeature("multiActiveResultset", true); + // this option is obsolete; here only to support older drivers, should be changed to ODBC_CURSOR_USE_NEVER // https://github.com/MicrosoftDocs/sql-docs/blob/live/docs/odbc/reference/appendixes/using-the-odbc-cursor-library.md setCursorUse("", ODBC_CURSOR_USE_IF_NEEDED); + open(); } @@ -64,10 +68,14 @@ SessionImpl::SessionImpl(const std::string& connect, _queryTimeout(-1), _dbEncoding("UTF-8") { + addFeatures(); setFeature("bulk", true); + setFeature("multiActiveResultset", true); + // this option is obsolete; here only to support older drivers, should be changed to ODBC_CURSOR_USE_NEVER // https://github.com/MicrosoftDocs/sql-docs/blob/live/docs/odbc/reference/appendixes/using-the-odbc-cursor-library.md setCursorUse("", ODBC_CURSOR_USE_IF_NEEDED); + open(); } @@ -97,6 +105,40 @@ Poco::Data::StatementImpl::Ptr SessionImpl::createStatementImpl() } +void SessionImpl::addFeatures() +{ + addFeature("autoCommit", + &SessionImpl::autoCommit, + &SessionImpl::isAutoCommit); + + addFeature("autoBind", + &SessionImpl::autoBind, + &SessionImpl::isAutoBind); + + addFeature("autoExtract", + &SessionImpl::autoExtract, + &SessionImpl::isAutoExtract); + + addProperty("maxFieldSize", + &SessionImpl::setMaxFieldSize, + &SessionImpl::getMaxFieldSize); + + addProperty("queryTimeout", + &SessionImpl::setQueryTimeout, + &SessionImpl::getQueryTimeout); + + addProperty("dbEncoding", + &SessionImpl::setDBEncoding, + &SessionImpl::getDBEncoding); + + // SQL Server supports multiple active resultsets + // currently has no effect on other back ends + addFeature("multiActiveResultset", + &SessionImpl::setMultiActiveResultset, + &SessionImpl::getMultiActiveResultset); +} + + void SessionImpl::open(const std::string& connect) { if (connect != connectionString()) @@ -122,30 +164,6 @@ void SessionImpl::open(const std::string& connect) &SessionImpl::setDataTypeInfo, &SessionImpl::dataTypeInfo); - addFeature("autoCommit", - &SessionImpl::autoCommit, - &SessionImpl::isAutoCommit); - - addFeature("autoBind", - &SessionImpl::autoBind, - &SessionImpl::isAutoBind); - - addFeature("autoExtract", - &SessionImpl::autoExtract, - &SessionImpl::isAutoExtract); - - addProperty("maxFieldSize", - &SessionImpl::setMaxFieldSize, - &SessionImpl::getMaxFieldSize); - - addProperty("queryTimeout", - &SessionImpl::setQueryTimeout, - &SessionImpl::getQueryTimeout); - - addProperty("dbEncoding", - &SessionImpl::setDBEncoding, - &SessionImpl::getDBEncoding); - Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_ATTR_QUIET_MODE, 0, 0); if (!canTransact()) autoCommit("", true); @@ -297,6 +315,27 @@ void SessionImpl::setTransactionIsolationImpl(Poco::UInt32 ti) const } +void SessionImpl::setMultiActiveResultset(const std::string&, bool val) +{ +#ifdef POCO_DATA_ODBC_HAVE_SQL_SERVER_EXT + int enabled = val ? SQL_MARS_ENABLED_YES : SQL_MARS_ENABLED_NO; + checkError(Poco::Data::ODBC::SQLSetConnectAttr(_db, SQL_COPT_SS_MARS_ENABLED, &enabled, SQL_IS_INTEGER)); +#endif +} + + +bool SessionImpl::getMultiActiveResultset(const std::string&) const +{ +#ifdef POCO_DATA_ODBC_HAVE_SQL_SERVER_EXT + SQLINTEGER mars; + Poco::Data::ODBC::SQLGetConnectAttr(_db, SQL_COPT_SS_MARS_ENABLED, &mars, SQL_IS_INTEGER, 0); + return mars == SQL_MARS_ENABLED_YES; +#else + return false; +#endif +} + + Poco::UInt32 SessionImpl::getTransactionIsolation() const { SQLULEN isolation = 0;