diff --git a/appveyor.yml b/appveyor.yml index 0b449210..10ce9d8d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -177,6 +177,7 @@ test_script: - copy %APPVEYOR_BUILD_FOLDER%\test\functional\setup\*.dll %APPVEYOR_BUILD_FOLDER%\test\functional\pdo_sqlsrv\ - python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\run_ksp.py -server %TEST_PHP_SQL_SERVER% -dbname %SQLSRV_DBNAME% -uid %TEST_PHP_SQL_UID% -pwd %TEST_PHP_SQL_PWD% - python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\run_ksp.py -server %TEST_PHP_SQL_SERVER% -dbname %PDOSQLSRV_DBNAME% -uid %TEST_PHP_SQL_UID% -pwd %TEST_PHP_SQL_PWD% + - OpenCppCoverage.exe --sources %PHP_SDK_DIR%\php-%PHP_VERSION%-src\ext\pdo_sqlsrv --sources %PHP_SDK_DIR%\php-%PHP_VERSION%-src\ext\sqlsrv --modules *sqlsrv*.dll --export_type=cobertura:.\coverage.xml --cover_children --quiet --continue_after_cpp_exception --optimized_build -- .\php.exe .\run-tests.php -P %APPVEYOR_BUILD_FOLDER%\test\functional\ - php run-tests.php -p php.exe %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv\*.phpt > %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv.log 2>&1 - type %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv.log - php run-tests.php -p php.exe %APPVEYOR_BUILD_FOLDER%\test\functional\pdo_sqlsrv\*.phpt > %APPVEYOR_BUILD_FOLDER%\test\functional\pdo_sqlsrv.log 2>&1 @@ -190,8 +191,7 @@ test_script: - ps: $outfiles = Get-ChildItem pdo_sqlsrv\*.out - ps: foreach($file in $difffiles){ls $file; more $file} - ps: foreach($file in $outfiles){ls $file; more $file} - - cd %PHP_INSTALL_DIR% - - OpenCppCoverage.exe --sources %PHP_SDK_DIR%\php-%PHP_VERSION%-src\ext\pdo_sqlsrv --sources %PHP_SDK_DIR%\php-%PHP_VERSION%-src\ext\sqlsrv --modules *sqlsrv*.dll --export_type=cobertura:.\coverage.xml --cover_children --quiet --continue_after_cpp_exception --optimized_build -- .\php.exe .\run-tests.php -P %APPVEYOR_BUILD_FOLDER%\test\functional\ + - cd %PHP_INSTALL_DIR% - ls - python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\cleanup_dbs.py -dbname %SQLSRV_DBNAME% - python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\cleanup_dbs.py -dbname %PDOSQLSRV_DBNAME% diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index eff54123..3e532456 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -386,6 +386,8 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ } if( zval_was_long ){ convert_to_string( param_z ); + if ( encoding != SQLSRV_ENCODING_SYSTEM && encoding != SQLSRV_ENCODING_UTF8 && encoding != SQLSRV_ENCODING_BINARY ) + encoding = SQLSRV_ENCODING_UTF8; match = Z_TYPE_P( param_z ) == IS_STRING; } else { @@ -424,6 +426,8 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ case SQLSRV_PHPTYPE_INT: if( zval_was_long ){ convert_to_string( param_z ); + if ( encoding != SQLSRV_ENCODING_SYSTEM && encoding != SQLSRV_ENCODING_UTF8 && encoding != SQLSRV_ENCODING_BINARY ) + encoding = SQLSRV_ENCODING_UTF8; } else { convert_to_long( param_z ); @@ -2091,6 +2095,54 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) ZVAL_NULL( value_z ); continue; } + + // if there was more to output than buffer size to hold it, then throw a truncation error + int null_size = 0; + switch( output_param->encoding ) { + case SQLSRV_ENCODING_UTF8: + null_size = sizeof( SQLWCHAR ); // string isn't yet converted to UTF-8, still UTF-16 + break; + case SQLSRV_ENCODING_SYSTEM: + null_size = 1; + break; + case SQLSRV_ENCODING_BINARY: + null_size = 0; + break; + default: + SQLSRV_ASSERT( false, "Invalid encoding in output_param structure." ); + break; + } + CHECK_CUSTOM_ERROR( str_len > ( output_param->original_buffer_len - null_size ), stmt, + SQLSRV_ERROR_OUTPUT_PARAM_TRUNCATED, output_param->param_num + 1 ) { + throw core::CoreException(); + } + + // For ODBC 11+ see https://msdn.microsoft.com/en-us/library/jj219209.aspx + // A length value of SQL_NO_TOTAL for SQLBindParameter indicates that the buffer contains up to + // output_param->original_buffer_len data and is NULL terminated. + // The IF statement can be true when using connection pooling with unixODBC 2.3.4. + if ( str_len == SQL_NO_TOTAL ) + { + str_len = output_param->original_buffer_len - null_size; + } + + // if it's not in the 8 bit encodings, then it's in UTF-16 + if( output_param->encoding != SQLSRV_ENCODING_CHAR && output_param->encoding != SQLSRV_ENCODING_BINARY ) { + bool converted = convert_zval_string_from_utf16(output_param->encoding, value_z, str_len); + CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_OUTPUT_PARAM_ENCODING_TRANSLATE, get_last_error_message()) { + throw core::CoreException(); + } + } + else if( output_param->encoding == SQLSRV_ENCODING_BINARY && str_len < output_param->original_buffer_len ) { + // ODBC doesn't null terminate binary encodings, but PHP complains if a string isn't null terminated + // so we do that here if the length of the returned data is less than the original allocation. The + // original allocation null terminates the buffer already. + str[ str_len ] = '\0'; + core::sqlsrv_zval_stringl(value_z, str, str_len); + } + else { + core::sqlsrv_zval_stringl(value_z, str, str_len); + } if ( output_param->is_long ) { zval* value_z_temp = ( zval * )sqlsrv_malloc( sizeof( zval )); ZVAL_COPY( value_z_temp, value_z ); @@ -2100,55 +2152,6 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) } sqlsrv_free( value_z_temp ); } - else { - // if there was more to output than buffer size to hold it, then throw a truncation error - int null_size = 0; - switch ( output_param->encoding ) { - case SQLSRV_ENCODING_UTF8: - null_size = sizeof( SQLWCHAR ); // string isn't yet converted to UTF-8, still UTF-16 - break; - case SQLSRV_ENCODING_SYSTEM: - null_size = 1; - break; - case SQLSRV_ENCODING_BINARY: - null_size = 0; - break; - default: - SQLSRV_ASSERT( false, "Invalid encoding in output_param structure." ); - break; - } - CHECK_CUSTOM_ERROR( str_len > ( output_param->original_buffer_len - null_size ), stmt, - SQLSRV_ERROR_OUTPUT_PARAM_TRUNCATED, output_param->param_num + 1 ) { - throw core::CoreException(); - } - - // For ODBC 11+ see https://msdn.microsoft.com/en-us/library/jj219209.aspx - // A length value of SQL_NO_TOTAL for SQLBindParameter indicates that the buffer contains up to - // output_param->original_buffer_len data and is NULL terminated. - // The IF statement can be true when using connection pooling with unixODBC 2.3.4. - if ( str_len == SQL_NO_TOTAL ) - { - str_len = output_param->original_buffer_len - null_size; - } - - // if it's not in the 8 bit encodings, then it's in UTF-16 - if ( output_param->encoding != SQLSRV_ENCODING_CHAR && output_param->encoding != SQLSRV_ENCODING_BINARY ) { - bool converted = convert_zval_string_from_utf16( output_param->encoding, value_z, str_len ); - CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_OUTPUT_PARAM_ENCODING_TRANSLATE, get_last_error_message() ) { - throw core::CoreException(); - } - } - else if ( output_param->encoding == SQLSRV_ENCODING_BINARY && str_len < output_param->original_buffer_len ) { - // ODBC doesn't null terminate binary encodings, but PHP complains if a string isn't null terminated - // so we do that here if the length of the returned data is less than the original allocation. The - // original allocation null terminates the buffer already. - str[str_len] = '\0'; - core::sqlsrv_zval_stringl( value_z, str, str_len ); - } - else { - core::sqlsrv_zval_stringl( value_z, str, str_len ); - } - } } break; case IS_LONG: