From 8666ea63c71dfc16a178baef5e9500c6575b31b9 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Thu, 21 Sep 2017 17:55:59 -0700 Subject: [PATCH] Fixed bug for sqlsrv too, sqlsrv test added --- source/pdo_sqlsrv/pdo_stmt.cpp | 8 -- source/shared/core_stmt.cpp | 9 ++ .../sqlsrv/sqlsrv_empty_result_error.phpt | 118 ++++++++++++++++++ 3 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 test/functional/sqlsrv/sqlsrv_empty_result_error.phpt diff --git a/source/pdo_sqlsrv/pdo_stmt.cpp b/source/pdo_sqlsrv/pdo_stmt.cpp index d548d6bc..85d726fd 100644 --- a/source/pdo_sqlsrv/pdo_stmt.cpp +++ b/source/pdo_sqlsrv/pdo_stmt.cpp @@ -1067,14 +1067,6 @@ int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_next_rowset: driver_data object was null" ); - // If SQLNumResultCols returns 0, the result set is empty. Normally this error is - // handled in core_sqlsrv_fetch, but if the user calls nextRowset() before fetch() - // the error message won't show up unless we handle it here. - SQLSMALLINT has_fields = core::SQLNumResultCols( driver_stmt TSRMLS_CC ); - CHECK_CUSTOM_ERROR( has_fields == 0, driver_stmt, SQLSRV_ERROR_NO_FIELDS ) { - throw core::CoreException(); - } - core_sqlsrv_next_result( static_cast( stmt->driver_data ) TSRMLS_CC ); // clear the current meta data since the new result will generate new meta data diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 349dbfc0..bcb4697f 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -1032,6 +1032,15 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin CHECK_CUSTOM_ERROR( stmt->past_next_result_end, stmt, SQLSRV_ERROR_NEXT_RESULT_PAST_END ) { throw core::CoreException(); } + + // Make sure that the result set is not null, i.e. SQLNumResultCols() does not + // return 0. Normally this error is handled in core_sqlsrv_fetch, but if the + // user calls sqlsrv_next_result() or nextRowset() before fetch() the error is + // never shown so we handle it here. + SQLSMALLINT has_fields = core::SQLNumResultCols( stmt TSRMLS_CC ); + CHECK_CUSTOM_ERROR( has_fields == 0, stmt, SQLSRV_ERROR_NO_FIELDS ) { + throw core::CoreException(); + } close_active_stream( stmt TSRMLS_CC ); diff --git a/test/functional/sqlsrv/sqlsrv_empty_result_error.phpt b/test/functional/sqlsrv/sqlsrv_empty_result_error.phpt new file mode 100644 index 00000000..68fedaa3 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_empty_result_error.phpt @@ -0,0 +1,118 @@ +--TEST-- +Test that calling sqlsrv_next_result() on a null result set produces the correct error message. Fix for Github 507. +--SKIPIF-- + +--FILE-- +$databaseName, "uid"=>$uid, "pwd"=>$pwd)); + +$stmt = sqlsrv_query($conn, "IF OBJECT_ID('TestEmptySetTable', 'U') IS NOT NULL DROP TABLE TestEmptySetTable"); +$stmt = sqlsrv_query($conn, "CREATE TABLE TestEmptySetTable ([c1] nvarchar(10),[c2] nvarchar(10))"); +$stmt = sqlsrv_query($conn, "INSERT INTO TestEmptySetTable (c1, c2) VALUES ('a', 'b')"); +$stmt = sqlsrv_query($conn, "IF OBJECT_ID('TestEmptySetProc', 'P') IS NOT NULL DROP PROCEDURE TestEmptySetProc"); +$stmt = sqlsrv_query($conn, "CREATE PROCEDURE TestEmptySetProc @a nvarchar(10), @b nvarchar(10) + AS SET NOCOUNT ON + BEGIN + IF @b='b' + BEGIN + SELECT 'a' as testValue + END + ELSE + BEGIN + UPDATE TestEmptySetTable SET c2 = 'c' WHERE c1 = @a + END + END"); + +// errors out when reaching the second nextRowset() call +// returned error indicates there are no more results +echo "Return a nonempty result set:\n"; + +$stmt = sqlsrv_query($conn,"TestEmptySetProc @a='a', @b='b'"); +$result = sqlsrv_fetch_array($stmt); +print_r($result); +sqlsrv_next_result($stmt); +$result = sqlsrv_fetch_array($stmt); +print_r($result); +sqlsrv_next_result($stmt); + +print_r(sqlsrv_errors()); + +// errors out indicating the result set contains no fields +echo "Return an empty result set, call nextRowset on it before fetching anything:\n"; + +$stmt = sqlsrv_query($conn, "TestEmptySetProc @a='a', @b='c'"); +sqlsrv_next_result($stmt); +print_r(sqlsrv_errors()); + +// errors out indicating the result set contains no fields +echo "Return an empty result set, call fetch on it:\n"; + +$stmt = sqlsrv_query($conn, "TestEmptySetProc @a='a', @b='c'"); +$result = sqlsrv_fetch_array($stmt); +print_r($result); +print_r(sqlsrv_errors()); + +$stmt = sqlsrv_query($conn, "DROP TABLE TestEmptySetTable"); +$stmt = sqlsrv_query($conn, "DROP PROCEDURE TestEmptySetProc"); +sqlsrv_free($conn); +?> +--EXPECT-- +Return a nonempty result set: +Array +( + [0] => a + [testValue] => a +) +Array +( + [0] => Array + ( + [0] => IMSSP + [SQLSTATE] => IMSSP + [1] => -26 + [code] => -26 + [2] => There are no more results returned by the query. + [message] => There are no more results returned by the query. + ) + + [1] => Array + ( + [0] => HY010 + [SQLSTATE] => HY010 + [1] => 0 + [code] => 0 + [2] => [unixODBC][Driver Manager]Function sequence error + [message] => [unixODBC][Driver Manager]Function sequence error + ) + +) +Return an empty result set, call nextRowset on it before fetching anything: +Array +( + [0] => Array + ( + [0] => IMSSP + [SQLSTATE] => IMSSP + [1] => -28 + [code] => -28 + [2] => The active result for the query contains no fields. + [message] => The active result for the query contains no fields. + ) + +) +Return an empty result set, call fetch on it: +Array +( + [0] => Array + ( + [0] => IMSSP + [SQLSTATE] => IMSSP + [1] => -28 + [code] => -28 + [2] => The active result for the query contains no fields. + [message] => The active result for the query contains no fields. + ) + +)