Skip to content

Commit 12d01c9

Browse files
authored
Issue 937 - fixed ASSERT and added new tests (#940)
1 parent b1b7a40 commit 12d01c9

File tree

6 files changed

+263
-10
lines changed

6 files changed

+263
-10
lines changed

source/pdo_sqlsrv/pdo_stmt.cpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -1029,20 +1029,28 @@ int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno
10291029

10301030
try {
10311031
SQLSRV_ASSERT( stmt != NULL, "pdo_sqlsrv_stmt_get_col_meta: pdo_stmt object was null" );
1032-
SQLSRV_ASSERT( stmt->columns != NULL, "pdo_sqlsrv_stmt_get_col_meta: columns are not available." );
10331032
SQLSRV_ASSERT( Z_TYPE_P( return_value ) == IS_NULL, "Metadata already has value. Must be NULL." );
10341033

1035-
sqlsrv_malloc_auto_ptr<field_meta_data> core_meta_data;
1036-
10371034
sqlsrv_stmt* driver_stmt = static_cast<sqlsrv_stmt*>( stmt->driver_data );
10381035
SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_get_col_meta: stmt->driver_data was null");
10391036

1040-
SQLSRV_ASSERT( colno >= 0 && colno < stmt->column_count, "pdo_sqlsrv_stmt_get_col_meta: invalid column number." );
1037+
// Based on PDOStatement::getColumnMeta API, this should return FALSE
1038+
// if the requested column does not exist in the result set, or if
1039+
// no result set exists. Thus, do not use SQLSRV_ASSERT, which causes
1040+
// the script to fail right away. Instead, log this warning if logging
1041+
// is enabled
1042+
if (colno < 0 || colno >= stmt->column_count || stmt->columns == NULL) {
1043+
LOG( SEV_WARNING, "Invalid column number %1!d!", colno );
1044+
return FAILURE;
1045+
}
10411046

1042-
core_meta_data = core_sqlsrv_field_metadata( driver_stmt, (SQLSMALLINT) colno TSRMLS_CC );
10431047
// initialize the array to nothing, as PDO requires us to create it
10441048
core::sqlsrv_array_init( *driver_stmt, return_value TSRMLS_CC );
10451049

1050+
sqlsrv_malloc_auto_ptr<field_meta_data> core_meta_data;
1051+
1052+
core_meta_data = core_sqlsrv_field_metadata( driver_stmt, (SQLSMALLINT) colno TSRMLS_CC );
1053+
10461054
// add the following fields: flags, native_type, driver:decl_type, table
10471055
add_assoc_long( return_value, "flags", 0 );
10481056

source/sqlsrv/stmt.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1807,7 +1807,7 @@ SQLSMALLINT get_resultset_meta_data(_Inout_ sqlsrv_stmt * stmt)
18071807
throw;
18081808
}
18091809

1810-
SQLSRV_ASSERT(num_cols > 0 && stmt->current_meta_data.size() == num_cols, "Meta data vector out of sync" );
1810+
SQLSRV_ASSERT(stmt->current_meta_data.size() == num_cols, "Meta data vector out of sync" );
18111811

18121812
return num_cols;
18131813
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
--TEST--
2+
GitHub issue 937 - getting metadata will not fail after an UPDATE / DELETE statement
3+
--DESCRIPTION--
4+
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.
5+
--ENV--
6+
PHPT_EXEC=true
7+
--SKIPIF--
8+
<?php require('skipif_mid-refactor.inc'); ?>
9+
--FILE--
10+
<?php
11+
require_once("MsSetup.inc");
12+
require_once("MsCommon_mid-refactor.inc");
13+
14+
$tableName = 'pdoTestTable_938';
15+
$procName = 'pdoTestProc_938';
16+
17+
function checkMetaData($stmt)
18+
{
19+
$metadata = $stmt->getColumnMeta(0);
20+
if ($metadata !== FALSE) {
21+
echo "Expects FALSE because no result set exists!\n";
22+
}
23+
}
24+
25+
try {
26+
$conn = connect();
27+
28+
dropTable($conn, $tableName);
29+
dropProc($conn, $procName);
30+
31+
$tsql = "CREATE TABLE $tableName([id] [int] NOT NULL, [name] [varchar](10) NOT NULL)";
32+
$conn->query($tsql);
33+
34+
$id = 3;
35+
$tsql = "INSERT INTO $tableName VALUES ($id, 'abcde')";
36+
$conn->query($tsql);
37+
38+
$tsql = "UPDATE $tableName SET name = 'updated' WHERE id = $id";
39+
$stmt = $conn->prepare($tsql);
40+
$stmt->execute();
41+
$numCol = $metadata = $stmt->columnCount();
42+
echo "Number of columns after UPDATE: $numCol\n";
43+
checkMetaData($stmt);
44+
45+
$tsql = "SELECT * FROM $tableName";
46+
$stmt = $conn->query($tsql);
47+
$numCol = $metadata = $stmt->columnCount();
48+
for ($i = 0; $i < $numCol; $i++) {
49+
$metadata = $stmt->getColumnMeta($i);
50+
var_dump($metadata);
51+
}
52+
53+
createProc($conn, $procName, "@id int, @val varchar(10) OUTPUT", "SELECT @val = name FROM $tableName WHERE id = @id");
54+
55+
$value = '';
56+
$tsql = "{CALL [$procName] (?, ?)}";
57+
$stmt = $conn->prepare($tsql);
58+
$stmt->bindParam(1, $id, PDO::PARAM_INT);
59+
$stmt->bindParam(2, $value, PDO::PARAM_STR, 10);
60+
$stmt->execute();
61+
$numCol = $metadata = $stmt->columnCount();
62+
echo "Number of columns after PROCEDURE: $numCol\n";
63+
echo "Value returned: $value\n";
64+
checkMetaData($stmt);
65+
66+
$query = "DELETE FROM $tableName WHERE name = 'updated'";
67+
$stmt = $conn->query($query);
68+
$numCol = $metadata = $stmt->columnCount();
69+
echo "Number of columns after DELETE: $numCol\n";
70+
checkMetaData($stmt);
71+
} catch (PDOException $e) {
72+
echo $e->getMessage() . PHP_EOL;
73+
}
74+
75+
dropTable($conn, $tableName);
76+
dropProc($conn, $procName);
77+
78+
unset($stmt);
79+
unset($conn);
80+
81+
?>
82+
--EXPECT--
83+
Number of columns after UPDATE: 0
84+
array(8) {
85+
["flags"]=>
86+
int(0)
87+
["sqlsrv:decl_type"]=>
88+
string(3) "int"
89+
["native_type"]=>
90+
string(6) "string"
91+
["table"]=>
92+
string(0) ""
93+
["pdo_type"]=>
94+
int(2)
95+
["name"]=>
96+
string(2) "id"
97+
["len"]=>
98+
int(10)
99+
["precision"]=>
100+
int(0)
101+
}
102+
array(8) {
103+
["flags"]=>
104+
int(0)
105+
["sqlsrv:decl_type"]=>
106+
string(7) "varchar"
107+
["native_type"]=>
108+
string(6) "string"
109+
["table"]=>
110+
string(0) ""
111+
["pdo_type"]=>
112+
int(2)
113+
["name"]=>
114+
string(4) "name"
115+
["len"]=>
116+
int(10)
117+
["precision"]=>
118+
int(0)
119+
}
120+
Number of columns after PROCEDURE: 0
121+
Value returned: updated
122+
Number of columns after DELETE: 0

test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt

+1-2
Original file line numberDiff line numberDiff line change
@@ -220,5 +220,4 @@ array(7) {
220220

221221
Warning: PDOStatement::getColumnMeta(): SQLSTATE[42P10]: Invalid column reference: column number must be non-negative in %s on line %x
222222
bool(false)
223-
224-
Fatal error: pdo_sqlsrv_stmt_get_col_meta: invalid column number. in %s on line %x
223+
bool(false)

test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt

+1-2
Original file line numberDiff line numberDiff line change
@@ -259,5 +259,4 @@ array(7) {
259259

260260
Warning: PDOStatement::getColumnMeta(): SQLSTATE[42P10]: Invalid column reference: column number must be non-negative in %s on line %x
261261
bool(false)
262-
263-
Fatal error: pdo_sqlsrv_stmt_get_col_meta: invalid column number. in %s on line %x
262+
bool(false)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
--TEST--
2+
GitHub issue #937 - getting metadata will not fail after an UPDATE / DELETE statement
3+
--DESCRIPTION--
4+
Verifies that sqlsrv_field_metadata will return an empty array after processing an
5+
UPDATE / DELETE query that returns no fields.
6+
--ENV--
7+
PHPT_EXEC=true
8+
--SKIPIF--
9+
<?php require('skipif.inc'); ?>
10+
--FILE--
11+
<?php
12+
require_once('MsCommon.inc');
13+
14+
$conn = connect();
15+
if ($conn === false) {
16+
die(print_r(sqlsrv_errors(), true));
17+
}
18+
19+
$tableName = 'srvTestTable_938';
20+
$procName = 'srvTestProc_938';
21+
22+
dropTable($conn, $tableName);
23+
dropProc($conn, $procName);
24+
25+
// Create the test table
26+
$tsql = "CREATE TABLE $tableName([id] [int] NOT NULL,
27+
[dummyColumn] [varchar](10) NOT NULL
28+
)";
29+
$stmt = sqlsrv_query($conn, $tsql);
30+
if (!$stmt) {
31+
fatalError("Failed to create table $tableName\n");
32+
}
33+
34+
$id = 5;
35+
$tsql = "INSERT INTO $tableName VALUES ($id, 'dummy')";
36+
$stmt = sqlsrv_query($conn, $tsql);
37+
if (!$stmt) {
38+
fatalError("Failed to insert a row into table $tableName\n");
39+
}
40+
41+
$tsql = "SELECT * FROM $tableName";
42+
$stmt = sqlsrv_query($conn, $tsql);
43+
$fieldmeta = sqlsrv_field_metadata($stmt);
44+
var_dump($fieldmeta);
45+
46+
$tsql = "UPDATE $tableName SET dummyColumn = 'updated' WHERE id = $id";
47+
$stmt = sqlsrv_prepare($conn, $tsql);
48+
sqlsrv_execute($stmt);
49+
$fieldmeta = sqlsrv_field_metadata($stmt);
50+
var_dump($fieldmeta);
51+
52+
createProc($conn, $procName, "@id int, @val varchar(10) OUTPUT", "SELECT @val = dummyColumn FROM $tableName WHERE id = @id");
53+
54+
$value = '';
55+
$tsql = "{CALL [$procName] (?, ?)}";
56+
$stmt = sqlsrv_prepare(
57+
$conn,
58+
$tsql,
59+
array(array($id, SQLSRV_PARAM_IN),
60+
array(&$value, SQLSRV_PARAM_OUT)
61+
)
62+
);
63+
$result = sqlsrv_execute($stmt);
64+
if (!$result) {
65+
fatalError("Failed to invoke stored procedure $procName\n");
66+
}
67+
68+
echo "The value returned: $value\n";
69+
70+
$fieldmeta = sqlsrv_field_metadata($stmt);
71+
var_dump($fieldmeta);
72+
73+
$options = array("Scrollable" => "buffered");
74+
$tsql = "DELETE FROM $tableName WHERE dummyColumn = 'updated'";
75+
$stmt = sqlsrv_query($conn, $tsql, array(), $options);
76+
$fieldmeta = sqlsrv_field_metadata($stmt);
77+
var_dump($fieldmeta);
78+
79+
dropTable($conn, $tableName);
80+
dropProc($conn, $procName);
81+
82+
sqlsrv_free_stmt($stmt);
83+
sqlsrv_close($conn);
84+
85+
?>
86+
--EXPECT--
87+
array(2) {
88+
[0]=>
89+
array(6) {
90+
["Name"]=>
91+
string(2) "id"
92+
["Type"]=>
93+
int(4)
94+
["Size"]=>
95+
NULL
96+
["Precision"]=>
97+
int(10)
98+
["Scale"]=>
99+
NULL
100+
["Nullable"]=>
101+
int(0)
102+
}
103+
[1]=>
104+
array(6) {
105+
["Name"]=>
106+
string(11) "dummyColumn"
107+
["Type"]=>
108+
int(12)
109+
["Size"]=>
110+
int(10)
111+
["Precision"]=>
112+
NULL
113+
["Scale"]=>
114+
NULL
115+
["Nullable"]=>
116+
int(0)
117+
}
118+
}
119+
array(0) {
120+
}
121+
The value returned: updated
122+
array(0) {
123+
}
124+
array(0) {
125+
}

0 commit comments

Comments
 (0)