Issue 937 - fixed ASSERT and added new tests (#940)

This commit is contained in:
Jenny Tam 2019-02-27 16:54:26 -08:00 committed by GitHub
parent b1b7a40f70
commit 12d01c9189
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 263 additions and 10 deletions

View file

@ -1029,20 +1029,28 @@ int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno
try {
SQLSRV_ASSERT( stmt != NULL, "pdo_sqlsrv_stmt_get_col_meta: pdo_stmt object was null" );
SQLSRV_ASSERT( stmt->columns != NULL, "pdo_sqlsrv_stmt_get_col_meta: columns are not available." );
SQLSRV_ASSERT( Z_TYPE_P( return_value ) == IS_NULL, "Metadata already has value. Must be NULL." );
sqlsrv_malloc_auto_ptr<field_meta_data> core_meta_data;
sqlsrv_stmt* driver_stmt = static_cast<sqlsrv_stmt*>( stmt->driver_data );
SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_get_col_meta: stmt->driver_data was null");
SQLSRV_ASSERT( colno >= 0 && colno < stmt->column_count, "pdo_sqlsrv_stmt_get_col_meta: invalid column number." );
// Based on PDOStatement::getColumnMeta API, this should return FALSE
// if the requested column does not exist in the result set, or if
// no result set exists. Thus, do not use SQLSRV_ASSERT, which causes
// the script to fail right away. Instead, log this warning if logging
// is enabled
if (colno < 0 || colno >= stmt->column_count || stmt->columns == NULL) {
LOG( SEV_WARNING, "Invalid column number %1!d!", colno );
return FAILURE;
}
core_meta_data = core_sqlsrv_field_metadata( driver_stmt, (SQLSMALLINT) colno TSRMLS_CC );
// initialize the array to nothing, as PDO requires us to create it
core::sqlsrv_array_init( *driver_stmt, return_value TSRMLS_CC );
sqlsrv_malloc_auto_ptr<field_meta_data> core_meta_data;
core_meta_data = core_sqlsrv_field_metadata( driver_stmt, (SQLSMALLINT) colno TSRMLS_CC );
// add the following fields: flags, native_type, driver:decl_type, table
add_assoc_long( return_value, "flags", 0 );

View file

@ -1807,7 +1807,7 @@ SQLSMALLINT get_resultset_meta_data(_Inout_ sqlsrv_stmt * stmt)
throw;
}
SQLSRV_ASSERT(num_cols > 0 && stmt->current_meta_data.size() == num_cols, "Meta data vector out of sync" );
SQLSRV_ASSERT(stmt->current_meta_data.size() == num_cols, "Meta data vector out of sync" );
return num_cols;
}

View file

@ -0,0 +1,122 @@
--TEST--
GitHub issue 937 - getting metadata will not fail after an UPDATE / DELETE statement
--DESCRIPTION--
Verifies that getColumnMeta will not fail after processing an UPDATE / DELETE query that returns no fields. Instead, it should simply return FALSE because no result set exists.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
$tableName = 'pdoTestTable_938';
$procName = 'pdoTestProc_938';
function checkMetaData($stmt)
{
$metadata = $stmt->getColumnMeta(0);
if ($metadata !== FALSE) {
echo "Expects FALSE because no result set exists!\n";
}
}
try {
$conn = connect();
dropTable($conn, $tableName);
dropProc($conn, $procName);
$tsql = "CREATE TABLE $tableName([id] [int] NOT NULL, [name] [varchar](10) NOT NULL)";
$conn->query($tsql);
$id = 3;
$tsql = "INSERT INTO $tableName VALUES ($id, 'abcde')";
$conn->query($tsql);
$tsql = "UPDATE $tableName SET name = 'updated' WHERE id = $id";
$stmt = $conn->prepare($tsql);
$stmt->execute();
$numCol = $metadata = $stmt->columnCount();
echo "Number of columns after UPDATE: $numCol\n";
checkMetaData($stmt);
$tsql = "SELECT * FROM $tableName";
$stmt = $conn->query($tsql);
$numCol = $metadata = $stmt->columnCount();
for ($i = 0; $i < $numCol; $i++) {
$metadata = $stmt->getColumnMeta($i);
var_dump($metadata);
}
createProc($conn, $procName, "@id int, @val varchar(10) OUTPUT", "SELECT @val = name FROM $tableName WHERE id = @id");
$value = '';
$tsql = "{CALL [$procName] (?, ?)}";
$stmt = $conn->prepare($tsql);
$stmt->bindParam(1, $id, PDO::PARAM_INT);
$stmt->bindParam(2, $value, PDO::PARAM_STR, 10);
$stmt->execute();
$numCol = $metadata = $stmt->columnCount();
echo "Number of columns after PROCEDURE: $numCol\n";
echo "Value returned: $value\n";
checkMetaData($stmt);
$query = "DELETE FROM $tableName WHERE name = 'updated'";
$stmt = $conn->query($query);
$numCol = $metadata = $stmt->columnCount();
echo "Number of columns after DELETE: $numCol\n";
checkMetaData($stmt);
} catch (PDOException $e) {
echo $e->getMessage() . PHP_EOL;
}
dropTable($conn, $tableName);
dropProc($conn, $procName);
unset($stmt);
unset($conn);
?>
--EXPECT--
Number of columns after UPDATE: 0
array(8) {
["flags"]=>
int(0)
["sqlsrv:decl_type"]=>
string(3) "int"
["native_type"]=>
string(6) "string"
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
["name"]=>
string(2) "id"
["len"]=>
int(10)
["precision"]=>
int(0)
}
array(8) {
["flags"]=>
int(0)
["sqlsrv:decl_type"]=>
string(7) "varchar"
["native_type"]=>
string(6) "string"
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
["name"]=>
string(4) "name"
["len"]=>
int(10)
["precision"]=>
int(0)
}
Number of columns after PROCEDURE: 0
Value returned: updated
Number of columns after DELETE: 0

View file

@ -220,5 +220,4 @@ array(7) {
Warning: PDOStatement::getColumnMeta(): SQLSTATE[42P10]: Invalid column reference: column number must be non-negative in %s on line %x
bool(false)
Fatal error: pdo_sqlsrv_stmt_get_col_meta: invalid column number. in %s on line %x
bool(false)

View file

@ -259,5 +259,4 @@ array(7) {
Warning: PDOStatement::getColumnMeta(): SQLSTATE[42P10]: Invalid column reference: column number must be non-negative in %s on line %x
bool(false)
Fatal error: pdo_sqlsrv_stmt_get_col_meta: invalid column number. in %s on line %x
bool(false)

View file

@ -0,0 +1,125 @@
--TEST--
GitHub issue #937 - getting metadata will not fail after an UPDATE / DELETE statement
--DESCRIPTION--
Verifies that sqlsrv_field_metadata will return an empty array after processing an
UPDATE / DELETE query that returns no fields.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$conn = connect();
if ($conn === false) {
die(print_r(sqlsrv_errors(), true));
}
$tableName = 'srvTestTable_938';
$procName = 'srvTestProc_938';
dropTable($conn, $tableName);
dropProc($conn, $procName);
// Create the test table
$tsql = "CREATE TABLE $tableName([id] [int] NOT NULL,
[dummyColumn] [varchar](10) NOT NULL
)";
$stmt = sqlsrv_query($conn, $tsql);
if (!$stmt) {
fatalError("Failed to create table $tableName\n");
}
$id = 5;
$tsql = "INSERT INTO $tableName VALUES ($id, 'dummy')";
$stmt = sqlsrv_query($conn, $tsql);
if (!$stmt) {
fatalError("Failed to insert a row into table $tableName\n");
}
$tsql = "SELECT * FROM $tableName";
$stmt = sqlsrv_query($conn, $tsql);
$fieldmeta = sqlsrv_field_metadata($stmt);
var_dump($fieldmeta);
$tsql = "UPDATE $tableName SET dummyColumn = 'updated' WHERE id = $id";
$stmt = sqlsrv_prepare($conn, $tsql);
sqlsrv_execute($stmt);
$fieldmeta = sqlsrv_field_metadata($stmt);
var_dump($fieldmeta);
createProc($conn, $procName, "@id int, @val varchar(10) OUTPUT", "SELECT @val = dummyColumn FROM $tableName WHERE id = @id");
$value = '';
$tsql = "{CALL [$procName] (?, ?)}";
$stmt = sqlsrv_prepare(
$conn,
$tsql,
array(array($id, SQLSRV_PARAM_IN),
array(&$value, SQLSRV_PARAM_OUT)
)
);
$result = sqlsrv_execute($stmt);
if (!$result) {
fatalError("Failed to invoke stored procedure $procName\n");
}
echo "The value returned: $value\n";
$fieldmeta = sqlsrv_field_metadata($stmt);
var_dump($fieldmeta);
$options = array("Scrollable" => "buffered");
$tsql = "DELETE FROM $tableName WHERE dummyColumn = 'updated'";
$stmt = sqlsrv_query($conn, $tsql, array(), $options);
$fieldmeta = sqlsrv_field_metadata($stmt);
var_dump($fieldmeta);
dropTable($conn, $tableName);
dropProc($conn, $procName);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>
--EXPECT--
array(2) {
[0]=>
array(6) {
["Name"]=>
string(2) "id"
["Type"]=>
int(4)
["Size"]=>
NULL
["Precision"]=>
int(10)
["Scale"]=>
NULL
["Nullable"]=>
int(0)
}
[1]=>
array(6) {
["Name"]=>
string(11) "dummyColumn"
["Type"]=>
int(12)
["Size"]=>
int(10)
["Precision"]=>
NULL
["Scale"]=>
NULL
["Nullable"]=>
int(0)
}
}
array(0) {
}
The value returned: updated
array(0) {
}
array(0) {
}