Merge pull request #344 from v-kaywon/error_numcol
workaround for unixODBC bug returning error when getting numcol
This commit is contained in:
commit
52e05992bd
|
@ -690,21 +690,22 @@ zend_long pdo_sqlsrv_dbh_do( pdo_dbh_t *dbh, const char *sql, size_t sql_len TSR
|
||||||
NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt TSRMLS_CC );
|
NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt TSRMLS_CC );
|
||||||
driver_stmt->set_func( __FUNCTION__ );
|
driver_stmt->set_func( __FUNCTION__ );
|
||||||
|
|
||||||
core_sqlsrv_execute( driver_stmt TSRMLS_CC, sql, static_cast<int>( sql_len ) );
|
SQLRETURN execReturn = core_sqlsrv_execute( driver_stmt TSRMLS_CC, sql, static_cast<int>( sql_len ) );
|
||||||
|
|
||||||
// since the user can give us a compound statement, we return the row count for the last set, and since the row count
|
// since the user can give us a compound statement, we return the row count for the last set, and since the row count
|
||||||
// isn't guaranteed to be valid until all the results have been fetched, we fetch them all first.
|
// isn't guaranteed to be valid until all the results have been fetched, we fetch them all first.
|
||||||
if( core_sqlsrv_has_any_result( driver_stmt TSRMLS_CC )) {
|
|
||||||
|
if ( execReturn != SQL_NO_DATA && core_sqlsrv_has_any_result( driver_stmt TSRMLS_CC )) {
|
||||||
|
|
||||||
SQLRETURN r = SQL_SUCCESS;
|
SQLRETURN r = SQL_SUCCESS;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
rows = core::SQLRowCount( driver_stmt TSRMLS_CC );
|
rows = core::SQLRowCount( driver_stmt TSRMLS_CC );
|
||||||
|
|
||||||
r = core::SQLMoreResults( driver_stmt TSRMLS_CC );
|
r = core::SQLMoreResults( driver_stmt TSRMLS_CC );
|
||||||
|
|
||||||
} while( r != SQL_NO_DATA );
|
} while ( r != SQL_NO_DATA );
|
||||||
}
|
}
|
||||||
|
|
||||||
// returning -1 forces PDO to return false, which signals an error occurred. SQLRowCount returns -1 for a number of cases
|
// returning -1 forces PDO to return false, which signals an error occurred. SQLRowCount returns -1 for a number of cases
|
||||||
|
|
|
@ -552,12 +552,18 @@ int pdo_sqlsrv_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
|
||||||
query_len = static_cast<unsigned int>( stmt->active_query_stringlen );
|
query_len = static_cast<unsigned int>( stmt->active_query_stringlen );
|
||||||
}
|
}
|
||||||
|
|
||||||
core_sqlsrv_execute( driver_stmt TSRMLS_CC, query, query_len );
|
SQLRETURN execReturn = core_sqlsrv_execute( driver_stmt TSRMLS_CC, query, query_len );
|
||||||
|
|
||||||
stmt->column_count = core::SQLNumResultCols( driver_stmt TSRMLS_CC );
|
if ( execReturn == SQL_NO_DATA ) {
|
||||||
|
stmt->column_count = 0;
|
||||||
|
stmt->row_count = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stmt->column_count = core::SQLNumResultCols( driver_stmt TSRMLS_CC );
|
||||||
|
|
||||||
// return the row count regardless if there are any rows or not
|
// return the row count regardless if there are any rows or not
|
||||||
stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC );
|
stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC );
|
||||||
|
}
|
||||||
|
|
||||||
// workaround for a bug in the PDO driver manager. It is fairly simple to crash the PDO driver manager with
|
// workaround for a bug in the PDO driver manager. It is fairly simple to crash the PDO driver manager with
|
||||||
// the following sequence:
|
// the following sequence:
|
||||||
|
|
|
@ -1364,7 +1364,7 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm
|
||||||
void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLINT direction, zval* param_z,
|
void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLINT direction, zval* param_z,
|
||||||
SQLSRV_PHPTYPE php_out_type, SQLSRV_ENCODING encoding, SQLSMALLINT sql_type, SQLULEN column_size,
|
SQLSRV_PHPTYPE php_out_type, SQLSRV_ENCODING encoding, SQLSMALLINT sql_type, SQLULEN column_size,
|
||||||
SQLSMALLINT decimal_digits TSRMLS_DC );
|
SQLSMALLINT decimal_digits TSRMLS_DC );
|
||||||
void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql = NULL, int sql_len = 0 );
|
SQLRETURN core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql = NULL, int sql_len = 0 );
|
||||||
field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT colno TSRMLS_DC );
|
field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT colno TSRMLS_DC );
|
||||||
bool core_sqlsrv_fetch( sqlsrv_stmt* stmt, SQLSMALLINT fetch_orientation, SQLULEN fetch_offset TSRMLS_DC );
|
bool core_sqlsrv_fetch( sqlsrv_stmt* stmt, SQLSMALLINT fetch_orientation, SQLULEN fetch_offset TSRMLS_DC );
|
||||||
void core_sqlsrv_get_field(sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_phptype, bool prefer_string,
|
void core_sqlsrv_get_field(sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_phptype, bool prefer_string,
|
||||||
|
@ -2041,7 +2041,7 @@ namespace core {
|
||||||
SQLRETURN r;
|
SQLRETURN r;
|
||||||
SQLSMALLINT num_cols;
|
SQLSMALLINT num_cols;
|
||||||
r = ::SQLNumResultCols( stmt->handle(), &num_cols );
|
r = ::SQLNumResultCols( stmt->handle(), &num_cols );
|
||||||
|
|
||||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||||
throw CoreException();
|
throw CoreException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -676,9 +676,9 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALL
|
||||||
// Return:
|
// Return:
|
||||||
// true if there is data, false if there is not
|
// true if there is data, false if there is not
|
||||||
|
|
||||||
void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_len )
|
SQLRETURN core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_len )
|
||||||
{
|
{
|
||||||
SQLRETURN r;
|
SQLRETURN r = SQL_ERROR;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -709,7 +709,7 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_
|
||||||
r = core::SQLExecute( stmt TSRMLS_CC );
|
r = core::SQLExecute( stmt TSRMLS_CC );
|
||||||
}
|
}
|
||||||
|
|
||||||
// if data is needed (streams were bound) and they should be sent at execute time, then do so now
|
// if data is needed (streams were bound) and they should be sent at execute time, then do so now
|
||||||
if( r == SQL_NEED_DATA && stmt->send_streams_at_exec ) {
|
if( r == SQL_NEED_DATA && stmt->send_streams_at_exec ) {
|
||||||
|
|
||||||
send_param_streams( stmt TSRMLS_CC );
|
send_param_streams( stmt TSRMLS_CC );
|
||||||
|
@ -723,20 +723,21 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_
|
||||||
|
|
||||||
finalize_output_parameters( stmt TSRMLS_CC );
|
finalize_output_parameters( stmt TSRMLS_CC );
|
||||||
}
|
}
|
||||||
// stream parameters are sent, clean the Hashtable
|
// stream parameters are sent, clean the Hashtable
|
||||||
if ( stmt->send_streams_at_exec ) {
|
if ( stmt->send_streams_at_exec ) {
|
||||||
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
catch( core::CoreException& e ) {
|
catch( core::CoreException& e ) {
|
||||||
|
|
||||||
// if the statement executed but failed in a subsequent operation before returning,
|
// if the statement executed but failed in a subsequent operation before returning,
|
||||||
// we need to cancel the statement and deref the output and stream parameters
|
// we need to cancel the statement and deref the output and stream parameters
|
||||||
if ( stmt->send_streams_at_exec ) {
|
if ( stmt->send_streams_at_exec ) {
|
||||||
zend_hash_clean( Z_ARRVAL( stmt->output_params ));
|
zend_hash_clean( Z_ARRVAL( stmt->output_params ));
|
||||||
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
||||||
}
|
}
|
||||||
if( stmt->executed ) {
|
if( stmt->executed ) {
|
||||||
SQLCancel( stmt->handle() );
|
SQLCancel( stmt->handle() );
|
||||||
// stmt->executed = false; should this be reset if something fails?
|
// stmt->executed = false; should this be reset if something fails?
|
||||||
}
|
}
|
||||||
|
|
60
test/pdo_sqlsrv/pdo_336_pho_exec_empty_result_set_error.phpt
Normal file
60
test/pdo_sqlsrv/pdo_336_pho_exec_empty_result_set_error.phpt
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
--TEST--
|
||||||
|
GitHub issue #336 - PDO::exec should not return an error with query returning SQL_NO_DATA
|
||||||
|
--DESCRIPTION--
|
||||||
|
Verifies GitHub issue 336 is fixed, PDO::exec on query returning SQL_NO_DATA will not give an error
|
||||||
|
--SKIPIF--
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
// Connect
|
||||||
|
require_once("autonomous_setup.php");
|
||||||
|
$dbName = "tempdb";
|
||||||
|
|
||||||
|
$conn = new PDO("sqlsrv:server=$serverName;Database=$dbName", $username, $password);
|
||||||
|
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
|
||||||
|
|
||||||
|
$sql = "DELETE FROM foo_table WHERE id = 42";
|
||||||
|
$sqlWithParameter = "DELETE FROM foo_table WHERE id = :id";
|
||||||
|
$sqlParameter = 42;
|
||||||
|
|
||||||
|
$Statement = $conn->exec("IF OBJECT_ID('foo_table', 'U') IS NOT NULL DROP TABLE foo_table");
|
||||||
|
$Statement = $conn->exec("CREATE TABLE foo_table (id BIGINT PRIMARY KEY NOT NULL IDENTITY, intField INT NOT NULL)");
|
||||||
|
$Statement = $conn->exec("INSERT INTO foo_table (intField) VALUES(3)");
|
||||||
|
|
||||||
|
//test prepare, not args
|
||||||
|
$stmt = $conn->prepare($sql);
|
||||||
|
$stmt->execute();
|
||||||
|
if ($conn->errorCode() == "00000")
|
||||||
|
echo "prepare OK\n";
|
||||||
|
else
|
||||||
|
echo "unexpected error at prepare";
|
||||||
|
|
||||||
|
//test prepare, with args
|
||||||
|
$stmt = $conn->prepare($sqlWithParameter);
|
||||||
|
$stmt->execute(array(':id' => $sqlParameter));
|
||||||
|
if ($conn->errorCode() == "00000")
|
||||||
|
echo "prepare with args OK\n";
|
||||||
|
else
|
||||||
|
echo "unexpected error at prepare with args";
|
||||||
|
|
||||||
|
//test direct exec
|
||||||
|
$stmt = $conn->exec($sql);
|
||||||
|
$err = $conn->errorCode();
|
||||||
|
if ($stmt == 0 && $err == "00000")
|
||||||
|
echo "direct exec OK\n";
|
||||||
|
else
|
||||||
|
if ($stmt != 0)
|
||||||
|
echo "unexpected row returned at direct exec\n";
|
||||||
|
if ($err != "00000")
|
||||||
|
echo "unexpected error at direct exec";
|
||||||
|
|
||||||
|
$Statement = $conn->exec("IF OBJECT_ID('foo_table', 'U') IS NOT NULL DROP TABLE foo_table");
|
||||||
|
|
||||||
|
$stmt = NULL;
|
||||||
|
$Statement = NULL;
|
||||||
|
$conn = NULL;
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
prepare OK
|
||||||
|
prepare with args OK
|
||||||
|
direct exec OK
|
Loading…
Reference in a new issue