diff --git a/source/shared/core_conn.cpp b/source/shared/core_conn.cpp index 9a41540f..89a6fd32 100644 --- a/source/shared/core_conn.cpp +++ b/source/shared/core_conn.cpp @@ -26,11 +26,8 @@ #include #include #endif // _WIN32 - -#include #include #include -#include #ifndef _WIN32 #include @@ -136,7 +133,7 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont if( options_ht && zend_hash_num_elements( options_ht ) > 0 ) { zval* option_z = NULL; - option_z = zend_hash_index_find(options_ht, SQLSRV_CONN_OPTION_CONN_POOLING); + option_z = zend_hash_index_find( options_ht, SQLSRV_CONN_OPTION_CONN_POOLING ); if ( option_z ) { // if the option was found and it's not true, then use the non pooled environment handle if(( Z_TYPE_P( option_z ) == IS_STRING && !core_str_zval_is_true( option_z )) || !zend_is_true( option_z ) ) { @@ -152,28 +149,28 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont conn = conn_factory( temp_conn_h, err, driver TSRMLS_CC ); conn->set_func( driver_func ); - build_connection_string_and_set_conn_attr(conn, server, uid, pwd, options_ht, valid_conn_opts, driver, conn_str TSRMLS_CC); + build_connection_string_and_set_conn_attr( conn, server, uid, pwd, options_ht, valid_conn_opts, driver, conn_str TSRMLS_CC ); bool missing_driver_error = false; - if (conn->is_driver_set) { + if ( conn->is_driver_set ) { r = core_odbc_connect( conn, conn_str, wconn_string, wconn_len, missing_driver_error, is_pooled); } - else if (conn->ce_option.enabled) { - conn_str = conn_str + CONNECTION_STRING_DRIVER_NAME[DRIVER_VERSION::ODBC_DRIVER_17]; + else if ( conn->ce_option.enabled ) { + 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_AE_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) { throw core::CoreException(); } } 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, wconn_string, wconn_len, missing_driver_error, is_pooled); + conn_str = conn_str + CONNECTION_STRING_DRIVER_NAME[ DRIVER_VERSION(i) ]; + r = core_odbc_connect( conn, conn_str, wconn_string, wconn_len, missing_driver_error, is_pooled ); // if it's a IM002, meaning that the correct ODBC driver is not installed - CHECK_CUSTOM_ERROR(missing_driver_error && (i == DRIVER_VERSION::LAST), conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) { + CHECK_CUSTOM_ERROR( missing_driver_error && ( i == DRIVER_VERSION::LAST ), conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) { throw core::CoreException(); } if ( !missing_driver_error ) { @@ -214,21 +211,21 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont 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() ); + 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 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() ); + 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 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() ); + 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->invalidate(); throw; @@ -247,11 +244,11 @@ SQLRETURN core_odbc_connect(_Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn // We only support UTF-8 encoding for connection string. // Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW - wconn_len = static_cast(conn_str.length() + 1) * sizeof(SQLWCHAR); + wconn_len = static_cast( conn_str.length() + 1 ) * sizeof( SQLWCHAR ); - wconn_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast(conn_str.length()), &wconn_len); + wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast( conn_str.length()), &wconn_len ); - CHECK_CUSTOM_ERROR(wconn_string == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE, get_last_error_message()) + CHECK_CUSTOM_ERROR( wconn_string == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE, get_last_error_message()) { throw core::CoreException(); } @@ -269,24 +266,21 @@ SQLRETURN core_odbc_connect(_Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn r = SQLDriverConnectW(conn->handle(), NULL, wconn_string, static_cast(wconn_len), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT); } #else - r = SQLDriverConnectW(conn->handle(), NULL, wconn_string, static_cast(wconn_len), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT); + r = SQLDriverConnectW( conn->handle(), NULL, wconn_string, static_cast(wconn_len), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT ); #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 + 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 wconn_len = 0; conn_str.clear(); - if (SQL_SUCCEEDED(r)) { - //conn->driver_version = static_cast(odbc_version); - } - else { - SQLCHAR state[SQL_SQLSTATE_BUFSIZE]; + if (!SQL_SUCCEEDED(r)) { + 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'); - } + 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' ); + } return r; } diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index d8df04ac..0c217d31 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -151,6 +151,7 @@ OACR_WARNING_POP #include #include +#include #include #include #include @@ -1067,8 +1068,6 @@ struct sqlsrv_conn : public sqlsrv_context { // instance variables SERVER_VERSION server_version; // version of the server that we're connected to - DRIVER_VERSION driver_version; - col_encryption_option ce_option; // holds the details of what are required to enable column encryption bool is_driver_set; @@ -1077,7 +1076,6 @@ struct sqlsrv_conn : public sqlsrv_context { sqlsrv_context( h, SQL_HANDLE_DBC, e, drv, encoding ) { server_version = SERVER_VERSION_UNKNOWN; - driver_version = ODBC_DRIVER_UNKNOWN; is_driver_set = false; } @@ -1201,6 +1199,8 @@ struct connection_option { void (*func)( connection_option const*, zval* value, sqlsrv_conn* conn, std::string& conn_str TSRMLS_DC ); }; +// connection attribute functions + // simply add the parsed value to the connection string struct conn_str_append_func { @@ -1212,6 +1212,21 @@ struct conn_null_func { static void func( connection_option const* /*option*/, zval* /*value*/, sqlsrv_conn* /*conn*/, std::string& /*conn_str*/ TSRMLS_DC ); }; +template +struct str_conn_attr_func { + + static void func(connection_option const* /*option*/, zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC) + { + try { + core::SQLSetConnectAttr(conn, Attr, reinterpret_cast(Z_STRVAL_P(value)), + static_cast(Z_STRLEN_P(value)) TSRMLS_CC); + } + catch (core::CoreException&) { + throw; + } + } +}; + struct column_encryption_set_func { static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC); @@ -1239,7 +1254,8 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont _Inout_z_ const char* server, _Inout_opt_z_ const char* uid, _Inout_opt_z_ const char* pwd, _Inout_opt_ HashTable* options_ht, _In_ error_callback err, _In_ const connection_option valid_conn_opts[], _In_ void* driver, _In_z_ const char* driver_func TSRMLS_DC ); -SQLRETURN core_odbc_connect( _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str, _Inout_ SQLWCHAR* wconn_string, _Inout_ unsigned int& wconn_len, _Inout_ bool& missing_driver_error); +SQLRETURN core_odbc_connect( _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str, _Inout_ SQLWCHAR* wconn_string, + _Inout_ unsigned int& wconn_len, _Inout_ bool& missing_driver_error, _In_ bool is_pooled); void core_sqlsrv_close( _Inout_opt_ sqlsrv_conn* conn TSRMLS_DC ); void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) const char* sql, _In_ SQLLEN sql_len TSRMLS_DC ); void core_sqlsrv_begin_transaction( _Inout_ sqlsrv_conn* conn TSRMLS_DC ); @@ -1692,10 +1708,6 @@ enum SQLSRV_ERROR_CODES { }; -// the message returned by ODBC Driver 11 for SQL Server -static const char* CONNECTION_BUSY_ODBC_ERROR[] = { "[Microsoft][ODBC Driver 13 for SQL Server]Connection is busy with results for another command", - "[Microsoft][ODBC Driver 11 for SQL Server]Connection is busy with results for another command" }; - // SQLSTATE for all internal errors extern SQLCHAR IMSSP[]; @@ -1871,8 +1883,12 @@ namespace core { throw CoreException(); } - std::size_t driver_version = stmt->conn->driver_version; - if( !strcmp( reinterpret_cast( err_msg ), CONNECTION_BUSY_ODBC_ERROR[driver_version] )) { + + // the message returned by ODBC Driver for SQL Server + 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 )) { THROW_CORE_ERROR( stmt, SQLSRV_ERROR_MARS_OFF ); } @@ -2420,20 +2436,5 @@ sqlsrv_conn* allocate_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* } // namespace core -// connection attribute functions -template -struct str_conn_attr_func { - - static void func( connection_option const* /*option*/, zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) - { - try { - core::SQLSetConnectAttr( conn, Attr, reinterpret_cast( Z_STRVAL_P( value )), - static_cast(Z_STRLEN_P( value )) TSRMLS_CC ); - } - catch( core::CoreException& ) { - throw; - } - } -}; #endif // CORE_SQLSRV_H