From: fandrieu Date: Tue, 17 Oct 2017 18:16:38 +0000 (-0400) Subject: Implemented request #69592: allow 0-column rowsets to be skipped automatically X-Git-Tag: php-7.3.0alpha1~1252 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=014fd21b482cd1aa8e3fc8662936c18cee300670;p=php Implemented request #69592: allow 0-column rowsets to be skipped automatically This adds a new attribute PDO::DBLIB_ATTR_SKIP_EMPTY_ROWSETS to enable automatic skipping of empty rowsets. This happens with some SQL commands (like PRINT or SET): a rowset with 0 columns is returned by the driver. With this option enabled, 0 columns rowsets are automatically skipped, mirroring the behavior of the deprecated mssql extension. Credits go to MiRacLe-RPZ for developping and promoting this patch. --- diff --git a/NEWS b/NEWS index 3f9cff1e5f..2ab64b2f56 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,10 @@ PHP NEWS . Removed support for ODBCRouter. (Kalle) . Removed support for Birdstep. (Kalle) +- PDO_DBlib: + . Implemented request #69592 (allow 0-column rowsets to be skipped + automatically). (fandrieu) + - PDO_OCI: . Fixed bug #74631 (PDO_PCO with PHP-FPM: OCI environment initialized before PHP-FPM sets it up). (Ingmar Runge) diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index efc8dc1197..e8c010c563 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -287,6 +287,9 @@ static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER: H->stringify_uniqueidentifier = zval_get_long(val); return 1; + case PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS: + H->skip_empty_rowsets = zval_is_true(val); + return 1; default: return 0; } @@ -314,6 +317,10 @@ static int dblib_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_valu ZVAL_STRING(return_value, dbversion()); break; + case PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS: + ZVAL_BOOL(return_value, H->skip_empty_rowsets); + break; + default: return 0; } @@ -387,6 +394,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) H->err.sqlstate = dbh->error_code; H->assume_national_character_set_strings = 0; H->stringify_uniqueidentifier = 0; + H->skip_empty_rowsets = 0; if (!H->login) { goto cleanup; @@ -409,6 +417,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options) H->assume_national_character_set_strings = pdo_attr_lval(driver_options, PDO_ATTR_DEFAULT_STR_PARAM, 0) == PDO_PARAM_STR_NATL ? 1 : 0; H->stringify_uniqueidentifier = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, 0); + H->skip_empty_rowsets = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS, 0); } DBERRHANDLE(H->login, (EHANDLEFUNC) pdo_dblib_error_handler); diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index 6c8427da6b..469bd790de 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -124,20 +124,29 @@ static int pdo_dblib_stmt_next_rowset_no_cancel(pdo_stmt_t *stmt) pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; pdo_dblib_db_handle *H = S->H; RETCODE ret; + int num_fields; + + do { + ret = dbresults(H->link); + num_fields = dbnumcols(H->link); + } while (H->skip_empty_rowsets && num_fields <= 0 && ret == SUCCEED); - ret = dbresults(H->link); if (FAIL == ret) { pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL"); return 0; } - if(NO_MORE_RESULTS == ret) { + if (NO_MORE_RESULTS == ret) { + return 0; + } + + if (H->skip_empty_rowsets && num_fields <= 0) { return 0; } stmt->row_count = DBCOUNT(H->link); - stmt->column_count = dbnumcols(H->link); + stmt->column_count = num_fields; return 1; } diff --git a/ext/pdo_dblib/pdo_dblib.c b/ext/pdo_dblib/pdo_dblib.c index 1732cd75f9..d6a0eda07b 100644 --- a/ext/pdo_dblib/pdo_dblib.c +++ b/ext/pdo_dblib/pdo_dblib.c @@ -195,6 +195,7 @@ PHP_MINIT_FUNCTION(pdo_dblib) REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_QUERY_TIMEOUT", (long) PDO_DBLIB_ATTR_QUERY_TIMEOUT); REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER", (long) PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER); REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_VERSION", (long) PDO_DBLIB_ATTR_VERSION); + REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_SKIP_EMPTY_ROWSETS", (long) PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS); if (FAIL == dbinit()) { return FAILURE; diff --git a/ext/pdo_dblib/php_pdo_dblib_int.h b/ext/pdo_dblib/php_pdo_dblib_int.h index c40697680f..1b59dd3a38 100644 --- a/ext/pdo_dblib/php_pdo_dblib_int.h +++ b/ext/pdo_dblib/php_pdo_dblib_int.h @@ -118,6 +118,7 @@ typedef struct { pdo_dblib_err err; unsigned assume_national_character_set_strings:1; unsigned stringify_uniqueidentifier:1; + unsigned skip_empty_rowsets:1; } pdo_dblib_db_handle; typedef struct { @@ -150,6 +151,7 @@ enum { PDO_DBLIB_ATTR_QUERY_TIMEOUT, PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, PDO_DBLIB_ATTR_VERSION, + PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS, }; #endif diff --git a/ext/pdo_dblib/tests/bug_69592.phpt b/ext/pdo_dblib/tests/bug_69592.phpt new file mode 100644 index 0000000000..98936618d1 --- /dev/null +++ b/ext/pdo_dblib/tests/bug_69592.phpt @@ -0,0 +1,60 @@ +--TEST-- +PDO_DBLIB: PDO::DBLIB_ATTR_SKIP_EMPTY_ROWSETS for skip junk resultsets on SET NOCOUNT expression +--SKIPIF-- + +--FILE-- +getAttribute(PDO::DBLIB_ATTR_SKIP_EMPTY_ROWSETS)); + +$stmt = $db->query($sql); +var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); +var_dump($stmt->nextRowset()); +var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); +$stmt->closeCursor(); + + +$db->setAttribute(PDO::DBLIB_ATTR_SKIP_EMPTY_ROWSETS, true); +var_dump($db->getAttribute(PDO::DBLIB_ATTR_SKIP_EMPTY_ROWSETS)); + +$stmt = $db->query($sql); +var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); +var_dump($stmt->nextRowset()); +var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); +$stmt->closeCursor(); +var_dump($db->getAttribute(PDO::DBLIB_ATTR_SKIP_EMPTY_ROWSETS)); + +?> +--EXPECT-- +bool(false) +array(0) { +} +bool(true) +array(1) { + [0]=> + array(1) { + ["result"]=> + int(0) + } +} +bool(true) +array(1) { + [0]=> + array(1) { + ["result"]=> + int(0) + } +} +bool(false) +array(0) { +} +bool(true)