Merge pull request #989 from david-puglielli/issue-432-fix
Issue #432 fix
This commit is contained in:
commit
f369ce6212
|
@ -386,7 +386,7 @@ SQLRETURN core_odbc_connect( _Inout_ sqlsrv_conn* conn, _Inout_ std::string& con
|
||||||
|
|
||||||
// We only support UTF-8 encoding for connection string.
|
// We only support UTF-8 encoding for connection string.
|
||||||
// Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW
|
// Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW
|
||||||
wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<unsigned int>( conn_str.length() ), &wconn_len );
|
wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<unsigned int>( conn_str.length() ), &wconn_len, true );
|
||||||
|
|
||||||
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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -1808,7 +1808,7 @@ struct sqlsrv_buffered_result_set : public sqlsrv_result_set {
|
||||||
bool convert_string_from_utf16_inplace( _In_ SQLSRV_ENCODING encoding, _Inout_updates_z_(len) char** string, _Inout_ SQLLEN& len);
|
bool convert_string_from_utf16_inplace( _In_ SQLSRV_ENCODING encoding, _Inout_updates_z_(len) char** string, _Inout_ SQLLEN& len);
|
||||||
bool validate_string( _In_ char* string, _In_ SQLLEN& len);
|
bool validate_string( _In_ char* string, _In_ SQLLEN& len);
|
||||||
bool convert_string_from_utf16( _In_ SQLSRV_ENCODING encoding, _In_reads_bytes_(cchInLen) const SQLWCHAR* inString, _In_ SQLINTEGER cchInLen, _Inout_updates_bytes_(cchOutLen) char** outString, _Out_ SQLLEN& cchOutLen );
|
bool convert_string_from_utf16( _In_ SQLSRV_ENCODING encoding, _In_reads_bytes_(cchInLen) const SQLWCHAR* inString, _In_ SQLINTEGER cchInLen, _Inout_updates_bytes_(cchOutLen) char** outString, _Out_ SQLLEN& cchOutLen );
|
||||||
SQLWCHAR* utf16_string_from_mbcs_string( _In_ SQLSRV_ENCODING php_encoding, _In_reads_bytes_(mbcs_len) const char* mbcs_string, _In_ unsigned int mbcs_len, _Out_ unsigned int* utf16_len );
|
SQLWCHAR* utf16_string_from_mbcs_string( _In_ SQLSRV_ENCODING php_encoding, _In_reads_bytes_(mbcs_len) const char* mbcs_string, _In_ unsigned int mbcs_len, _Out_ unsigned int* utf16_len, bool use_strict_conversion = false );
|
||||||
|
|
||||||
//*********************************************************************************************************************************
|
//*********************************************************************************************************************************
|
||||||
// Error handling routines and Predefined Errors
|
// Error handling routines and Predefined Errors
|
||||||
|
|
|
@ -34,7 +34,7 @@ char last_err_msg[2048] = {'\0'}; // 2k to hold the error messages
|
||||||
unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encoding, _In_reads_bytes_(mbcs_len) char const* mbcs_in_string,
|
unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encoding, _In_reads_bytes_(mbcs_len) char const* mbcs_in_string,
|
||||||
_In_ unsigned int mbcs_len,
|
_In_ unsigned int mbcs_len,
|
||||||
_Out_writes_(utf16_len) __transfer( mbcs_in_string ) SQLWCHAR* utf16_out_string,
|
_Out_writes_(utf16_len) __transfer( mbcs_in_string ) SQLWCHAR* utf16_out_string,
|
||||||
_In_ unsigned int utf16_len );
|
_In_ unsigned int utf16_len, bool use_strict_conversion = false );
|
||||||
}
|
}
|
||||||
|
|
||||||
// SQLSTATE for all internal errors
|
// SQLSTATE for all internal errors
|
||||||
|
@ -172,11 +172,11 @@ bool convert_string_from_utf16( _In_ SQLSRV_ENCODING encoding, _In_reads_bytes_(
|
||||||
// allocation of the destination string. An empty string passed in returns
|
// allocation of the destination string. An empty string passed in returns
|
||||||
// failure since it's a failure case for convert_string_from_default_encoding.
|
// failure since it's a failure case for convert_string_from_default_encoding.
|
||||||
SQLWCHAR* utf16_string_from_mbcs_string( _In_ SQLSRV_ENCODING php_encoding, _In_reads_bytes_(mbcs_len) const char* mbcs_string, _In_ unsigned int mbcs_len,
|
SQLWCHAR* utf16_string_from_mbcs_string( _In_ SQLSRV_ENCODING php_encoding, _In_reads_bytes_(mbcs_len) const char* mbcs_string, _In_ unsigned int mbcs_len,
|
||||||
_Out_ unsigned int* utf16_len )
|
_Out_ unsigned int* utf16_len, bool use_strict_conversion )
|
||||||
{
|
{
|
||||||
*utf16_len = (mbcs_len + 1);
|
*utf16_len = (mbcs_len + 1);
|
||||||
SQLWCHAR* utf16_string = reinterpret_cast<SQLWCHAR*>( sqlsrv_malloc( *utf16_len * sizeof( SQLWCHAR )));
|
SQLWCHAR* utf16_string = reinterpret_cast<SQLWCHAR*>( sqlsrv_malloc( *utf16_len * sizeof( SQLWCHAR )));
|
||||||
*utf16_len = convert_string_from_default_encoding( php_encoding, mbcs_string, mbcs_len, utf16_string, *utf16_len );
|
*utf16_len = convert_string_from_default_encoding( php_encoding, mbcs_string, mbcs_len, utf16_string, *utf16_len, use_strict_conversion );
|
||||||
|
|
||||||
if( *utf16_len == 0 ) {
|
if( *utf16_len == 0 ) {
|
||||||
// we preserve the error and reset it because sqlsrv_free resets the last error
|
// we preserve the error and reset it because sqlsrv_free resets the last error
|
||||||
|
@ -384,7 +384,7 @@ namespace {
|
||||||
// to convert.
|
// to convert.
|
||||||
unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encoding, _In_reads_bytes_(mbcs_len) char const* mbcs_in_string,
|
unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encoding, _In_reads_bytes_(mbcs_len) char const* mbcs_in_string,
|
||||||
_In_ unsigned int mbcs_len, _Out_writes_(utf16_len) __transfer( mbcs_in_string ) SQLWCHAR* utf16_out_string,
|
_In_ unsigned int mbcs_len, _Out_writes_(utf16_len) __transfer( mbcs_in_string ) SQLWCHAR* utf16_out_string,
|
||||||
_In_ unsigned int utf16_len )
|
_In_ unsigned int utf16_len, bool use_strict_conversion )
|
||||||
{
|
{
|
||||||
unsigned int win_encoding = CP_ACP;
|
unsigned int win_encoding = CP_ACP;
|
||||||
switch( php_encoding ) {
|
switch( php_encoding ) {
|
||||||
|
@ -400,7 +400,13 @@ unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encodin
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
unsigned int required_len = SystemLocale::ToUtf16( win_encoding, mbcs_in_string, mbcs_len, utf16_out_string, utf16_len );
|
unsigned int required_len;
|
||||||
|
if (use_strict_conversion) {
|
||||||
|
required_len = SystemLocale::ToUtf16Strict( win_encoding, mbcs_in_string, mbcs_len, utf16_out_string, utf16_len );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
required_len = SystemLocale::ToUtf16( win_encoding, mbcs_in_string, mbcs_len, utf16_out_string, utf16_len );
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
unsigned int required_len = MultiByteToWideChar( win_encoding, MB_ERR_INVALID_CHARS, mbcs_in_string, mbcs_len, utf16_out_string, utf16_len );
|
unsigned int required_len = MultiByteToWideChar( win_encoding, MB_ERR_INVALID_CHARS, mbcs_in_string, mbcs_len, utf16_out_string, utf16_len );
|
||||||
#endif // !_Win32
|
#endif // !_Win32
|
||||||
|
|
|
@ -214,12 +214,12 @@ bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_err
|
||||||
// returned in utf16_out_string.
|
// returned in utf16_out_string.
|
||||||
unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encoding, _In_reads_bytes_(mbcs_len) char const* mbcs_in_string,
|
unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encoding, _In_reads_bytes_(mbcs_len) char const* mbcs_in_string,
|
||||||
_In_ unsigned int mbcs_len, _Out_writes_(utf16_len) __transfer(mbcs_in_string) wchar_t* utf16_out_string,
|
_In_ unsigned int mbcs_len, _Out_writes_(utf16_len) __transfer(mbcs_in_string) wchar_t* utf16_out_string,
|
||||||
_In_ unsigned int utf16_len );
|
_In_ unsigned int utf16_len, bool use_strict_conversion = false );
|
||||||
// create a wide char string from the passed in mbcs string. NULL is returned if the string
|
// create a wide char string from the passed in mbcs string. NULL is returned if the string
|
||||||
// could not be created. No error is posted by this function. utf16_len is the number of
|
// could not be created. No error is posted by this function. utf16_len is the number of
|
||||||
// wchar_t characters, not the number of bytes.
|
// wchar_t characters, not the number of bytes.
|
||||||
SQLWCHAR* utf16_string_from_mbcs_string( _In_ unsigned int php_encoding, _In_reads_bytes_(mbcs_len) const char* mbcs_string,
|
SQLWCHAR* utf16_string_from_mbcs_string( _In_ unsigned int php_encoding, _In_reads_bytes_(mbcs_len) const char* mbcs_string,
|
||||||
_In_ unsigned int mbcs_len, _Out_ unsigned int* utf16_len );
|
_In_ unsigned int mbcs_len, _Out_ unsigned int* utf16_len, bool use_strict_conversion = false );
|
||||||
|
|
||||||
// *** internal error macros and functions ***
|
// *** internal error macros and functions ***
|
||||||
bool handle_error( sqlsrv_context const* ctx, int log_subsystem, const char* function,
|
bool handle_error( sqlsrv_context const* ctx, int log_subsystem, const char* function,
|
||||||
|
|
|
@ -38,7 +38,7 @@ function invalidServer()
|
||||||
echo "Should have failed to connect to invalid server.\n";
|
echo "Should have failed to connect to invalid server.\n";
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
$error1 = '*Login timeout expired';
|
$error1 = '*Login timeout expired';
|
||||||
$error2 = '*An error occurred translating the connection string to UTF-16: No mapping for the Unicode character exists in the target multi-byte code page*';
|
$error2 = '*An error occurred translating the connection string to UTF-16: *';
|
||||||
if (fnmatch($error1, $e->getMessage()) || fnmatch($error2, $e->getMessage())) {
|
if (fnmatch($error1, $e->getMessage()) || fnmatch($error2, $e->getMessage())) {
|
||||||
; // matched at least one of the expected error messages
|
; // matched at least one of the expected error messages
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,7 +102,7 @@ function invalidPassword()
|
||||||
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
|
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
// Possible errors
|
// Possible errors
|
||||||
$error = "*An error occurred translating the connection string to UTF-16: No mapping for the Unicode character exists in the target multi-byte code page.*";
|
$error = "*An error occurred translating the connection string to UTF-16: *";
|
||||||
$error1 = "*Login failed for user \'*\'.";
|
$error1 = "*Login failed for user \'*\'.";
|
||||||
$error2 = "*Login timeout expired*";
|
$error2 = "*Login timeout expired*";
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
--TEST--
|
--TEST--
|
||||||
UTF-8 connection strings
|
UTF-8 connection strings
|
||||||
--SKIPIF--
|
--SKIPIF--
|
||||||
<?php require('skipif_unix.inc'); ?>
|
<?php require('skipif.inc'); ?>
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once('MsSetup.inc');
|
require_once('MsSetup.inc');
|
||||||
|
|
||||||
|
// Expected errors
|
||||||
|
$gibberishEncoding = array('IMSSP', '-48', "The encoding 'gibberish' is not a supported encoding for the CharacterSet connection option.");
|
||||||
|
$binaryEncoding = array('IMSSP', '-48', "The encoding 'binary' is not a supported encoding for the CharacterSet connection option.");
|
||||||
|
$utf16Error = array('IMSSP', '-47', "An error occurred translating the connection string to UTF-16: *");
|
||||||
|
$userLoginFailed = array('28000', '18456', "*Login failed for user *");
|
||||||
|
|
||||||
function connect($options=array())
|
function connect($options=array())
|
||||||
{
|
{
|
||||||
global $server, $uid, $pwd, $databaseName;
|
global $server, $uid, $pwd, $databaseName;
|
||||||
|
@ -22,6 +29,17 @@ function connect($options=array())
|
||||||
return sqlsrv_connect($server, $options);
|
return sqlsrv_connect($server, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkErrors($expectedError)
|
||||||
|
{
|
||||||
|
// On Windows one call returns two identical errors, so just take the first element
|
||||||
|
$error = sqlsrv_errors()[0];
|
||||||
|
if (!fnmatch($expectedError[0], $error[0]) ||
|
||||||
|
!fnmatch($expectedError[1], $error[1]) ||
|
||||||
|
!fnmatch($expectedError[2], $error[2])) {
|
||||||
|
fatalError("Errors do not match!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sqlsrv_configure('WarningsReturnAsErrors', 0);
|
sqlsrv_configure('WarningsReturnAsErrors', 0);
|
||||||
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
|
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
|
||||||
|
|
||||||
|
@ -30,13 +48,13 @@ $c = connect(array( 'CharacterSet' => 'gibberish' ));
|
||||||
if ($c !== false) {
|
if ($c !== false) {
|
||||||
fatalError("Should have errored on an invalid encoding.");
|
fatalError("Should have errored on an invalid encoding.");
|
||||||
}
|
}
|
||||||
print_r(sqlsrv_errors());
|
checkErrors($gibberishEncoding);
|
||||||
|
|
||||||
$c = connect(array( 'CharacterSet' => SQLSRV_ENC_BINARY ));
|
$c = connect(array( 'CharacterSet' => SQLSRV_ENC_BINARY ));
|
||||||
if ($c !== false) {
|
if ($c !== false) {
|
||||||
fatalError("Should have errored on an invalid encoding.");
|
fatalError("Should have errored on an invalid encoding.");
|
||||||
}
|
}
|
||||||
print_r(sqlsrv_errors());
|
checkErrors($binaryEncoding);
|
||||||
|
|
||||||
$c = connect(array( 'CharacterSet' => SQLSRV_ENC_CHAR ));
|
$c = connect(array( 'CharacterSet' => SQLSRV_ENC_CHAR ));
|
||||||
if ($c === false) {
|
if ($c === false) {
|
||||||
|
@ -50,7 +68,7 @@ $c = sqlsrv_connect($server_invalid, array( 'Database' => 'test', 'CharacterSet'
|
||||||
if ($c !== false) {
|
if ($c !== false) {
|
||||||
fatalError("sqlsrv_connect(1) should have failed");
|
fatalError("sqlsrv_connect(1) should have failed");
|
||||||
}
|
}
|
||||||
print_r(sqlsrv_errors());
|
checkErrors($utf16Error);
|
||||||
|
|
||||||
// APP has a UTF-8 name
|
// APP has a UTF-8 name
|
||||||
$c = connect(array(
|
$c = connect(array(
|
||||||
|
@ -67,7 +85,7 @@ $c = connect(array(
|
||||||
if ($c !== false) {
|
if ($c !== false) {
|
||||||
fatalError("sqlsrv_connect(3) should have failed");
|
fatalError("sqlsrv_connect(3) should have failed");
|
||||||
}
|
}
|
||||||
print_r(sqlsrv_errors());
|
checkErrors($userLoginFailed);
|
||||||
|
|
||||||
// invalid UTF-8 in the pwd
|
// invalid UTF-8 in the pwd
|
||||||
$c = connect(array(
|
$c = connect(array(
|
||||||
|
@ -77,89 +95,10 @@ $c = connect(array(
|
||||||
if ($c !== false) {
|
if ($c !== false) {
|
||||||
fatalError("sqlsrv_connect(4) should have failed");
|
fatalError("sqlsrv_connect(4) should have failed");
|
||||||
}
|
}
|
||||||
print_r(sqlsrv_errors());
|
checkErrors($utf16Error);
|
||||||
|
|
||||||
echo "Test succeeded.\n";
|
echo "Test succeeded.\n";
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECT--
|
||||||
Array
|
|
||||||
(
|
|
||||||
[0] => Array
|
|
||||||
(
|
|
||||||
[0] => IMSSP
|
|
||||||
[SQLSTATE] => IMSSP
|
|
||||||
[1] => -48
|
|
||||||
[code] => -48
|
|
||||||
[2] => The encoding 'gibberish' is not a supported encoding for the CharacterSet connection option.
|
|
||||||
[message] => The encoding 'gibberish' is not a supported encoding for the CharacterSet connection option.
|
|
||||||
)
|
|
||||||
|
|
||||||
)
|
|
||||||
Array
|
|
||||||
(
|
|
||||||
[0] => Array
|
|
||||||
(
|
|
||||||
[0] => IMSSP
|
|
||||||
[SQLSTATE] => IMSSP
|
|
||||||
[1] => -48
|
|
||||||
[code] => -48
|
|
||||||
[2] => The encoding 'binary' is not a supported encoding for the CharacterSet connection option.
|
|
||||||
[message] => The encoding 'binary' is not a supported encoding for the CharacterSet connection option.
|
|
||||||
)
|
|
||||||
|
|
||||||
)
|
|
||||||
Array
|
|
||||||
(
|
|
||||||
[0] => Array
|
|
||||||
(
|
|
||||||
[0] => IMSSP
|
|
||||||
[SQLSTATE] => IMSSP
|
|
||||||
[1] => -47
|
|
||||||
[code] => -47
|
|
||||||
[2] => An error occurred translating the connection string to UTF-16: No mapping for the Unicode character exists in the target multi-byte code page.
|
|
||||||
|
|
||||||
[message] => An error occurred translating the connection string to UTF-16: No mapping for the Unicode character exists in the target multi-byte code page.
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
)
|
|
||||||
Array
|
|
||||||
(
|
|
||||||
[0] => Array
|
|
||||||
(
|
|
||||||
[0] => 28000
|
|
||||||
[SQLSTATE] => 28000
|
|
||||||
[1] => 18456
|
|
||||||
[code] => 18456
|
|
||||||
[2] => %SLogin failed for user '%s'.
|
|
||||||
[message] => %SLogin failed for user '%s'.
|
|
||||||
)
|
|
||||||
|
|
||||||
[1] => Array
|
|
||||||
(
|
|
||||||
[0] => 28000
|
|
||||||
[SQLSTATE] => 28000
|
|
||||||
[1] => 18456
|
|
||||||
[code] => 18456
|
|
||||||
[2] => %SLogin failed for user '%s'.
|
|
||||||
[message] => %SLogin failed for user '%s'.
|
|
||||||
)
|
|
||||||
|
|
||||||
)
|
|
||||||
Array
|
|
||||||
(
|
|
||||||
[0] => Array
|
|
||||||
(
|
|
||||||
[0] => IMSSP
|
|
||||||
[SQLSTATE] => IMSSP
|
|
||||||
[1] => -47
|
|
||||||
[code] => -47
|
|
||||||
[2] => An error occurred translating the connection string to UTF-16: No mapping for the Unicode character exists in the target multi-byte code page.
|
|
||||||
|
|
||||||
[message] => An error occurred translating the connection string to UTF-16: No mapping for the Unicode character exists in the target multi-byte code page.
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
)
|
|
||||||
Test succeeded.
|
Test succeeded.
|
||||||
|
|
Loading…
Reference in a new issue