diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index b86bec0e..3fd3e53a 100644 --- a/source/pdo_sqlsrv/pdo_dbh.cpp +++ b/source/pdo_sqlsrv/pdo_dbh.cpp @@ -43,6 +43,7 @@ const char AttachDBFileName[] = "AttachDbFileName"; const char ConnectionPooling[] = "ConnectionPooling"; const char Authentication[] = "Authentication"; const char ColumnEncryption[] = "ColumnEncryption"; +const char Driver[] = "Driver"; const char CEKeystoreProvider[] = "CEKeystoreProvider"; const char CEKeystoreName[] = "CEKeystoreName"; const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey"; @@ -234,6 +235,15 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_STRING, column_encryption_set_func::func }, + { + PDOConnOptionNames::Driver, + sizeof(PDOConnOptionNames::Driver), + SQLSRV_CONN_OPTION_DRIVER, + ODBCConnOptions::Driver, + sizeof(ODBCConnOptions::Driver), + CONN_ATTR_STRING, + driver_set_func::func + }, { PDOConnOptionNames::CEKeystoreProvider, sizeof(PDOConnOptionNames::CEKeystoreProvider), diff --git a/source/pdo_sqlsrv/pdo_util.cpp b/source/pdo_sqlsrv/pdo_util.cpp index fa184627..4a22a92f 100644 --- a/source/pdo_sqlsrv/pdo_util.cpp +++ b/source/pdo_sqlsrv/pdo_util.cpp @@ -398,9 +398,13 @@ pdo_error PDO_ERRORS[] = { { IMSSP, (SQLCHAR*) "Invalid value for loading a custom keystore provider.", -77, false} }, { - SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED, + SQLSRV_ERROR_AE_DRIVER_NOT_INSTALLED, { IMSSP, (SQLCHAR*) "This extension requires Microsoft ODBC Driver 17 for SQL Server when ColumnEncryption attribute is enabled.", -78, false } - }, + }, + { + SQLSRV_ERROR_CONNECT_INVALID_DRIVER, + { IMSSP, (SQLCHAR*) "Invalid value %1!s! was specified for Driver option. For the list of valid connection options visit https://docs.microsoft.com/en-us/sql/connect/php/connection-options", -79, true } + }, { UINT_MAX, {} } }; diff --git a/source/shared/core_conn.cpp b/source/shared/core_conn.cpp index d2749204..2708f7be 100644 --- a/source/shared/core_conn.cpp +++ b/source/shared/core_conn.cpp @@ -49,7 +49,7 @@ const int INFO_BUFFER_LEN = 256; const char* PROCESSOR_ARCH[] = { "x86", "x64", "ia64" }; // ODBC driver name. -const char* CONNECTION_STRING_DRIVER_NAME[] = {"Driver={ODBC Driver 17 for SQL Server};","Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};"}; +std::vector CONNECTION_STRING_DRIVER_NAME{ "Driver={ODBC Driver 17 for SQL Server};","Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};" }; // default options if only the server is specified const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes}"; @@ -160,7 +160,7 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont conn_str = conn_str + CONNECTION_STRING_DRIVER_NAME[ DRIVER_VERSION::ODBC_DRIVER_17 ]; r = core_odbc_connect( conn, conn_str, wconn_string, wconn_len, missing_driver_error, is_pooled ); - CHECK_CUSTOM_ERROR( missing_driver_error, conn, SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) { + CHECK_CUSTOM_ERROR( missing_driver_error, conn, SQLSRV_ERROR_AE_DRIVER_NOT_INSTALLED, get_processor_arch()) { throw core::CoreException(); } } @@ -903,18 +903,18 @@ void driver_set_func::func( _In_ connection_option const* option, _In_ zval* val { convert_to_string( value ); const char* value_str = Z_STRVAL_P( value ); - std::vector valid_odbc_drivers{ "Driver={ODBC Driver 17 for SQL Server};","Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};" }; - conn_str += option->odbc_name; - conn_str += "="; - conn_str += value_str; - conn_str += ";"; - - CHECK_CUSTOM_ERROR( std::find( valid_odbc_drivers.begin(), valid_odbc_drivers.end(), conn_str ) == valid_odbc_drivers.end(), conn, SQLSRV_ERROR_KEYSTORE_INVALID_VALUE ){ + std::string driver_option( option->odbc_name ); + driver_option += "="; + driver_option += value_str; + driver_option += ";"; + + CHECK_CUSTOM_ERROR( std::find( CONNECTION_STRING_DRIVER_NAME.begin(), CONNECTION_STRING_DRIVER_NAME.end(), driver_option) == CONNECTION_STRING_DRIVER_NAME.end(), conn, SQLSRV_ERROR_CONNECT_INVALID_DRIVER, value_str){ throw core::CoreException(); } conn->is_driver_set = true; + conn_str += driver_option; } diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index 326ff08a..f2f3676d 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -1643,7 +1643,8 @@ enum SQLSRV_ERROR_CODES { SQLSRV_ERROR_ODBC, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, - SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED, + SQLSRV_ERROR_AE_DRIVER_NOT_INSTALLED, + SQLSRV_ERROR_CONNECT_INVALID_DRIVER, SQLSRV_ERROR_ZEND_HASH, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE, @@ -1872,7 +1873,7 @@ namespace core { const std::string connection_busy_error( "Connection is busy with results for another command" ); const std::string returned_error( reinterpret_cast( err_msg )); - if(( returned_error.find( connection_busy_error ) == std::string::npos )) { + if(( returned_error.find( connection_busy_error ) != std::string::npos )) { THROW_CORE_ERROR( stmt, SQLSRV_ERROR_MARS_OFF ); } diff --git a/source/sqlsrv/conn.cpp b/source/sqlsrv/conn.cpp index 92698dd1..bc0ca386 100644 --- a/source/sqlsrv/conn.cpp +++ b/source/sqlsrv/conn.cpp @@ -134,8 +134,7 @@ struct bool_conn_attr_func { static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) { try { - core::SQLSetConnectAttr(conn, Attr, reinterpret_cast((zend_long)zend_is_true(value)), - SQL_IS_UINTEGER TSRMLS_CC); + core::SQLSetConnectAttr(conn, Attr, reinterpret_cast((zend_long)zend_is_true(value)), SQL_IS_UINTEGER TSRMLS_CC); } catch( core::CoreException& ) { @@ -189,6 +188,7 @@ const char CharacterSet[] = "CharacterSet"; const char Authentication[] = "Authentication"; const char ConnectionPooling[] = "ConnectionPooling"; const char ColumnEncryption[] = "ColumnEncryption"; +const char Driver[] = "Driver"; const char CEKeystoreProvider[] = "CEKeystoreProvider"; const char CEKeystoreName[] = "CEKeystoreName"; const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey"; @@ -316,6 +316,15 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_STRING, column_encryption_set_func::func }, + { + SSConnOptionNames::Driver, + sizeof(SSConnOptionNames::Driver), + SQLSRV_CONN_OPTION_DRIVER, + ODBCConnOptions::Driver, + sizeof(ODBCConnOptions::Driver), + CONN_ATTR_STRING, + driver_set_func::func + }, { SSConnOptionNames::CEKeystoreProvider, sizeof(SSConnOptionNames::CEKeystoreProvider), diff --git a/source/sqlsrv/util.cpp b/source/sqlsrv/util.cpp index 5c9e60f7..5e28c8a4 100644 --- a/source/sqlsrv/util.cpp +++ b/source/sqlsrv/util.cpp @@ -300,7 +300,7 @@ ss_error SS_ERRORS[] = { { SQLSRV_ERROR_DRIVER_NOT_INSTALLED, - { IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver 11 or 13 for SQL Server. " + { IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver 13 or 11 for SQL Server. " "Access the following URL to download the ODBC Driver for SQL Server for %1!s!: " "http://go.microsoft.com/fwlink/?LinkId=163712", -49, true } }, @@ -393,9 +393,13 @@ ss_error SS_ERRORS[] = { { IMSSP, (SQLCHAR*) "Invalid value for loading a custom keystore provider.", -104, false} }, { - SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED, + SQLSRV_ERROR_AE_DRIVER_NOT_INSTALLED, { IMSSP, (SQLCHAR*) "This extension requires Microsoft ODBC Driver 17 for SQL Server when ColumnEncryption attribute is enabled.", -105, false } }, + { + SQLSRV_ERROR_CONNECT_INVALID_DRIVER, + { IMSSP, (SQLCHAR*) "Invalid value %1!s! was specified for Driver option. For the list of valid connection options visit https://docs.microsoft.com/en-us/sql/connect/php/connection-options", -106, true } + }, // terminate the list of errors/warnings { UINT_MAX, {} } };