PDO errorinfo includes additional odbc messages if available (#1133)
This commit is contained in:
parent
d308aa4d0f
commit
06d7a496ae
|
@ -99,6 +99,7 @@ install:
|
|||
- echo install opencppcoverage
|
||||
- choco install opencppcoverage
|
||||
- set path=C:\Program Files\OpenCppCoverage;%PYTHON%;%PYTHON%\Scripts;%path%
|
||||
- copy %APPVEYOR_BUILD_FOLDER%\codecov.yml c:\projects
|
||||
|
||||
build_script:
|
||||
- copy %APPVEYOR_BUILD_FOLDER%\buildscripts\*.py c:\projects
|
||||
|
@ -122,7 +123,7 @@ test_script:
|
|||
- ps: >-
|
||||
If ($env:BUILD_PLATFORM -Match "x86") {
|
||||
Write-Host "Running phpt tests via OpenCppCoverage..."
|
||||
OpenCppCoverage.exe --sources ${env:PHP_SRC_DIR}\*sqlsrv --modules ${env:PHP_EXE_PATH}\php*sqlsrv.dll --export_type=cobertura:c:\projects\coverage.xml --quiet --cover_children --continue_after_cpp_exception --optimized_build -- .\php.exe run-tests.php -P ${env:APPVEYOR_BUILD_FOLDER}\test\functional\ | out-file -filePath ${env:APPVEYOR_BUILD_FOLDER}\test\functional\tests.log -encoding UTF8;
|
||||
OpenCppCoverage.exe --sources ${env:PHP_SRC_DIR}\*sqlsrv --modules ${env:PHP_EXE_PATH}\php*sqlsrv.dll --excluded_sources ${env:PHP_SRC_DIR}\pdo_sqlsrv\shared\core_stream.cpp --export_type=cobertura:c:\projects\coverage.xml --quiet --cover_children --continue_after_cpp_exception --optimized_build -- .\php.exe run-tests.php -P ${env:APPVEYOR_BUILD_FOLDER}\test\functional\ | out-file -filePath ${env:APPVEYOR_BUILD_FOLDER}\test\functional\tests.log -encoding UTF8;
|
||||
Write-Host "Showing the last 25 lines of the log file..."
|
||||
Get-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\tests.log -Tail 25;
|
||||
ls *.xml
|
||||
|
|
|
@ -43,8 +43,11 @@ const int WARNING_MIN_LENGTH = static_cast<const int>( strlen( WARNING_TEMPLATE
|
|||
sqlsrv_error_const* get_error_message( _In_opt_ unsigned int sqlsrv_error_code);
|
||||
|
||||
// build the object and throw the PDO exception
|
||||
void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error );
|
||||
void pdo_sqlsrv_throw_exception(_In_ sqlsrv_error const* error);
|
||||
|
||||
void format_or_get_all_errors(_Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _Inout_ sqlsrv_error_auto_ptr& error, _Inout_ char* error_code, _In_opt_ va_list* print_args);
|
||||
|
||||
void add_remaining_errors_to_array (_In_ sqlsrv_error const* error, _Inout_ zval* array_z);
|
||||
}
|
||||
|
||||
// pdo driver error messages
|
||||
|
@ -462,47 +465,26 @@ pdo_error PDO_ERRORS[] = {
|
|||
{ UINT_MAX, {} }
|
||||
};
|
||||
|
||||
// PDO error handler for the environment context.
|
||||
bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
_In_opt_ va_list* print_args )
|
||||
{
|
||||
SQLSRV_ASSERT(( ctx != NULL ), "pdo_sqlsrv_handle_env_error: sqlsrv_context was null" );
|
||||
pdo_dbh_t* dbh = reinterpret_cast<pdo_dbh_t*>( ctx.driver());
|
||||
SQLSRV_ASSERT(( dbh != NULL ), "pdo_sqlsrv_handle_env_error: pdo_dbh_t was null" );
|
||||
|
||||
SQLSRV_ASSERT((ctx != NULL), "pdo_sqlsrv_handle_env_error: sqlsrv_context was null");
|
||||
pdo_dbh_t* dbh = reinterpret_cast<pdo_dbh_t*>(ctx.driver());
|
||||
SQLSRV_ASSERT((dbh != NULL), "pdo_sqlsrv_handle_env_error: pdo_dbh_t was null");
|
||||
|
||||
sqlsrv_error_auto_ptr error;
|
||||
format_or_get_all_errors(ctx, sqlsrv_error_code, error, dbh->error_code, print_args);
|
||||
|
||||
if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) {
|
||||
|
||||
core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR, print_args );
|
||||
}
|
||||
else {
|
||||
|
||||
bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR );
|
||||
SQLSRV_ASSERT( err == true, "No ODBC error was found" );
|
||||
// error_mode is valid because PDO API has already taken care of invalid ones
|
||||
if (!warning && dbh->error_mode == PDO_ERRMODE_EXCEPTION) {
|
||||
pdo_sqlsrv_throw_exception(error);
|
||||
}
|
||||
|
||||
strcpy_s( dbh->error_code, sizeof( pdo_error_type ), reinterpret_cast<const char*>( error->sqlstate ));
|
||||
ctx.set_last_error(error);
|
||||
|
||||
switch( dbh->error_mode ) {
|
||||
|
||||
case PDO_ERRMODE_EXCEPTION:
|
||||
if( !warning ) {
|
||||
|
||||
pdo_sqlsrv_throw_exception( error );
|
||||
}
|
||||
ctx.set_last_error( error );
|
||||
break;
|
||||
|
||||
default:
|
||||
DIE( "pdo_sqlsrv_handle_env_error: Unexpected error mode. %1!d!", dbh->error_mode );
|
||||
break;
|
||||
}
|
||||
|
||||
// we don't transfer the zval_auto_ptr since set_last_error increments the zval ref count
|
||||
// return error ignored = true for warnings.
|
||||
return ( warning ? true : false );
|
||||
|
||||
return (warning ? true : false);
|
||||
}
|
||||
|
||||
// pdo error handler for the dbh context.
|
||||
|
@ -513,95 +495,50 @@ bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned
|
|||
SQLSRV_ASSERT( dbh != NULL, "pdo_sqlsrv_handle_dbh_error: Null dbh passed" );
|
||||
|
||||
sqlsrv_error_auto_ptr error;
|
||||
format_or_get_all_errors(ctx, sqlsrv_error_code, error, dbh->error_code, print_args);
|
||||
|
||||
if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) {
|
||||
|
||||
core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR, print_args );
|
||||
}
|
||||
else {
|
||||
bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR );
|
||||
SQLSRV_ASSERT( err == true, "No ODBC error was found" );
|
||||
// error_mode is valid because PDO API has already taken care of invalid ones
|
||||
if (!warning) {
|
||||
if (dbh->error_mode == PDO_ERRMODE_EXCEPTION) {
|
||||
pdo_sqlsrv_throw_exception(error);
|
||||
}
|
||||
else if (dbh->error_mode == PDO_ERRMODE_WARNING) {
|
||||
size_t msg_len = strnlen_s(reinterpret_cast<const char*>(error->native_message)) + SQL_SQLSTATE_BUFSIZE
|
||||
+ MAX_DIGITS + WARNING_MIN_LENGTH + 1;
|
||||
sqlsrv_malloc_auto_ptr<char> msg;
|
||||
msg = static_cast<char*>(sqlsrv_malloc(msg_len));
|
||||
core_sqlsrv_format_message(msg, static_cast<unsigned int>(msg_len), WARNING_TEMPLATE, error->sqlstate, error->native_code,
|
||||
error->native_message);
|
||||
php_error(E_WARNING, "%s", msg.get());
|
||||
}
|
||||
}
|
||||
|
||||
SQLSRV_ASSERT(strnlen_s(reinterpret_cast<const char*>(error->sqlstate)) <= sizeof(dbh->error_code), "Error code overflow");
|
||||
strcpy_s(dbh->error_code, sizeof(dbh->error_code), reinterpret_cast<const char*>(error->sqlstate));
|
||||
|
||||
switch( dbh->error_mode ) {
|
||||
case PDO_ERRMODE_EXCEPTION:
|
||||
if( !warning ) {
|
||||
|
||||
pdo_sqlsrv_throw_exception( error );
|
||||
}
|
||||
ctx.set_last_error( error );
|
||||
break;
|
||||
case PDO_ERRMODE_WARNING:
|
||||
if( !warning ) {
|
||||
size_t msg_len = strnlen_s( reinterpret_cast<const char*>( error->native_message )) + SQL_SQLSTATE_BUFSIZE
|
||||
+ MAX_DIGITS + WARNING_MIN_LENGTH + 1;
|
||||
sqlsrv_malloc_auto_ptr<char> msg;
|
||||
msg = static_cast<char*>( sqlsrv_malloc( msg_len ) );
|
||||
core_sqlsrv_format_message( msg, static_cast<unsigned int>( msg_len ), WARNING_TEMPLATE, error->sqlstate, error->native_code,
|
||||
error->native_message );
|
||||
php_error(E_WARNING, "%s", msg.get());
|
||||
}
|
||||
ctx.set_last_error( error );
|
||||
break;
|
||||
case PDO_ERRMODE_SILENT:
|
||||
ctx.set_last_error( error );
|
||||
break;
|
||||
default:
|
||||
DIE( "Unknown error mode. %1!d!", dbh->error_mode );
|
||||
break;
|
||||
}
|
||||
ctx.set_last_error(error);
|
||||
|
||||
// return error ignored = true for warnings.
|
||||
return ( warning ? true : false );
|
||||
return (warning ? true : false);
|
||||
}
|
||||
|
||||
// PDO error handler for the statement context.
|
||||
bool pdo_sqlsrv_handle_stmt_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
_In_opt_ va_list* print_args )
|
||||
bool pdo_sqlsrv_handle_stmt_error(_Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
_In_opt_ va_list* print_args)
|
||||
{
|
||||
pdo_stmt_t* pdo_stmt = reinterpret_cast<pdo_stmt_t*>( ctx.driver());
|
||||
SQLSRV_ASSERT( pdo_stmt != NULL && pdo_stmt->dbh != NULL, "pdo_sqlsrv_handle_stmt_error: Null statement or dbh passed" );
|
||||
pdo_stmt_t* pdo_stmt = reinterpret_cast<pdo_stmt_t*>(ctx.driver());
|
||||
SQLSRV_ASSERT(pdo_stmt != NULL && pdo_stmt->dbh != NULL, "pdo_sqlsrv_handle_stmt_error: Null statement or dbh passed");
|
||||
|
||||
sqlsrv_error_auto_ptr error;
|
||||
format_or_get_all_errors(ctx, sqlsrv_error_code, error, pdo_stmt->error_code, print_args);
|
||||
|
||||
if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) {
|
||||
core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR, print_args );
|
||||
}
|
||||
else {
|
||||
bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR );
|
||||
SQLSRV_ASSERT( err == true, "No ODBC error was found" );
|
||||
}
|
||||
|
||||
SQLSRV_ASSERT( strnlen_s( reinterpret_cast<const char*>( error->sqlstate ) ) <= sizeof( pdo_stmt->error_code ), "Error code overflow");
|
||||
strcpy_s( pdo_stmt->error_code, sizeof( pdo_stmt->error_code ), reinterpret_cast<const char*>( error->sqlstate ));
|
||||
|
||||
switch( pdo_stmt->dbh->error_mode ) {
|
||||
case PDO_ERRMODE_EXCEPTION:
|
||||
if( !warning ) {
|
||||
|
||||
pdo_sqlsrv_throw_exception( error );
|
||||
}
|
||||
ctx.set_last_error( error );
|
||||
break;
|
||||
case PDO_ERRMODE_WARNING:
|
||||
ctx.set_last_error( error );
|
||||
break;
|
||||
case PDO_ERRMODE_SILENT:
|
||||
ctx.set_last_error( error );
|
||||
break;
|
||||
default:
|
||||
DIE( "Unknown error mode. %1!d!", pdo_stmt->dbh->error_mode );
|
||||
break;
|
||||
// error_mode is valid because PDO API has already taken care of invalid ones
|
||||
if (!warning && pdo_stmt->dbh->error_mode == PDO_ERRMODE_EXCEPTION) {
|
||||
pdo_sqlsrv_throw_exception(error);
|
||||
}
|
||||
ctx.set_last_error(error);
|
||||
|
||||
// return error ignored = true for warnings.
|
||||
return ( warning ? true : false );
|
||||
return (warning ? true : false);
|
||||
}
|
||||
|
||||
|
||||
// Transfer a sqlsrv_context's error to a PDO zval. The standard format for a zval error is 3 elements:
|
||||
// 0, native code
|
||||
// 1, native message
|
||||
|
@ -613,6 +550,8 @@ void pdo_sqlsrv_retrieve_context_error( _In_ sqlsrv_error const* last_error, _Ou
|
|||
// SQLSTATE is already present in the zval.
|
||||
add_next_index_long( pdo_zval, last_error->native_code );
|
||||
add_next_index_string( pdo_zval, reinterpret_cast<char*>( last_error->native_message ));
|
||||
|
||||
add_remaining_errors_to_array (last_error, pdo_zval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,7 +578,7 @@ sqlsrv_error_const* get_error_message( _In_opt_ unsigned int sqlsrv_error_code)
|
|||
return error_message;
|
||||
}
|
||||
|
||||
void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error )
|
||||
void pdo_sqlsrv_throw_exception(_In_ sqlsrv_error const* error)
|
||||
{
|
||||
zval ex_obj;
|
||||
ZVAL_UNDEF( &ex_obj );
|
||||
|
@ -650,10 +589,10 @@ void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error )
|
|||
SQLSRV_ASSERT( zr != FAILURE, "Failed to initialize exception object" );
|
||||
|
||||
sqlsrv_malloc_auto_ptr<char> ex_msg;
|
||||
size_t ex_msg_len = strnlen_s( reinterpret_cast<const char*>( error->native_message )) + SQL_SQLSTATE_BUFSIZE +
|
||||
size_t ex_msg_len = strnlen_s(reinterpret_cast<const char*>(error->native_message)) + SQL_SQLSTATE_BUFSIZE +
|
||||
12 + 1; // 12 = "SQLSTATE[]: "
|
||||
ex_msg = reinterpret_cast<char*>( sqlsrv_malloc( ex_msg_len ));
|
||||
snprintf( ex_msg, ex_msg_len, EXCEPTION_MSG_TEMPLATE, error->sqlstate, error->native_message );
|
||||
ex_msg = reinterpret_cast<char*>(sqlsrv_malloc(ex_msg_len));
|
||||
snprintf(ex_msg, ex_msg_len, EXCEPTION_MSG_TEMPLATE, error->sqlstate, error->native_message);
|
||||
zend_update_property_string( ex_class, &ex_obj, EXCEPTION_PROPERTY_MSG, sizeof( EXCEPTION_PROPERTY_MSG ) - 1,
|
||||
ex_msg );
|
||||
zend_update_property_string( ex_class, &ex_obj, EXCEPTION_PROPERTY_CODE, sizeof( EXCEPTION_PROPERTY_CODE ) - 1,
|
||||
|
@ -665,6 +604,9 @@ void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error )
|
|||
add_next_index_string( &ex_error_info, reinterpret_cast<char*>( error->sqlstate ));
|
||||
add_next_index_long( &ex_error_info, error->native_code );
|
||||
add_next_index_string( &ex_error_info, reinterpret_cast<char*>( error->native_message ));
|
||||
|
||||
add_remaining_errors_to_array (error, &ex_error_info);
|
||||
|
||||
//zend_update_property makes an entry in the properties_table in ex_obj point to the Z_ARRVAL( ex_error_info )
|
||||
//and the refcount of the zend_array is incremented by 1
|
||||
zend_update_property( ex_class, &ex_obj, EXCEPTION_PROPERTY_ERRORINFO, sizeof( EXCEPTION_PROPERTY_ERRORINFO ) - 1,
|
||||
|
@ -677,4 +619,59 @@ void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error )
|
|||
zend_throw_exception_object( &ex_obj );
|
||||
}
|
||||
|
||||
void add_remaining_errors_to_array (_In_ sqlsrv_error const* error, _Inout_ zval* array_z)
|
||||
{
|
||||
if (error->next != NULL && PDO_SQLSRV_G(report_additional_errors)) {
|
||||
sqlsrv_error *p = error->next;
|
||||
while (p != NULL) {
|
||||
// check if sql state or native message is NULL and handle them accordingly
|
||||
char *state = "";
|
||||
char *msg = "";
|
||||
|
||||
if (p->sqlstate != NULL) {
|
||||
state = reinterpret_cast<char*>(p->sqlstate);
|
||||
}
|
||||
if (p->native_message != NULL) {
|
||||
msg = reinterpret_cast<char*>(p->native_message);
|
||||
}
|
||||
|
||||
add_next_index_string(array_z, state);
|
||||
add_next_index_long(array_z, p->native_code);
|
||||
add_next_index_string(array_z, msg);
|
||||
|
||||
p = p-> next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void format_or_get_all_errors(_Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _Inout_ sqlsrv_error_auto_ptr& error, _Inout_ char* error_code, _In_opt_ va_list* print_args)
|
||||
{
|
||||
if (sqlsrv_error_code != SQLSRV_ERROR_ODBC) {
|
||||
core_sqlsrv_format_driver_error(ctx, get_error_message(sqlsrv_error_code), error, SEV_ERROR, print_args);
|
||||
strcpy_s(error_code, sizeof(pdo_error_type), reinterpret_cast<const char*>(error->sqlstate));
|
||||
}
|
||||
else {
|
||||
bool result = core_sqlsrv_get_odbc_error(ctx, 1, error, SEV_ERROR, true);
|
||||
if (result) {
|
||||
// Check if there exist more errors
|
||||
int rec_number = 2;
|
||||
sqlsrv_error_auto_ptr err;
|
||||
sqlsrv_error *p = error;
|
||||
|
||||
do {
|
||||
result = core_sqlsrv_get_odbc_error(ctx, rec_number++, err, SEV_ERROR, true);
|
||||
if (result) {
|
||||
p->next = err.get();
|
||||
err.transferred();
|
||||
p = p->next;
|
||||
}
|
||||
} while (result);
|
||||
}
|
||||
|
||||
// core_sqlsrv_get_odbc_error() returns the error_code of size SQL_SQLSTATE_BUFSIZE,
|
||||
// which is the same size as pdo_error_type
|
||||
strcpy_s(error_code, sizeof(pdo_error_type), reinterpret_cast<const char*>(error->sqlstate));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlsrv)
|
|||
|
||||
unsigned int pdo_log_severity;
|
||||
zend_long client_buffer_max_size;
|
||||
short report_additional_errors;
|
||||
|
||||
#ifndef _WIN32
|
||||
zend_long set_locale_info;
|
||||
|
|
|
@ -53,6 +53,7 @@ extern HMODULE g_sqlsrv_hmodule;
|
|||
// (these are defined as macros to allow concatenation as we do below)
|
||||
#define INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE "client_buffer_max_kb_size"
|
||||
#define INI_PDO_SQLSRV_LOG "log_severity"
|
||||
#define INI_PDO_SQLSRV_MORE_ERRORS "report_additional_errors"
|
||||
#define INI_PREFIX "pdo_sqlsrv."
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -64,6 +65,7 @@ PHP_INI_BEGIN()
|
|||
zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals )
|
||||
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE , INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong,
|
||||
client_buffer_max_size, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals )
|
||||
STD_PHP_INI_ENTRY(INI_PREFIX INI_PDO_SQLSRV_MORE_ERRORS, "1", PHP_INI_ALL, OnUpdateLong, report_additional_errors, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals)
|
||||
#ifndef _WIN32
|
||||
STD_PHP_INI_ENTRY(INI_PREFIX INI_PDO_SET_LOCALE_INFO, "2", PHP_INI_ALL, OnUpdateLong, set_locale_info,
|
||||
zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals)
|
||||
|
|
|
@ -776,6 +776,7 @@ struct sqlsrv_error_const {
|
|||
|
||||
// subclass which is used by the core layer to instantiate ODBC errors
|
||||
struct sqlsrv_error : public sqlsrv_error_const {
|
||||
struct sqlsrv_error *next; // Only used in pdo_sqlsrv for additional errors (as a linked list)
|
||||
|
||||
sqlsrv_error( void )
|
||||
{
|
||||
|
@ -783,16 +784,18 @@ struct sqlsrv_error : public sqlsrv_error_const {
|
|||
native_message = NULL;
|
||||
native_code = -1;
|
||||
format = false;
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
sqlsrv_error( _In_ SQLCHAR* sql_state, _In_ SQLCHAR* message, _In_ SQLINTEGER code, _In_ bool printf_format = false )
|
||||
sqlsrv_error( _In_ SQLCHAR* sql_state, _In_ SQLCHAR* message, _In_ SQLINTEGER code, _In_ bool printf_format = false)
|
||||
{
|
||||
sqlstate = reinterpret_cast<SQLCHAR*>( sqlsrv_malloc( SQL_SQLSTATE_BUFSIZE ));
|
||||
native_message = reinterpret_cast<SQLCHAR*>( sqlsrv_malloc( SQL_MAX_ERROR_MESSAGE_LENGTH + 1 ));
|
||||
strcpy_s( reinterpret_cast<char*>( sqlstate ), SQL_SQLSTATE_BUFSIZE, reinterpret_cast<const char*>( sql_state ));
|
||||
strcpy_s( reinterpret_cast<char*>( native_message ), SQL_MAX_ERROR_MESSAGE_LENGTH + 1, reinterpret_cast<const char*>( message ));
|
||||
sqlstate = reinterpret_cast<SQLCHAR*>(sqlsrv_malloc(SQL_SQLSTATE_BUFSIZE));
|
||||
native_message = reinterpret_cast<SQLCHAR*>(sqlsrv_malloc(SQL_MAX_ERROR_MESSAGE_LENGTH + 1));
|
||||
strcpy_s(reinterpret_cast<char*>(sqlstate), SQL_SQLSTATE_BUFSIZE, reinterpret_cast<const char*>(sql_state));
|
||||
strcpy_s(reinterpret_cast<char*>(native_message), SQL_MAX_ERROR_MESSAGE_LENGTH + 1, reinterpret_cast<const char*>(message));
|
||||
native_code = code;
|
||||
format = printf_format;
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
sqlsrv_error( _In_ sqlsrv_error_const const& prototype )
|
||||
|
@ -802,16 +805,26 @@ struct sqlsrv_error : public sqlsrv_error_const {
|
|||
|
||||
~sqlsrv_error( void )
|
||||
{
|
||||
if( sqlstate != NULL ) {
|
||||
sqlsrv_free( sqlstate );
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (sqlstate != NULL) {
|
||||
sqlsrv_free(sqlstate);
|
||||
sqlstate = NULL;
|
||||
}
|
||||
if( native_message != NULL ) {
|
||||
sqlsrv_free( native_message );
|
||||
if (native_message != NULL) {
|
||||
sqlsrv_free(native_message);
|
||||
native_message = NULL;
|
||||
}
|
||||
if (next != NULL) {
|
||||
next->reset(); // free the next sqlsrv_error, and so on
|
||||
sqlsrv_free(next);
|
||||
next = NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// an auto_ptr for sqlsrv_errors. These call the destructor explicitly rather than call delete
|
||||
class sqlsrv_error_auto_ptr : public sqlsrv_auto_ptr<sqlsrv_error, sqlsrv_error_auto_ptr > {
|
||||
|
||||
|
@ -852,7 +865,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Context
|
||||
//*********************************************************************************************************************************
|
||||
|
@ -1901,7 +1913,7 @@ enum error_handling_flags {
|
|||
// 3/message) driver specific error message
|
||||
// The fetch type determines if the indices are numeric, associative, or both.
|
||||
bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_number, _Inout_ sqlsrv_error_auto_ptr& error,
|
||||
_In_ logging_severity severity );
|
||||
_In_ logging_severity severity, _In_ bool check_warning = false );
|
||||
|
||||
// format and return a driver specfic error
|
||||
void core_sqlsrv_format_driver_error( _In_ sqlsrv_context& ctx, _In_ sqlsrv_error_const const* custom_error,
|
||||
|
|
|
@ -257,8 +257,7 @@ void convert_datetime_string_to_zval(_Inout_ sqlsrv_stmt* stmt, _In_opt_ char* i
|
|||
// 3/message) driver specific error message
|
||||
// The fetch type determines if the indices are numeric, associative, or both.
|
||||
|
||||
bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_number, _Inout_ sqlsrv_error_auto_ptr& error, _In_ logging_severity severity
|
||||
)
|
||||
bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_number, _Inout_ sqlsrv_error_auto_ptr& error, _In_ logging_severity severity, _In_ bool check_warning /* = false */)
|
||||
{
|
||||
SQLHANDLE h = ctx.handle();
|
||||
SQLSMALLINT h_type = ctx.handle_type();
|
||||
|
@ -297,17 +296,9 @@ bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_nu
|
|||
r = SQLGetDiagRecW( h_type, h, record_number, wsqlstate, &error->native_code, wnative_message,
|
||||
SQL_MAX_ERROR_MESSAGE_LENGTH + 1, &wmessage_len );
|
||||
// don't use the CHECK* macros here since it will trigger reentry into the error handling system
|
||||
// Workaround for a bug in unixODBC 2.3.4 when connection pooling is enabled (PDO SQLSRV).
|
||||
// Instead of returning false, we return an empty error message to prevent the driver from throwing an exception.
|
||||
// To reproduce:
|
||||
// Create a connection and close it (return it to the pool)
|
||||
// Create a new connection from the pool.
|
||||
// Prepare and execute a statement that generates an info message (such as 'USE tempdb;')
|
||||
#ifdef __APPLE__
|
||||
if( r == SQL_NO_DATA && ctx.driver() != NULL /*PDO SQLSRV*/ ) {
|
||||
r = SQL_SUCCESS;
|
||||
}
|
||||
#endif // __APPLE__
|
||||
// removed the workaround for Mac users with unixODBC 2.3.4 when connection pooling is enabled (PDO SQLSRV), for two reasons:
|
||||
// (1) not recommended to use connection pooling with unixODBC < 2.3.7
|
||||
// (2) the problem was not reproducible with unixODBC 2.3.7
|
||||
if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) {
|
||||
return false;
|
||||
}
|
||||
|
@ -348,6 +339,15 @@ bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_nu
|
|||
break;
|
||||
}
|
||||
|
||||
// Only overrides 'severity' if 'check_warning' is true (false by default)
|
||||
if (check_warning) {
|
||||
// The character string value returned for an SQLSTATE consists of a two-character class value
|
||||
// followed by a three-character subclass value. A class value of "01" indicates a warning.
|
||||
// https://docs.microsoft.com/sql/odbc/reference/appendixes/appendix-a-odbc-error-codes?view=sql-server-ver15
|
||||
if (error->sqlstate[0] == '0' && error->sqlstate[1] == '1') {
|
||||
severity = SEV_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
// log the error first
|
||||
LOG( severity, "%1!s!: SQLSTATE = %2!s!", ctx.func(), error->sqlstate );
|
||||
|
|
|
@ -20,5 +20,8 @@ Array
|
|||
\(
|
||||
\[0\] => 42S02
|
||||
\[1\] => 208
|
||||
\[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Invalid object name 'Person.Addressx'.
|
||||
\[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Invalid object name 'Person.Addressx'\.
|
||||
\[3\] => 42000
|
||||
\[4\] => 8180
|
||||
\[5\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Statement\(s\) could not be prepared\.
|
||||
\)
|
|
@ -23,4 +23,7 @@ Array
|
|||
\[0\] => 42S22
|
||||
\[1\] => 207
|
||||
\[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Invalid column name 'Cityx'.
|
||||
\[3\] => 42000
|
||||
\[4\] => 8180
|
||||
\[5\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Statement\(s\) could not be prepared\.
|
||||
\)
|
|
@ -3,7 +3,11 @@ PDO_SQLSRV Connection Pooling Test on Unix
|
|||
--DESCRIPTION--
|
||||
This test assumes the default odbcinst.ini has not been modified.
|
||||
--SKIPIF--
|
||||
<?php if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') die("Skipped: Test for Linux and Mac"); ?>
|
||||
<?php
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
die("Skip test for Linux and Mac only.");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
function findODBCDriver($content, $lines_to_add)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
include 'MsSetup.inc';
|
||||
|
||||
$conn1 = new PDO("sqlsrv:Server=$server; database=$databaseName; driver=$driver", $uid, $pwd);
|
||||
$connId1 = ConnectionID($conn1);
|
||||
$conn1 = null;
|
||||
$connId1 = connectionID($conn1);
|
||||
unset($conn1);
|
||||
|
||||
$conn2 = new PDO("sqlsrv:Server=$server; database=$databaseName; driver=$driver", $uid, $pwd);
|
||||
$connId2 = ConnectionID($conn2);
|
||||
$conn2 = null;
|
||||
$connId2 = connectionID($conn2);
|
||||
|
||||
if ($connId1 === $connId2){
|
||||
echo "Pooled\n";
|
||||
|
@ -14,7 +14,21 @@ if ($connId1 === $connId2){
|
|||
echo "Not Pooled\n";
|
||||
}
|
||||
|
||||
function ConnectionID($conn)
|
||||
// The following is not applicable in Azure
|
||||
$azure = isAzure($conn2);
|
||||
if (!$azure) {
|
||||
try {
|
||||
$conn2->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$stmt = $conn2->prepare("SET NOCOUNT ON; USE tempdb; SELECT 1/0 AS col1");
|
||||
$stmt->execute();
|
||||
} catch (PDOException $e) {
|
||||
checkErrorInfo($stmt, $e);
|
||||
}
|
||||
}
|
||||
|
||||
unset($conn2);
|
||||
|
||||
function connectionID($conn)
|
||||
{
|
||||
$tsql = "SELECT [connection_id] FROM [sys].[dm_exec_connections] where session_id = @@SPID";
|
||||
$stmt = $conn->query($tsql);
|
||||
|
@ -23,4 +37,42 @@ function ConnectionID($conn)
|
|||
$stmt = null;
|
||||
return ($connID);
|
||||
}
|
||||
|
||||
function isAzure($conn)
|
||||
{
|
||||
try {
|
||||
$tsql = "SELECT SERVERPROPERTY ('edition')";
|
||||
$stmt = $conn->query($tsql);
|
||||
|
||||
$result = $stmt->fetch(PDO::FETCH_NUM);
|
||||
$edition = $result[0];
|
||||
|
||||
if ($edition === "SQL Azure") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
die("Could not fetch server property.");
|
||||
}
|
||||
}
|
||||
|
||||
function checkErrorInfo($stmt, $err)
|
||||
{
|
||||
$expected = "*Divide by zero error encountered*";
|
||||
$idx = count($err->errorInfo) - 1;
|
||||
$failed = false;
|
||||
if ($idx != 5 || !fnmatch($expected, $err->errorInfo[$idx])) {
|
||||
echo "Error message unexpected!\n";
|
||||
$failed = true;
|
||||
}
|
||||
if ($err->errorInfo !== $stmt->errorInfo()) {
|
||||
echo "Error info arrays should match!\n";
|
||||
$failed = true;
|
||||
}
|
||||
if ($failed) {
|
||||
var_dump($err);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
156
test/functional/pdo_sqlsrv/pdo_924_display_more_errors.phpt
Normal file
156
test/functional/pdo_sqlsrv/pdo_924_display_more_errors.phpt
Normal file
|
@ -0,0 +1,156 @@
|
|||
--TEST--
|
||||
GitHub issue 924 - Wrong error message after switching database context
|
||||
--DESCRIPTION--
|
||||
Verifies that the user has the option to see the following error message after the first one.
|
||||
--SKIPIF--
|
||||
<?php require('skipif_azure.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsSetup.inc");
|
||||
|
||||
$tsql = "SET NOCOUNT ON; USE $databaseName; SELECT 1/0 AS col1";
|
||||
|
||||
$errorInfo = array("01000", 5701, "*Changed database context to '$databaseName'.");
|
||||
$errorInfo2 = array("22012", 8134, "*Divide by zero error encountered*");
|
||||
|
||||
function compareErrorInfo($actualErrorInfo, $errorInfo, $index = 0)
|
||||
{
|
||||
if (($actualErrorInfo[$index] != $errorInfo[0]) ||
|
||||
($actualErrorInfo[$index + 1] != $errorInfo[1]) ||
|
||||
!fnmatch($errorInfo[2], $actualErrorInfo[$index + 2])) {
|
||||
|
||||
echo "Expected this: \n";
|
||||
var_dump($errorInfo);
|
||||
echo "Actual error info is: \n";
|
||||
var_dump($actualErrorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
function compare2ErrorInfo($actualErrorInfo)
|
||||
{
|
||||
global $errorInfo, $errorInfo2;
|
||||
|
||||
if (count($actualErrorInfo) != 6) {
|
||||
echo "Expect 6 elements in the error info!\n";
|
||||
var_dump($actualErrorInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
// Compare the first three elements
|
||||
compareErrorInfo($actualErrorInfo, $errorInfo);
|
||||
compareErrorInfo($actualErrorInfo, $errorInfo2, 3);
|
||||
}
|
||||
|
||||
function checkException($conn, $on)
|
||||
{
|
||||
global $tsql, $errorInfo, $errorInfo2;
|
||||
|
||||
ini_set('pdo_sqlsrv.report_additional_errors', $on);
|
||||
|
||||
try {
|
||||
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$stmt = $conn->prepare($tsql);
|
||||
$stmt->execute();
|
||||
|
||||
var_dump($stmt->fetchColumn());
|
||||
|
||||
echo "Exception should have been thrown!\n";
|
||||
} catch (PDOException $e) {
|
||||
// compare errorInfo arrays from both the exception object and the stmt object
|
||||
if ($on) {
|
||||
compare2ErrorInfo($e->errorInfo);
|
||||
compare2ErrorInfo($stmt->errorInfo());
|
||||
}
|
||||
else {
|
||||
compareErrorInfo($e->errorInfo, $errorInfo);
|
||||
compareErrorInfo($stmt->errorInfo(), $errorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
}
|
||||
|
||||
function checkWarning($conn, $on)
|
||||
{
|
||||
global $tsql, $errorInfo, $errorInfo2;
|
||||
|
||||
ini_set('pdo_sqlsrv.report_additional_errors', $on);
|
||||
|
||||
try {
|
||||
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
|
||||
$stmt = $conn->prepare($tsql);
|
||||
$stmt->execute();
|
||||
|
||||
compareErrorInfo($stmt->errorInfo(), $errorInfo);
|
||||
if ($on) {
|
||||
compareErrorInfo($stmt->errorInfo(), $errorInfo2, 3);
|
||||
} else {
|
||||
echo count($stmt->errorInfo()) . PHP_EOL;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo " Warnings are logged but do not expect exceptions.\n";
|
||||
var_dump($e);
|
||||
}
|
||||
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
}
|
||||
|
||||
try {
|
||||
// This forces PHP to log errors rather than displaying errors on screen
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('log_errors', '1');
|
||||
|
||||
$logFilename = 'php_924_errors.log';
|
||||
$logFilepath = dirname(__FILE__).'/'.$logFilename;
|
||||
|
||||
if (file_exists($logFilepath)) {
|
||||
unlink($logFilepath);
|
||||
}
|
||||
|
||||
ini_set('error_log', $logFilepath);
|
||||
ini_set('pdo_sqlsrv.log_severity', '2'); // warnings only
|
||||
|
||||
$conn = new PDO("sqlsrv:server=$server;", $uid, $pwd);
|
||||
checkWarning($conn, 1);
|
||||
checkException($conn, 1);
|
||||
checkWarning($conn, 0);
|
||||
checkException($conn, 0);
|
||||
|
||||
if (file_exists($logFilepath)) {
|
||||
echo file_get_contents($logFilepath);
|
||||
unlink($logFilepath);
|
||||
} else {
|
||||
echo "Expected to find the log file\n";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
var_dump($e);
|
||||
}
|
||||
|
||||
echo "\nDone\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
3
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5701
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed database context to 'master'.
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5703
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed language setting to us_english.
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 5701
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Changed database context to '%s'.
|
||||
[%s UTC] PHP Warning: PDOStatement::execute(): SQLSTATE[01000]: Warning: 5701 %s[SQL Server]Changed database context to '%s'. in %spdo_924_display_more_errors.php on line %d
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 5701
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Changed database context to '%s'.
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 5701
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Changed database context to '%s'.
|
||||
[%s UTC] PHP Warning: PDOStatement::execute(): SQLSTATE[01000]: Warning: 5701 %s[SQL Server]Changed database context to '%s'. in %spdo_924_display_more_errors.php on line %d
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 5701
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Changed database context to '%s'.
|
||||
|
||||
Done
|
239
test/functional/pdo_sqlsrv/pdo_924_log_all_warnings.phpt
Normal file
239
test/functional/pdo_sqlsrv/pdo_924_log_all_warnings.phpt
Normal file
|
@ -0,0 +1,239 @@
|
|||
--TEST--
|
||||
GitHub issue 924 - verifies the warnings or error messages are logged to a log file
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
function toConnect()
|
||||
{
|
||||
require("MsSetup.inc");
|
||||
|
||||
$dsn = getDSN($server, $databaseName, $driver);
|
||||
$conn = new PDO($dsn, $uid, $pwd);
|
||||
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
return $conn;
|
||||
}
|
||||
|
||||
function printCursor($cursorArray)
|
||||
{
|
||||
if ($cursorArray[PDO::ATTR_CURSOR] == PDO::CURSOR_FWDONLY) {
|
||||
$cursor = 'FORWARD ONLY cursor';
|
||||
} else {
|
||||
switch ($cursorArray[PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE]) {
|
||||
case PDO::SQLSRV_CURSOR_DYNAMIC:
|
||||
$cursor = 'server side DYNAMIC cursor';
|
||||
break;
|
||||
case PDO::SQLSRV_CURSOR_STATIC:
|
||||
$cursor = 'server side STATIC cursor';
|
||||
break;
|
||||
case PDO::SQLSRV_CURSOR_KEYSET:
|
||||
$cursor = 'server side KEYSET cursor';
|
||||
break;
|
||||
case PDO::SQLSRV_CURSOR_BUFFERED:
|
||||
$cursor = 'client side BUFFERED cursor';
|
||||
break;
|
||||
default:
|
||||
$cursor = 'error';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
echo "#####Testing $cursor#####\n";
|
||||
return $cursor;
|
||||
}
|
||||
|
||||
function checkResults($data, $results, $resultSet, $expectedRows)
|
||||
{
|
||||
$failed = false;
|
||||
for ($j = 0; $j < $expectedRows; $j++) {
|
||||
if ($results[$j][0] != $data[$resultSet][$j]) {
|
||||
$failed = true;
|
||||
echo "Fetched results unexpected at row $j:\n";
|
||||
print_r($results[$j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $failed;
|
||||
}
|
||||
|
||||
try {
|
||||
ini_set('log_errors', '1');
|
||||
|
||||
$logFilename = 'php_924_cursors.log';
|
||||
$logFilepath = dirname(__FILE__).'/'.$logFilename;
|
||||
|
||||
if (file_exists($logFilepath)) {
|
||||
unlink($logFilepath);
|
||||
}
|
||||
|
||||
ini_set('error_log', $logFilepath);
|
||||
ini_set('pdo_sqlsrv.log_severity', '3'); // warnings and errors only
|
||||
|
||||
// All supported cursor types
|
||||
$cursors = array(array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY),
|
||||
array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_DYNAMIC),
|
||||
array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_STATIC),
|
||||
array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_KEYSET),
|
||||
array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED),
|
||||
);
|
||||
|
||||
|
||||
// Data for testing, all integer types
|
||||
$data = array(array(86, -217483648, 0, -432987563, 7, 217483647),
|
||||
array(0, 31, 127, 255, 1, 10),
|
||||
array(4534, -212, 32767, 0, 7, -32768),
|
||||
array(-1, 546098342985600, 9223372000000000000, 5115115115115, 7, -7),
|
||||
array(0, 1, 0, 0, 1, 1),
|
||||
);
|
||||
|
||||
$tableName = 'pdo_924_batchquery_test';
|
||||
|
||||
// Column names
|
||||
$colName = array('c1_int', 'c2_tinyint', 'c3_smallint', 'c4_bigint', 'c5_bit');
|
||||
$columns = array(new ColumnMeta('int', $colName[0]),
|
||||
new ColumnMeta('tinyint', $colName[1]),
|
||||
new ColumnMeta('smallint',$colName[2]),
|
||||
new ColumnMeta('bigint', $colName[3]),
|
||||
new ColumnMeta('bit', $colName[4]));
|
||||
|
||||
$conn = toConnect();
|
||||
createTable($conn, $tableName, $columns);
|
||||
|
||||
$expectedRows = sizeof($data[0]);
|
||||
|
||||
// Expected result sets = number of columns, since the batch fetches each column sequentially
|
||||
$expectedResultSets = count($colName);
|
||||
|
||||
// Insert each row. Need an associative array to use insertRow()
|
||||
for ($i = 0; $i < $expectedRows; ++$i) {
|
||||
$inputs = array();
|
||||
for ($j = 0; $j < $expectedResultSets; ++$j) {
|
||||
$inputs[$colName[$j]] = $data[$j][$i];
|
||||
}
|
||||
|
||||
$stmt = insertRow($conn, $tableName, $inputs);
|
||||
unset($stmt);
|
||||
}
|
||||
|
||||
$query = "SELECT c1_int FROM $tableName;
|
||||
SELECT c2_tinyint FROM $tableName;
|
||||
SELECT c3_smallint FROM $tableName;
|
||||
SELECT c4_bigint FROM $tableName;
|
||||
SELECT c5_bit FROM $tableName;";
|
||||
|
||||
for ($i = 0; $i < sizeof($cursors); ++$i) {
|
||||
$cursorType = $cursors[$i];
|
||||
// $cursor = printCursor($i);
|
||||
$cursor = printCursor($cursorType);
|
||||
|
||||
$stmt = $conn->prepare($query, $cursorType);
|
||||
$stmt->execute();
|
||||
|
||||
$numResultSets = 0;
|
||||
do {
|
||||
$res = $stmt->fetchAll(PDO::FETCH_NUM);
|
||||
$failed = checkResults($data, $res, $numResultSets, $expectedRows);
|
||||
++$numResultSets;
|
||||
} while (!$failed && $stmt->nextRowset());
|
||||
|
||||
if ($numResultSets != $expectedResultSets) {
|
||||
echo ("Unexpected number of result sets, expected $expectedResultedSets, got $numResultSets\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (file_exists($logFilepath)) {
|
||||
echo file_get_contents($logFilepath);
|
||||
unlink($logFilepath);
|
||||
}
|
||||
|
||||
unset($stmt);
|
||||
echo "#####Finished testing with $cursor#####\n";
|
||||
}
|
||||
|
||||
// Now reset logging by disabling it
|
||||
ini_set('pdo_sqlsrv.log_severity', '0');
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
var_dump($e->errorInfo);
|
||||
}
|
||||
|
||||
echo "Done.\n";
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
#####Testing FORWARD ONLY cursor#####
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5701
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed database context to '%s'.
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5703
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed language setting to us_english.
|
||||
#####Finished testing with FORWARD ONLY cursor#####
|
||||
#####Testing server side DYNAMIC cursor#####
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 16954
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Executing SQL directly; no cursor.
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
#####Finished testing with server side DYNAMIC cursor#####
|
||||
#####Testing server side STATIC cursor#####
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 16954
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Executing SQL directly; no cursor.
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
#####Finished testing with server side STATIC cursor#####
|
||||
#####Testing server side KEYSET cursor#####
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 16954
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Executing SQL directly; no cursor.
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0
|
||||
[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed
|
||||
#####Finished testing with server side KEYSET cursor#####
|
||||
#####Testing client side BUFFERED cursor#####
|
||||
#####Finished testing with client side BUFFERED cursor#####
|
||||
Done.
|
|
@ -44,6 +44,9 @@ try {
|
|||
} else {
|
||||
echo "$logFilepath is missing!\n";
|
||||
}
|
||||
|
||||
// Now reset logging by disabling it
|
||||
ini_set('pdo_sqlsrv.log_severity', '0');
|
||||
|
||||
echo "Done\n";
|
||||
} catch (Exception $e) {
|
||||
|
@ -56,6 +59,9 @@ try {
|
|||
[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5701
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed database context to '%s'.
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5703
|
||||
[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed language setting to %s.
|
||||
[%s UTC] pdo_sqlsrv_dbh_prepare: entering
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: entering
|
||||
[%s UTC] pdo_sqlsrv_stmt_describe_col: entering
|
||||
|
|
|
@ -5,21 +5,36 @@ Test the PDO::errorCode() and PDO::errorInfo() methods.
|
|||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("MsData_PDO_AllTypes.inc");
|
||||
|
||||
try {
|
||||
$db = connect();
|
||||
$tbname = "PDO_MainTypes";
|
||||
createTableMainTypes($db, $tbname);
|
||||
// query with a wrong column name.
|
||||
$db->query("SELECT * FROM $tbname WHERE IntColX = 1");
|
||||
$tbname = "PDO_test_error";
|
||||
|
||||
// create a dummy table
|
||||
createTable($db, $tbname, array(new ColumnMeta("int", "id")));
|
||||
|
||||
try {
|
||||
// query with a wrong column name -- catch the exception and show errors
|
||||
$stmt = $db->query("SELECT * FROM $tbname WHERE IntColX = 1");
|
||||
echo "Should have thrown an exception!\n";
|
||||
} catch (PDOException $e) {
|
||||
echo $db->errorCode() . PHP_EOL;
|
||||
if ($e->getCode() != $db->errorCode()) {
|
||||
echo "Error codes do not match!\n";
|
||||
echo $e->getCode() . PHP_EOL;
|
||||
}
|
||||
$info = $db->errorInfo();
|
||||
print_r($info);
|
||||
if ($e->errorInfo != $info) {
|
||||
echo "Error info arrays do not match!\n";
|
||||
print_r($e->errorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
dropTable($db, $tbname);
|
||||
unset($conn);
|
||||
unset($db);
|
||||
} catch (PDOException $e) {
|
||||
print($db->errorCode());
|
||||
echo "\n";
|
||||
print_r($db->errorInfo());
|
||||
var_dump($e);
|
||||
}
|
||||
?>
|
||||
--EXPECTREGEX--
|
||||
|
@ -29,4 +44,7 @@ Array
|
|||
\[0\] => 42S22
|
||||
\[1\] => 207
|
||||
\[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Invalid column name 'IntColX'\.
|
||||
\[3\] => 42000
|
||||
\[4\] => 8180
|
||||
\[5\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Statement\(s\) could not be prepared\.
|
||||
\)
|
|
@ -96,6 +96,9 @@ Done with 0
|
|||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 42S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 208
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Invalid object name 'temp_table'.
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 42000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 8180
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Statement(s) could not be prepared.
|
||||
Done with 1
|
||||
|
||||
[%s UTC] PHP Warning: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 208 %s[SQL Server]Invalid object name 'temp_table'. in %spdo_errorMode_logs.php on line %d
|
||||
|
@ -112,5 +115,8 @@ Done with 4
|
|||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 42S02
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 208
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Invalid object name 'temp_table'.
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 42000
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: error code = 8180
|
||||
[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Statement(s) could not be prepared.
|
||||
Done with -1
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
--TEST--
|
||||
Error checking for multiple active row sets (MARS) disabled
|
||||
--DESCRIPTION--
|
||||
This is similar to sqlsrv srv_053_mars_disabled_error_checks.phpt to check the errors
|
||||
when multiple active row sets (MARS) is disabled.
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsSetup.inc");
|
||||
|
||||
try {
|
||||
$conn = new PDO("sqlsrv:server=$server; MultipleActiveResultSets = false", $uid, $pwd);
|
||||
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$sql1 = "SELECT 'ONE'";
|
||||
$sql2 = "SELECT 'TWO'";
|
||||
|
||||
$stmt1 = $conn->query($sql1);
|
||||
$stmt2 = $conn->query($sql2);
|
||||
$res = [$stmt1->fetch(), $stmt2->fetch()];
|
||||
var_dump($res);
|
||||
|
||||
unset($stmt1);
|
||||
unset($stmt2);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
var_dump($e->errorInfo);
|
||||
}
|
||||
|
||||
echo "\nDone\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(5) "IMSSP"
|
||||
[1]=>
|
||||
int(-61)
|
||||
[2]=>
|
||||
string(313) "The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option."
|
||||
}
|
||||
|
||||
Done
|
Loading…
Reference in a new issue