feat(Data::ODBC) add MARS support #4230

This commit is contained in:
Alex Fabijanic 2023-10-27 16:01:33 +02:00
parent bd06526ee0
commit efd9b2ca1d
3 changed files with 81 additions and 25 deletions

View File

@ -52,9 +52,15 @@
#endif
#include "Poco/Data/ODBC/Unicode.h"
#if (__cplusplus >= 201703L)
#if __has_include(<msodbcsql.h>)
#include <msodbcsql.h>
#define POCO_DATA_ODBC_HAVE_SQL_SERVER_EXT
#endif
#endif
//
// Automatically link Data library.

View File

@ -81,6 +81,9 @@ public:
Poco::SharedPtr<Poco::Data::StatementImpl> 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.

View File

@ -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;