refactored odbc connect, added ae connect error
This commit is contained in:
parent
278a27c3aa
commit
f25677e457
|
@ -380,7 +380,12 @@ pdo_error PDO_ERRORS[] = {
|
|||
{
|
||||
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
|
||||
{ IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.", -73, false }
|
||||
},
|
||||
},
|
||||
{
|
||||
SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED,
|
||||
{ IMSSP, (SQLCHAR*) "This extension requires Microsoft ODBC Driver 17 or higher to "
|
||||
"communicate with SQL Server with ColumnEncryption attribute enabled.", -74, false }
|
||||
},
|
||||
{ UINT_MAX, {} }
|
||||
};
|
||||
|
||||
|
|
|
@ -50,7 +50,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 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};"};
|
||||
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};"};
|
||||
|
||||
// default options if only the server is specified
|
||||
const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes}";
|
||||
|
@ -144,60 +144,29 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont
|
|||
core::SQLAllocHandle( SQL_HANDLE_DBC, *henv, &temp_conn_h TSRMLS_CC );
|
||||
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_options TSRMLS_CC);
|
||||
|
||||
for( std::size_t i = DRIVER_VERSION::MIN; i <= DRIVER_VERSION::MAX; ++i ) {
|
||||
std::string conn_str = conn_options + CONNECTION_STRING_DRIVER_NAME[i];
|
||||
|
||||
// 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<unsigned int>( conn_str.length() + 1 ) * sizeof( SQLWCHAR );
|
||||
build_connection_string_and_set_conn_attr(conn, server, uid, pwd, options_ht, valid_conn_opts, driver, conn_options TSRMLS_CC);
|
||||
bool missing_driver_error = false;
|
||||
if (conn->ce_option.enabled) {
|
||||
r = core_odbc_connect(conn, conn_options, DRIVER_VERSION::ODBC_DRIVER_13, wconn_string, wconn_len, missing_driver_error);
|
||||
|
||||
wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<unsigned int>(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(missing_driver_error, conn, SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
SQLSMALLINT output_conn_size;
|
||||
#ifndef _WIN32
|
||||
// unixODBC 2.3.1 requires a non-wide SQLDriverConnect call while pooling enabled.
|
||||
// connection handle has been allocated using henv_cp, means pooling enabled in a PHP script
|
||||
if ( henv == &henv_cp )
|
||||
{
|
||||
r = SQLDriverConnect( conn->handle(), NULL, (SQLCHAR*)conn_str.c_str(), SQL_NTS, NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
}
|
||||
else
|
||||
{
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
}
|
||||
#else
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
#endif // !_WIN32
|
||||
else {
|
||||
|
||||
// clear the connection string from memory to remove sensitive data (such as a password).
|
||||
memset( const_cast<char*>(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();
|
||||
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 );
|
||||
bool missing_driver_error = ( SQL_SUCCEEDED( sr ) && state[0] == 'I' && state[1] == 'M' && state[2] == '0' && state[3] == '0' && state[4] == '2' );
|
||||
for (std::size_t i = DRIVER_VERSION::ODBC_DRIVER_11; i <= DRIVER_VERSION::LAST; ++i) {
|
||||
r = core_odbc_connect(conn, conn_options, static_cast<DRIVER_VERSION>(i), wconn_string, wconn_len, missing_driver_error);
|
||||
// if it's a IM002, meaning that the correct ODBC driver is not installed
|
||||
CHECK_CUSTOM_ERROR(missing_driver_error && ( i == DRIVER_VERSION::MAX ), 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 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
conn->driver_version = static_cast<DRIVER_VERSION>( i );
|
||||
break;
|
||||
}
|
||||
} // for
|
||||
} // for
|
||||
} // else ce_option enabled
|
||||
|
||||
CHECK_SQL_ERROR( r, conn ) {
|
||||
throw core::CoreException();
|
||||
|
@ -256,6 +225,54 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont
|
|||
return return_conn;
|
||||
}
|
||||
|
||||
SQLRETURN core_odbc_connect(_Inout_ sqlsrv_conn* conn, const std::string& conn_options, const DRIVER_VERSION odbc_version, SQLWCHAR* wconn_string, unsigned int& wconn_len,bool missing_driver_error)
|
||||
{
|
||||
SQLRETURN r = SQL_SUCCESS;
|
||||
std::string conn_str = conn_options + CONNECTION_STRING_DRIVER_NAME[odbc_version];
|
||||
|
||||
// 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<unsigned int>(conn_str.length() + 1) * sizeof(SQLWCHAR);
|
||||
|
||||
wconn_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<unsigned int>(conn_str.length()), &wconn_len);
|
||||
|
||||
CHECK_CUSTOM_ERROR(wconn_string == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE, get_last_error_message())
|
||||
{
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
SQLSMALLINT output_conn_size;
|
||||
#ifndef _WIN32
|
||||
// unixODBC 2.3.1 requires a non-wide SQLDriverConnect call while pooling enabled.
|
||||
// connection handle has been allocated using henv_cp, means pooling enabled in a PHP script
|
||||
if (henv == &henv_cp)
|
||||
{
|
||||
r = SQLDriverConnect(conn->handle(), NULL, (SQLCHAR*)conn_str.c_str(), SQL_NTS, NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = SQLDriverConnectW(conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>(wconn_string.get()), static_cast<SQLSMALLINT>(wconn_len), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT);
|
||||
}
|
||||
#else
|
||||
r = SQLDriverConnectW(conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>(wconn_string), static_cast<SQLSMALLINT>(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<char*>(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();
|
||||
|
||||
if (SQL_SUCCEEDED(r)) {
|
||||
conn->driver_version = static_cast<DRIVER_VERSION>(odbc_version);
|
||||
}
|
||||
else {
|
||||
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');
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
// core_sqlsrv_begin_transaction
|
||||
|
|
|
@ -1034,10 +1034,11 @@ enum SERVER_VERSION {
|
|||
|
||||
// supported driver versions.
|
||||
enum DRIVER_VERSION : size_t {
|
||||
MIN = 0,
|
||||
ODBC_DRIVER_13 = MIN,
|
||||
ODBC_DRIVER_11 = 1,
|
||||
MAX = ODBC_DRIVER_11,
|
||||
FIRST = 0,
|
||||
ODBC_DRIVER_17 = FIRST,
|
||||
ODBC_DRIVER_13 = 1,
|
||||
ODBC_DRIVER_11 = 2,
|
||||
LAST = ODBC_DRIVER_11
|
||||
};
|
||||
|
||||
// forward decl
|
||||
|
@ -1205,6 +1206,7 @@ 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, const std::string& conn_options, const DRIVER_VERSION odbc_version, SQLWCHAR* wconn_string, unsigned int& wconn_len, bool missing_driver_error);
|
||||
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 );
|
||||
|
@ -1608,6 +1610,7 @@ enum SQLSRV_ERROR_CODES {
|
|||
|
||||
SQLSRV_ERROR_ODBC,
|
||||
SQLSRV_ERROR_DRIVER_NOT_INSTALLED,
|
||||
SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED,
|
||||
SQLSRV_ERROR_ZEND_HASH,
|
||||
SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE,
|
||||
SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE,
|
||||
|
|
|
@ -376,6 +376,11 @@ ss_error SS_ERRORS[] = {
|
|||
SS_SQLSRV_WARNING_FIELD_NAME_EMPTY,
|
||||
{ SSPWARN, (SQLCHAR*)"An empty field name was skipped by sqlsrv_fetch_object.", -100, false }
|
||||
},
|
||||
{
|
||||
SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED,
|
||||
{ IMSSP, (SQLCHAR*) "This extension requires Microsoft ODBC Driver 17 or higher to "
|
||||
"communicate with SQL Server with ColumnEncryption attribute enabled.", -105, false }
|
||||
},
|
||||
|
||||
// terminate the list of errors/warnings
|
||||
{ UINT_MAX, {} }
|
||||
|
|
Loading…
Reference in a new issue