Skip to content

Commit

Permalink
Issue 937 - fixed ASSERT and added new tests (#940)
Browse files Browse the repository at this point in the history
  • Loading branch information
yitam authored Feb 28, 2019
1 parent b1b7a40 commit 12d01c9
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 10 deletions.
18 changes: 13 additions & 5 deletions source/pdo_sqlsrv/pdo_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

Expand Down
2 changes: 1 addition & 1 deletion source/sqlsrv/stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
122 changes: 122 additions & 0 deletions test/functional/pdo_sqlsrv/pdo_937_metadata.phpt
Original file line number Diff line number Diff line change
@@ -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
3 changes: 1 addition & 2 deletions test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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)
125 changes: 125 additions & 0 deletions test/functional/sqlsrv/srv_937_metadata.phpt
Original file line number Diff line number Diff line change
@@ -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) {
}

0 comments on commit 12d01c9

Please sign in to comment.