Merge pull request #989 from david-puglielli/issue-432-fix

Issue #432 fix
This commit is contained in:
David Puglielli 2019-05-13 15:24:18 -07:00 committed by GitHub
commit f369ce6212
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 44 additions and 99 deletions

View file

@ -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.
// 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())
{

View file

@ -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 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 );
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

View file

@ -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,
_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 = false );
}
// 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
// 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,
_Out_ unsigned int* utf16_len )
_Out_ unsigned int* utf16_len, bool use_strict_conversion )
{
*utf16_len = (mbcs_len + 1);
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 ) {
// we preserve the error and reset it because sqlsrv_free resets the last error
@ -384,7 +384,7 @@ namespace {
// to convert.
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 utf16_len )
_In_ unsigned int utf16_len, bool use_strict_conversion )
{
unsigned int win_encoding = CP_ACP;
switch( php_encoding ) {
@ -399,8 +399,14 @@ unsigned int convert_string_from_default_encoding( _In_ unsigned int php_encodin
win_encoding = php_encoding;
break;
}
#ifndef _WIN32
unsigned int required_len = SystemLocale::ToUtf16( win_encoding, mbcs_in_string, mbcs_len, utf16_out_string, utf16_len );
#ifndef _WIN32
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
unsigned int required_len = MultiByteToWideChar( win_encoding, MB_ERR_INVALID_CHARS, mbcs_in_string, mbcs_len, utf16_out_string, utf16_len );
#endif // !_Win32
@ -610,4 +616,4 @@ namespace data_classification {
columns_sensitivity.clear();
}
} // namespace data_classification
} // namespace data_classification

View file

@ -214,12 +214,12 @@ bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_err
// 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,
_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
// 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.
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 ***
bool handle_error( sqlsrv_context const* ctx, int log_subsystem, const char* function,

View file

@ -38,7 +38,7 @@ function invalidServer()
echo "Should have failed to connect to invalid server.\n";
} catch (PDOException $e) {
$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())) {
; // matched at least one of the expected error messages
} else {
@ -102,7 +102,7 @@ function invalidPassword()
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
// 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 \'*\'.";
$error2 = "*Login timeout expired*";

View file

@ -1,11 +1,18 @@
--TEST--
UTF-8 connection strings
--SKIPIF--
<?php require('skipif_unix.inc'); ?>
<?php require('skipif.inc'); ?>
--FILE--
<?php
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())
{
global $server, $uid, $pwd, $databaseName;
@ -22,6 +29,17 @@ function connect($options=array())
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('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
@ -30,13 +48,13 @@ $c = connect(array( 'CharacterSet' => 'gibberish' ));
if ($c !== false) {
fatalError("Should have errored on an invalid encoding.");
}
print_r(sqlsrv_errors());
checkErrors($gibberishEncoding);
$c = connect(array( 'CharacterSet' => SQLSRV_ENC_BINARY ));
if ($c !== false) {
fatalError("Should have errored on an invalid encoding.");
}
print_r(sqlsrv_errors());
checkErrors($binaryEncoding);
$c = connect(array( 'CharacterSet' => SQLSRV_ENC_CHAR ));
if ($c === false) {
@ -50,7 +68,7 @@ $c = sqlsrv_connect($server_invalid, array( 'Database' => 'test', 'CharacterSet'
if ($c !== false) {
fatalError("sqlsrv_connect(1) should have failed");
}
print_r(sqlsrv_errors());
checkErrors($utf16Error);
// APP has a UTF-8 name
$c = connect(array(
@ -67,7 +85,7 @@ $c = connect(array(
if ($c !== false) {
fatalError("sqlsrv_connect(3) should have failed");
}
print_r(sqlsrv_errors());
checkErrors($userLoginFailed);
// invalid UTF-8 in the pwd
$c = connect(array(
@ -77,89 +95,10 @@ $c = connect(array(
if ($c !== false) {
fatalError("sqlsrv_connect(4) should have failed");
}
print_r(sqlsrv_errors());
checkErrors($utf16Error);
echo "Test succeeded.\n";
?>
--EXPECTF--
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.
)
)
--EXPECT--
Test succeeded.