From 08c9ca87e1a305ba7d6e6cb604baeec10408efa6 Mon Sep 17 00:00:00 2001 From: Hadis Kakanejadi Fard Date: Fri, 20 Jan 2017 15:14:46 -0800 Subject: [PATCH] merged conversion functions in core_sqlsrv and core_util --- source/shared/core_sqlsrv.h | 54 +++++++++++++++++------------- source/shared/core_util.cpp | 67 +++++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 48 deletions(-) diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index b278ac81..cd65e633 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -226,7 +226,7 @@ void core_sqlsrv_register_logger( log_callback ); void write_to_log( unsigned int severity TSRMLS_DC, const char* msg, ... ); // a macro to make it convenient to use the function. -#define LOG( severity, msg, ...) write_to_log( severity TSRMLS_CC, msg, __VA_ARGS__ ) +#define LOG( severity, msg, ...) write_to_log( severity TSRMLS_CC, msg, ## __VA_ARGS__ ) // mask for filtering which severities are written to the log enum logging_severity { @@ -238,7 +238,7 @@ enum logging_severity { // Kill the PHP process and log the message to PHP void die( const char* msg, ... ); -#define DIE( msg, ... ) { die( msg, __VA_ARGS__ ); } +#define DIE( msg, ... ) { die( msg, ## __VA_ARGS__ ); } //********************************************************************************************************************************* @@ -588,9 +588,9 @@ public: // free the original pointer and assign a new pointer. Use NULL to simply free the pointer. void reset( T* ptr = NULL ) { - if( _ptr ) - sqlsrv_free( (void*) _ptr ); - _ptr = ptr; + if( sqlsrv_auto_ptr >::_ptr ) + sqlsrv_free( (void*) sqlsrv_auto_ptr >::_ptr ); + sqlsrv_auto_ptr >::_ptr = ptr; } T* operator=( T* ptr ) @@ -608,8 +608,8 @@ public: // DO NOT CALL sqlsrv_realloc with a sqlsrv_malloc_auto_ptr. Use the resize member function. // has the same parameter list as sqlsrv_realloc: new_size is the size in bytes of the newly allocated buffer void resize( size_t new_size ) - { - _ptr = reinterpret_cast( sqlsrv_realloc( _ptr, new_size )); + { + sqlsrv_auto_ptr >::_ptr = reinterpret_cast( sqlsrv_realloc( sqlsrv_auto_ptr >::_ptr, new_size )); } }; @@ -776,7 +776,7 @@ public: { sqlsrv_error* p = src.get(); src.transferred(); - this->_ptr = p; + reset( p ); } }; @@ -804,8 +804,8 @@ class sqlsrv_context { sqlsrv_context( SQLSMALLINT type, error_callback e, void* drv, SQLSRV_ENCODING encoding = SQLSRV_ENCODING_INVALID ) : handle_( SQL_NULL_HANDLE ), handle_type_( type ), - err_( e ), name_( NULL ), + err_( e ), driver_( drv ), last_error_(), encoding_( encoding ) @@ -815,8 +815,8 @@ class sqlsrv_context { sqlsrv_context( SQLHANDLE h, SQLSMALLINT t, error_callback e, void* drv, SQLSRV_ENCODING encoding = SQLSRV_ENCODING_INVALID ) : handle_( h ), handle_type_( t ), - err_( e ), name_( NULL ), + err_( e ), driver_( drv ), last_error_(), encoding_( encoding ) @@ -826,13 +826,17 @@ class sqlsrv_context { sqlsrv_context( sqlsrv_context const& ctx ) : handle_( ctx.handle_ ), handle_type_( ctx.handle_type_ ), - err_( ctx.err_ ), name_( ctx.name_ ), + err_( ctx.err_ ), driver_( ctx.driver_ ), last_error_( ctx.last_error_ ) { } + virtual ~sqlsrv_context() + { + } + void set_func( const char* f ) { name_ = f; @@ -997,6 +1001,8 @@ struct sqlsrv_conn : public sqlsrv_context { sqlsrv_conn( SQLHANDLE h, error_callback e, void* drv, SQLSRV_ENCODING encoding TSRMLS_DC ) : sqlsrv_context( h, SQL_HANDLE_DBC, e, drv, encoding ) { + server_version = SERVER_VERSION_UNKNOWN; + driver_version = ODBC_DRIVER_13; } // sqlsrv_conn has no destructor since its allocated using placement new, which requires that the destructor be @@ -1186,14 +1192,13 @@ struct sqlsrv_stream { SQLUSMALLINT field_index; SQLSMALLINT sql_type; sqlsrv_stmt* stmt; - std::size_t stmt_index; sqlsrv_stream( zval* str_z, SQLSRV_ENCODING enc ) : - stream_z( str_z ), encoding( enc ) + stream_z( str_z ), encoding( enc ), field_index( 0 ), sql_type( SQL_UNKNOWN_TYPE ), stmt( NULL ) { } - sqlsrv_stream() : stream_z( NULL ), encoding( SQLSRV_ENCODING_INVALID ), stmt( NULL ) + sqlsrv_stream() : stream_z( NULL ), encoding( SQLSRV_ENCODING_INVALID ), field_index( 0 ), sql_type( SQL_UNKNOWN_TYPE ), stmt( NULL ) { } }; @@ -1226,8 +1231,8 @@ struct sqlsrv_output_param { // every other type output parameter constructor sqlsrv_output_param( zval* p_z, int num, bool is_bool ) : param_z( p_z ), - param_num( num ), encoding( SQLSRV_ENCODING_INVALID ), + param_num( num ), original_buffer_len( -1 ), is_bool( is_bool ) { @@ -1310,7 +1315,11 @@ const int SQLSRV_DEFAULT_SIZE = -1; // size given for an output parameter th const unsigned int QUERY_TIMEOUT_INVALID = 0xffffffff; // special buffered query constant +#ifdef __linux__ +const size_t SQLSRV_CURSOR_BUFFERED = 42; // arbitrary number that doesn't map to any other SQL_CURSOR_* constant +#else const size_t SQLSRV_CURSOR_BUFFERED = 0xfffffffeUL; // arbitrary number that doesn't map to any other SQL_CURSOR_* constant +#endif // factory to create a statement typedef sqlsrv_stmt* (*driver_stmt_factory)( sqlsrv_conn* conn, SQLHANDLE h, error_callback e, void* drv TSRMLS_DC ); @@ -1519,9 +1528,8 @@ struct sqlsrv_buffered_result_set : public sqlsrv_result_set { bool convert_string_from_utf16_inplace( SQLSRV_ENCODING encoding, char** string, SQLLEN& len); bool convert_zval_string_from_utf16(SQLSRV_ENCODING encoding, zval* value_z, SQLLEN& len); bool validate_string(char* string, SQLLEN& len); -bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inString, SQLINTEGER cchInLen, char** outString, SQLLEN& cchOutLen ); -wchar_t* utf16_string_from_mbcs_string( SQLSRV_ENCODING php_encoding, const char* mbcs_string, - unsigned int mbcs_len, _Out_ unsigned int* utf16_len ); +bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const SQLWCHAR* inString, SQLINTEGER cchInLen, char** outString, SQLLEN& cchOutLen ); +SQLWCHAR* utf16_string_from_mbcs_string( SQLSRV_ENCODING php_encoding, const char* mbcs_string, unsigned int mbcs_len, _Out_ unsigned int* utf16_len ); //********************************************************************************************************************************* // Error handling routines and Predefined Errors @@ -1744,13 +1752,13 @@ namespace core { // and return a more helpful message prepended to the ODBC errors if that error occurs if( !SQL_SUCCEEDED( r )) { - SQLCHAR err_msg[ SQL_MAX_MESSAGE_LENGTH + 1 ]; + SQLCHAR err_msg[ SQL_MAX_MESSAGE_LENGTH + 1 ] = { '\0' }; SQLSMALLINT len = 0; - SQLRETURN r = ::SQLGetDiagField( stmt->handle_type(), stmt->handle(), 1, SQL_DIAG_MESSAGE_TEXT, + SQLRETURN rtemp = ::SQLGetDiagField( stmt->handle_type(), stmt->handle(), 1, SQL_DIAG_MESSAGE_TEXT, err_msg, SQL_MAX_MESSAGE_LENGTH, &len ); - CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { + CHECK_SQL_ERROR_OR_WARNING( rtemp, stmt ) { throw CoreException(); } @@ -1889,7 +1897,7 @@ namespace core { return r; } - inline SQLRETURN SQLExecDirectW( sqlsrv_stmt* stmt, wchar_t* wsql TSRMLS_DC ) + inline SQLRETURN SQLExecDirectW( sqlsrv_stmt* stmt, SQLWCHAR* wsql TSRMLS_DC ) { SQLRETURN r; r = ::SQLExecDirectW( stmt->handle(), reinterpret_cast( wsql ), SQL_NTS ); @@ -2263,7 +2271,7 @@ namespace core { inline void sqlsrv_zend_hash_add( sqlsrv_context& ctx, HashTable* ht, zend_string* key, unsigned int key_len, zval* data, unsigned int data_size, zval* pDest TSRMLS_DC ) { - int zr = (pDest = ::zend_hash_add(ht, key, data)) != NULL ? SUCCESS : FAILURE; + int zr = ::zend_hash_add(ht, key, data) != NULL ? SUCCESS : FAILURE; CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { throw CoreException(); } diff --git a/source/shared/core_util.cpp b/source/shared/core_util.cpp index fe3c4d06..5cdea8ae 100644 --- a/source/shared/core_util.cpp +++ b/source/shared/core_util.cpp @@ -35,7 +35,7 @@ char last_err_msg[ 2048 ]; // 2k to hold the error messages // routine used by utf16_string_from_mbcs_string unsigned int convert_string_from_default_encoding( unsigned int php_encoding, _In_reads_bytes_(mbcs_len) char const* mbcs_in_string, unsigned int mbcs_len, - _Out_writes_(utf16_len) __transfer( mbcs_in_string ) wchar_t* utf16_out_string, + _Out_writes_(utf16_len) __transfer( mbcs_in_string ) SQLWCHAR* utf16_out_string, unsigned int utf16_len ); } @@ -81,8 +81,7 @@ bool convert_string_from_utf16_inplace( SQLSRV_ENCODING encoding, char** string, char* outString = NULL; SQLLEN outLen = 0; - bool result = convert_string_from_utf16( encoding, - reinterpret_cast(*string), int(len / sizeof(wchar_t)), &outString, outLen); + bool result = convert_string_from_utf16( encoding, reinterpret_cast(*string), int(len / sizeof(SQLWCHAR)), &outString, outLen ); if (result) { @@ -105,8 +104,7 @@ bool convert_zval_string_from_utf16(SQLSRV_ENCODING encoding, zval* value_z, SQL char* outString = NULL; SQLLEN outLen = 0; - bool result = convert_string_from_utf16(encoding, - reinterpret_cast(string), int(len / sizeof(wchar_t)), &outString, outLen); + bool result = convert_string_from_utf16( encoding, reinterpret_cast(string), int(len / sizeof(SQLWCHAR)), &outString, outLen ); if (result) { @@ -127,16 +125,16 @@ bool validate_string(char* string, SQLLEN& len) return true; } - if ((len / sizeof(wchar_t)) > INT_MAX) - { - LOG(SEV_ERROR, "UTP-16 (wide character) string mapping: buffer length exceeded."); - throw core::CoreException(); - } + if ((len / sizeof(SQLWCHAR)) > INT_MAX) + { + LOG(SEV_ERROR, "UTP-16 (wide character) string mapping: buffer length exceeded."); + throw core::CoreException(); + } return false; } -bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inString, SQLINTEGER cchInLen, char** outString, SQLLEN& cchOutLen ) +bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const SQLWCHAR* inString, SQLINTEGER cchInLen, char** outString, SQLLEN& cchOutLen ) { SQLSRV_ASSERT( inString != NULL, "Input string must be specified" ); SQLSRV_ASSERT( outString != NULL, "Output buffer pointer must be specified" ); @@ -158,18 +156,28 @@ bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inStrin } // calculate the number of characters needed +#ifdef __linux__ + cchOutLen = SystemLocale::FromUtf16Strict( encoding, inString, cchInLen, NULL, 0 ); +#else cchOutLen = WideCharToMultiByte( encoding, flags, inString, cchInLen, NULL, 0, NULL, NULL ); +#endif + if( cchOutLen == 0 ) { return false; } // Create a buffer to fit the encoded string char* newString = reinterpret_cast( sqlsrv_malloc( cchOutLen + 1 /* NULL char*/ )); + +#ifdef __linux__ + int rc = SystemLocale::FromUtf16( encoding, inString, cchInLen, newString, static_cast(cchOutLen)); +#else int rc = WideCharToMultiByte( encoding, flags, inString, cchInLen, newString, static_cast(cchOutLen), NULL, NULL ); +#endif if( rc == 0 ) { cchOutLen = 0; sqlsrv_free( newString ); @@ -185,13 +193,13 @@ bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inStrin // thin wrapper around convert_string_from_default_encoding that handles // allocation of the destination string. An empty string passed in returns // failure since it's a failure case for convert_string_from_default_encoding. -wchar_t* utf16_string_from_mbcs_string( SQLSRV_ENCODING php_encoding, const char* mbcs_string, unsigned int mbcs_len, +SQLWCHAR* utf16_string_from_mbcs_string( SQLSRV_ENCODING php_encoding, const char* mbcs_string, unsigned int mbcs_len, unsigned int* utf16_len ) { *utf16_len = (mbcs_len + 1); - wchar_t* utf16_string = reinterpret_cast( sqlsrv_malloc( *utf16_len * sizeof( wchar_t ))); - *utf16_len = convert_string_from_default_encoding( php_encoding, mbcs_string, mbcs_len, - utf16_string, *utf16_len ); + SQLWCHAR* utf16_string = reinterpret_cast( sqlsrv_malloc( *utf16_len * sizeof( SQLWCHAR ))); + *utf16_len = convert_string_from_default_encoding( php_encoding, mbcs_string, mbcs_len, utf16_string, *utf16_len ); + if( *utf16_len == 0 ) { // we preserve the error and reset it because sqlsrv_free resets the last error DWORD last_error = GetLastError(); @@ -220,13 +228,10 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_ return false; } - zval* ssphp_z = NULL; - int zr = SUCCESS; - zval* temp = NULL; SQLRETURN r = SQL_SUCCESS; SQLSMALLINT wmessage_len = 0; - SQLWCHAR wsqlstate[ SQL_SQLSTATE_BUFSIZE ]; - SQLWCHAR wnative_message[ SQL_MAX_MESSAGE_LENGTH + 1 ]; + SQLWCHAR wsqlstate[ SQL_SQLSTATE_BUFSIZE ] = { L'\0' }; + SQLWCHAR wnative_message[ SQL_MAX_MESSAGE_LENGTH + 1 ] = { L'\0' }; SQLSRV_ENCODING enc = ctx.encoding(); switch( h_type ) { @@ -238,7 +243,7 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_ error = stmt->current_results->get_diag_rec( record_number ); // don't use the CHECK* macros here since it will trigger reentry into the error handling system - if( error == NULL ) { + if( error == 0 ) { return false; } break; @@ -261,8 +266,15 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_ return false; } +#ifdef __linux__ + // In linux we need to calculate number of characters + SQLLEN wsqlstate_len = sizeof( wsqlstate ) / sizeof( SQLWCHAR ); +#else + // In Windows we need the size in bytes + SQLLEN wsqlstate_len = sizeof( wsqlstate ); +#endif SQLLEN sqlstate_len = 0; - convert_string_from_utf16(enc, wsqlstate, sizeof(wsqlstate), (char**)&error->sqlstate, sqlstate_len); + convert_string_from_utf16(enc, wsqlstate, wsqlstate_len, (char**)&error->sqlstate, sqlstate_len); SQLLEN message_len = 0; convert_string_from_utf16(enc, wnative_message, wmessage_len, (char**)&error->native_message, message_len); @@ -350,8 +362,8 @@ void die( const char* msg, ... ) { va_list format_args; va_start( format_args, msg ); - - DWORD rc = FormatMessage( FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, last_err_msg, sizeof( last_err_msg ), &format_args ); + + DWORD rc = FormatMessage( FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, last_err_msg, sizeof( last_err_msg ), &format_args ); va_end( format_args ); @@ -371,7 +383,7 @@ namespace { // a failure since MBTWC returns 0 for both an empty string and failure // to convert. unsigned int convert_string_from_default_encoding( unsigned int php_encoding, _In_reads_bytes_(mbcs_len) char const* mbcs_in_string, - unsigned int mbcs_len, _Out_writes_(utf16_len) __transfer( mbcs_in_string ) wchar_t* utf16_out_string, + unsigned int mbcs_len, _Out_writes_(utf16_len) __transfer( mbcs_in_string ) SQLWCHAR* utf16_out_string, unsigned int utf16_len ) { unsigned int win_encoding = CP_ACP; @@ -387,8 +399,13 @@ unsigned int convert_string_from_default_encoding( unsigned int php_encoding, _I win_encoding = php_encoding; break; } +#ifdef __linux__ + unsigned int 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 + if( required_len == 0 ) { return 0; }