From 91752413588d2210c51443e4e10cd329e0aeb01c Mon Sep 17 00:00:00 2001 From: Hadis-Fard Date: Wed, 13 Sep 2017 19:06:28 -0700 Subject: [PATCH] added pdo test, fixed issue with missing driver --- source/shared/core_conn.cpp | 29 ++-- .../pdo_sqlsrv/pdo_connect_encrypted.phpt | 163 +++++++++++------- 2 files changed, 121 insertions(+), 71 deletions(-) diff --git a/source/shared/core_conn.cpp b/source/shared/core_conn.cpp index 1d058726..de47bd11 100644 --- a/source/shared/core_conn.cpp +++ b/source/shared/core_conn.cpp @@ -164,10 +164,9 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont } else { - for ( std::size_t i = DRIVER_VERSION::ODBC_DRIVER_13; i <= DRIVER_VERSION::LAST; ++i ) { - conn_str = conn_str + CONNECTION_STRING_DRIVER_NAME[ DRIVER_VERSION(i) ]; - r = core_odbc_connect( conn, conn_str, missing_driver_error, is_pooled ); - // if it's a IM002, meaning that the correct ODBC driver is not installed + for ( std::size_t i = DRIVER_VERSION::FIRST; i <= DRIVER_VERSION::LAST; ++i ) { + std::string conn_str_driver = conn_str + CONNECTION_STRING_DRIVER_NAME[ DRIVER_VERSION(i) ]; + r = core_odbc_connect( conn, conn_str_driver, missing_driver_error, is_pooled ); CHECK_CUSTOM_ERROR( missing_driver_error && ( i == DRIVER_VERSION::LAST ), conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) { throw core::CoreException(); } @@ -203,24 +202,24 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont #endif // !_WIN32 } catch( std::bad_alloc& ) { - memset( const_cast( conn_str.c_str()), 0, conn_str.size() ); + conn_str.clear(); conn->invalidate(); DIE( "C++ memory allocation failure building the connection string." ); } catch( std::out_of_range const& ex ) { - memset( const_cast( conn_str.c_str()), 0, conn_str.size() ); + conn_str.clear(); LOG( SEV_ERROR, "C++ exception returned: %1!s!", ex.what() ); conn->invalidate(); throw; } catch( std::length_error const& ex ) { - memset( const_cast( conn_str.c_str()), 0, conn_str.size() ); + conn_str.clear(); LOG( SEV_ERROR, "C++ exception returned: %1!s!", ex.what() ); conn->invalidate(); throw; } catch( core::CoreException& ) { - memset( const_cast( conn_str.c_str()), 0, conn_str.size() ); + conn_str.clear(); conn->invalidate(); throw; } @@ -232,6 +231,16 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont return return_conn; } + +// core_odbc_connect +// calls odbc connect API to establish the connection to server +// Parameters: +// conn - The connection structure on which we establish the connection +// conn_str - Connection string +// missing_driver_error - indicates whether odbc driver is installed on client machine +// is_pooled - indicate whether it is a pooled connection +// Return - SQLRETURN status retunred by SQLDriverConnect + SQLRETURN core_odbc_connect(_Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str, _Inout_ bool& missing_driver_error, _In_ bool is_pooled) { SQLRETURN r = SQL_SUCCESS; @@ -264,7 +273,6 @@ SQLRETURN core_odbc_connect(_Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn #endif // !_WIN32 // clear the connection string from memory to remove sensitive data (such as a password). - memset( const_cast( conn_str.c_str() ), 0, conn_str.size() ); memset( wconn_string, 0, wconn_len * sizeof( SQLWCHAR )); // wconn_len is the number of characters, not bytes conn_str.clear(); @@ -272,7 +280,8 @@ SQLRETURN core_odbc_connect(_Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ]; SQLSMALLINT len; SQLRETURN sr = SQLGetDiagField( SQL_HANDLE_DBC, conn->handle(), 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len ); - missing_driver_error = ( SQL_SUCCEEDED(sr) && state[0] == 'I' && state[1] == 'M' && state[2] == '0' && state[3] == '0' && state[4] == '2' ); + // sql state IM002/IM003 in ODBC 17, means that the correct ODBC driver is not installed + missing_driver_error = ( SQL_SUCCEEDED(sr) && state[0] == 'I' && state[1] == 'M' && state[2] == '0' && state[3] == '0' && (state[4] == '2' || state[4] == '3')); } return r; } diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt index 1416b211..ffff90f7 100644 --- a/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt @@ -4,66 +4,107 @@ Test new connection keyword ColumnEncryption --FILE-- getMessage() ); - echo "\n"; - } - $conn = null; - //////////////////////////////////////// - $connectionInfo = "Database = $databaseName; ColumnEncryption = false;"; - try - { - $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); - } - catch( PDOException $e ) - { - echo "Failed to connect.\n"; - print_r( $e->getMessage() ); - echo "\n"; - } - //////////////////////////////////////// - $connectionInfo = "Database = $databaseName; ColumnEncryption = 1;"; - try - { - $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); - } - catch( PDOException $e ) - { - echo "Failed to connect.\n"; - print_r( $e->getMessage() ); - echo "\n"; - } - - //////////////////////////////////////// - $connectionInfo = "Database = $databaseName; ColumnEncryption = Disabled;"; - try - { - $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); - echo "Connected successfully with ColumnEncryption disabled.\n"; - } - catch( PDOException $e ) - { - echo "Failed to connect with ColumnEncryption disabled.\n"; - print_r( $e->getMessage() ); - echo "\n"; - } - $conn = null; - echo "Done\n"; +require_once("MsSetup.inc"); +$msodbcsql_maj = ""; + +try +{ + $conn = new PDO( "sqlsrv:server = $server", $uid, $pwd ); + $msodbcsql_ver = $conn->getAttribute( PDO::ATTR_CLIENT_VERSION )['DriverVer']; + $msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; +} +catch( PDOException $e ) +{ + echo "Failed to connect\n"; + print_r( $e->getMessage() ); + echo "\n"; +} + +test_ColumnEncryption( $server, $uid, $pwd, $msodbcsql_maj ); +echo "Done"; + + +function verify_output( $PDOerror, $expected ) +{ + if( strpos( $PDOerror->getMessage(), $expected ) === false ) + { + print_r( $PDOerror->getMessage() ); + echo "\n"; + } +} + +function test_ColumnEncryption( $server, $uid, $pwd, $msodbcsql_maj ) +{ + // Only works for ODBC 17 + //////////////////////////////////////// + $connectionInfo = "ColumnEncryption = Enabled;"; + try + { + $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); + } + catch( PDOException $e ) + { + if($msodbcsql_maj < 17) + { + $expected = "This extension requires Microsoft ODBC Driver 17 for SQL Server when ColumnEncryption attribute is enabled."; + verify_output( $e, $expected ); + } + else + { + print_r( $e->getMessage() ); + echo "\n"; + } + } + + // Works for ODBC 17, ODBC 13 + //////////////////////////////////////// + $connectionInfo = "ColumnEncryption = Disabled;"; + try + { + $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); + } + catch( PDOException $e ) + { + if($msodbcsql_maj < 13) + { + $expected = "Invalid connection string attribute"; + verify_output( $e, $expected ); + } + else + { + print_r( $e->getMessage() ); + echo "\n"; + } + } + + // should fail for all ODBC drivers + //////////////////////////////////////// + $connectionInfo = "ColumnEncryption = false;"; + try + { + $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); + } + catch( PDOException $e ) + { + $expected = "Invalid value specified for connection string attribute 'ColumnEncryption'"; + verify_output( $e, $expected ); + } + + // should fail for all ODBC drivers + //////////////////////////////////////// + $connectionInfo = "ColumnEncryption = 1;"; + try + { + $conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd ); + } + catch( PDOException $e ) + { + $expected = "Invalid value specified for connection string attribute 'ColumnEncryption'"; + verify_output( $e, $expected ); + } +} + + ?> ---EXPECTREGEX-- -Connected successfully with ColumnEncryption enabled. -Failed to connect. -SQLSTATE\[08001\]: .*\[Microsoft\]\[ODBC Driver 13 for SQL Server\]Invalid value specified for connection string attribute 'ColumnEncryption' -Failed to connect. -SQLSTATE\[08001\]: .*\[Microsoft\]\[ODBC Driver 13 for SQL Server\]Invalid value specified for connection string attribute 'ColumnEncryption' -Connected successfully with ColumnEncryption disabled. +--EXPECTF-- Done \ No newline at end of file