merged conversion functions in core_sqlsrv and core_util

This commit is contained in:
Hadis Kakanejadi Fard 2017-01-20 15:14:46 -08:00
parent cb88f51e16
commit 08c9ca87e1
2 changed files with 73 additions and 48 deletions

View file

@ -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<T,sqlsrv_malloc_auto_ptr<T> >::_ptr )
sqlsrv_free( (void*) sqlsrv_auto_ptr<T,sqlsrv_malloc_auto_ptr<T> >::_ptr );
sqlsrv_auto_ptr<T,sqlsrv_malloc_auto_ptr<T> >::_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<T*>( sqlsrv_realloc( _ptr, new_size ));
{
sqlsrv_auto_ptr<T,sqlsrv_malloc_auto_ptr<T> >::_ptr = reinterpret_cast<T*>( sqlsrv_realloc( sqlsrv_auto_ptr<T,sqlsrv_malloc_auto_ptr<T> >::_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<SQLWCHAR*>( 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();
}

View file

@ -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<const wchar_t*>(*string), int(len / sizeof(wchar_t)), &outString, outLen);
bool result = convert_string_from_utf16( encoding, reinterpret_cast<const SQLWCHAR*>(*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<const wchar_t*>(string), int(len / sizeof(wchar_t)), &outString, outLen);
bool result = convert_string_from_utf16( encoding, reinterpret_cast<const SQLWCHAR*>(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<char*>( sqlsrv_malloc( cchOutLen + 1 /* NULL char*/ ));
#ifdef __linux__
int rc = SystemLocale::FromUtf16( encoding, inString, cchInLen, newString, static_cast<int>(cchOutLen));
#else
int rc = WideCharToMultiByte( encoding, flags,
inString, cchInLen,
newString, static_cast<int>(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<wchar_t*>( 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<SQLWCHAR*>( 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;
}