diff --git a/google/cloud/odbc/bq_driver/internal/odbc_conn_attr.cc b/google/cloud/odbc/bq_driver/internal/odbc_conn_attr.cc index a0cb3307ec..b3d99cc32b 100644 --- a/google/cloud/odbc/bq_driver/internal/odbc_conn_attr.cc +++ b/google/cloud/odbc/bq_driver/internal/odbc_conn_attr.cc @@ -36,6 +36,9 @@ ConnectionAttr::ConnectionAttr() { {SQL_ATTR_LOGIN_TIMEOUT, {"SQL_ATTR_LOGIN_TIMEOUT", ConnectionValidation::kBefore, SupportedAttribute::kBoth, (SQLPOINTER)0}}, + {SQL_ATTR_ANSI_APP, + {"SQL_ATTR_ANSI_APP", ConnectionValidation::kEither, + SupportedAttribute::kSet, (SQLPOINTER)SQL_AA_FALSE}}, {SQL_ATTR_METADATA_ID, {"SQL_ATTR_METADATA_ID", ConnectionValidation::kEither, SupportedAttribute::kBoth, (SQLPOINTER)SQL_FALSE}}, @@ -76,6 +79,10 @@ ConnectionAttr::ConnectionAttr() { {"SQL_ATTR_AUTOCOMMIT", ConnectionValueType::kSqlUInt, {(SQLPOINTER)SQL_AUTOCOMMIT_OFF, (SQLPOINTER)SQL_AUTOCOMMIT_ON}}}, + {SQL_ATTR_ANSI_APP, + {"SQL_ATTR_ANSI_APP", + ConnectionValueType::kSqlULen, + {(SQLPOINTER)SQL_AA_TRUE, (SQLPOINTER)SQL_AA_FALSE}}}, {SQL_ATTR_METADATA_ID, {"SQL_ATTR_METADATA_ID", ConnectionValueType::kSqlUInt, diff --git a/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h b/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h index 04a2085138..6aa7e780e3 100644 --- a/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h +++ b/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h @@ -197,6 +197,7 @@ class ConnectionHandle : public Handle { // storage of all explicitly allocated descriptor handles associated with this // connection handle std::set desc_handles_; + EnvironmentHandle* env_handle_{nullptr}; mutable std::mutex connection_handle_mutex_; // Session ID of the started session. diff --git a/google/cloud/odbc/bq_driver/odbc_connection.cc b/google/cloud/odbc/bq_driver/odbc_connection.cc index 9baa70a973..ebfad3f41c 100644 --- a/google/cloud/odbc/bq_driver/odbc_connection.cc +++ b/google/cloud/odbc/bq_driver/odbc_connection.cc @@ -471,6 +471,9 @@ SQLRETURN SQLSetConnectAttrInternal(SQLHDBC connection_handle, return LogAndReturnCode(*conn_handle, status_record); } + if (attribute == SQL_ATTR_ANSI_APP) { + return SQL_SUCCESS; + } // Additionally set these attributes to all associated statement handles if (attribute == SQL_ATTR_METADATA_ID || attribute == SQL_ATTR_ASYNC_ENABLE) { for (auto* const stmt_handle : conn_handle->GetStatementHandles()) { diff --git a/google/cloud/odbc/integration_tests/odbc_driver_tests/connection_test.cc b/google/cloud/odbc/integration_tests/odbc_driver_tests/connection_test.cc index 2798bef220..79af3165ca 100644 --- a/google/cloud/odbc/integration_tests/odbc_driver_tests/connection_test.cc +++ b/google/cloud/odbc/integration_tests/odbc_driver_tests/connection_test.cc @@ -597,6 +597,26 @@ TEST(MultipleConnectionTest, SQLDriverConnect) { } } +TEST(ConnectionTest, VerifySQLANSIAttributes) { + auto conn = std::make_shared(); + SQLRETURN status; + SQLCHAR data_source[kBufferLength]; + SQLSMALLINT buflen = 0; + SetAttributes(conn, 30, true); + StrToChar(reinterpret_cast(data_source), kDefaultConnectionString); + + status = + SQLDriverConnectA(conn->hdbc, nullptr, data_source, SQL_NTS, + reinterpret_cast(conn->outdsn), + sizeof(conn->outdsn), &buflen, SQL_DRIVER_COMPLETE); + CheckError(status, "SQLDriverConnectA", conn, true); + + // SQL_ATTR_ANSI_APP is expected to be successful after connection. + status = SQLSetConnectAttr(conn->hdbc, SQL_ATTR_ANSI_APP, + ToSqlPointer(SQL_AA_FALSE), 0); + EXPECT_EQ(status, SQL_SUCCESS); +} + TEST(ConnectionTest, SQLDriverConnectA) { auto conn = std::make_shared(); EXPECT_EQ(Connect(kDefaultConnectionString, conn, true), SQL_SUCCESS); diff --git a/google/cloud/odbc/testing/odbc_utils/connection.cc b/google/cloud/odbc/testing/odbc_utils/connection.cc index da32dda607..0d474f04e7 100644 --- a/google/cloud/odbc/testing/odbc_utils/connection.cc +++ b/google/cloud/odbc/testing/odbc_utils/connection.cc @@ -36,6 +36,11 @@ void SetAttributes(std::shared_ptr const& conn, int timeout, status = SQLSetConnectAttrA(conn->hdbc, SQL_ATTR_CONNECTION_TIMEOUT, ToSqlPointer(timeout), 0); CheckError(status, "SQLSetConnectAttr", conn, use_ansi); +#ifndef WIN32 + status = SQLSetConnectAttrA(conn->hdbc, SQL_ATTR_ANSI_APP, + ToSqlPointer(SQL_AA_TRUE), 0); + CheckError(status, "SQLSetConnectAttr", conn, use_ansi); +#endif // WIN32 } else { status = SQLSetConnectAttr(conn->hdbc, SQL_ATTR_LOGIN_TIMEOUT, ToSqlPointer(10), 0); @@ -44,12 +49,17 @@ void SetAttributes(std::shared_ptr const& conn, int timeout, status = SQLSetConnectAttr(conn->hdbc, SQL_ATTR_CONNECTION_TIMEOUT, ToSqlPointer(timeout), 0); CheckError(status, "SQLSetConnectAttr", conn, use_ansi); +#ifndef WIN32 + status = SQLSetConnectAttr(conn->hdbc, SQL_ATTR_ANSI_APP, + ToSqlPointer(SQL_AA_FALSE), 0); + CheckError(status, "SQLSetConnectAttr", conn, use_ansi); +#endif // WIN32 } } SQLRETURN Connect(std::string const& conn_str, - std::shared_ptr const& conn, int timeout, - bool use_ansi) { + std::shared_ptr const& conn, bool use_ansi, + int timeout) { SQLSMALLINT buflen; SQLCHAR data_source[kBufferLength]; SQLSMALLINT out_len; diff --git a/google/cloud/odbc/testing/odbc_utils/connection.h b/google/cloud/odbc/testing/odbc_utils/connection.h index 34fe3e0eec..ab4de7fabd 100644 --- a/google/cloud/odbc/testing/odbc_utils/connection.h +++ b/google/cloud/odbc/testing/odbc_utils/connection.h @@ -55,7 +55,7 @@ std::string const kImpersonatedAccountEmail = // Connect using a and populate the ODBCHandles SQLRETURN Connect(std::string const& conn_str, std::shared_ptr const& conn, - int timeout = 30, bool use_ansi = false); + bool use_ansi = false, int timeout = 30); // To validate SQLDriverConnect and SQLDriverConnectW with NULL output // parameters.