|
| 1 | +--TEST-- |
| 2 | +GitHub issue 1466 - Re-executing prepared statement with multiple result sets |
| 3 | +--DESCRIPTION-- |
| 4 | +Verifies that re-executing a prepared statement returning multiple result sets |
| 5 | +does not cause a fatal error or return corrupted data. |
| 6 | +--SKIPIF-- |
| 7 | +<?php require('skipif.inc'); ?> |
| 8 | +--FILE-- |
| 9 | +<?php |
| 10 | +require_once('MsCommon.inc'); |
| 11 | + |
| 12 | +$conn = connect(); |
| 13 | +if ($conn === false) { |
| 14 | + fatalError("Could not connect.\n"); |
| 15 | +} |
| 16 | + |
| 17 | +$sql = " |
| 18 | + SET NOCOUNT ON; |
| 19 | + DECLARE @id INT = ?; |
| 20 | + -- Result set 1 |
| 21 | + SELECT @id AS r1col1, 2 AS r1col2, 3 AS r1col3, N'Test' AS r1col4 |
| 22 | + WHERE @id IN (2, 3); |
| 23 | + -- Result set 2 |
| 24 | + SELECT @id AS r2col1, N'/test.txt' AS r2col2, N'text/plain' AS r2col3 |
| 25 | + WHERE @id IN (2, 3); |
| 26 | +"; |
| 27 | + |
| 28 | +$stmt = sqlsrv_prepare($conn, $sql, array(&$id)); |
| 29 | +if ($stmt === false) { |
| 30 | + fatalError("sqlsrv_prepare failed.\n"); |
| 31 | +} |
| 32 | + |
| 33 | +$idList = array(2, 1, 3); |
| 34 | +foreach ($idList as $id) { |
| 35 | + if (!sqlsrv_execute($stmt)) { |
| 36 | + fatalError("sqlsrv_execute failed for id=$id.\n"); |
| 37 | + } |
| 38 | + |
| 39 | + // Fetch result set 1 |
| 40 | + $rowCount1 = 0; |
| 41 | + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { |
| 42 | + if (!array_key_exists('r1col1', $row)) { |
| 43 | + fatalError("Result set 1 row missing expected column 'r1col1'.\n"); |
| 44 | + } |
| 45 | + if ($row['r1col1'] != $id) { |
| 46 | + fatalError("Result set 1 r1col1 expected $id, got {$row['r1col1']}.\n"); |
| 47 | + } |
| 48 | + $rowCount1++; |
| 49 | + } |
| 50 | + |
| 51 | + // Move to result set 2 |
| 52 | + $nextResult = sqlsrv_next_result($stmt); |
| 53 | + if ($nextResult === false) { |
| 54 | + fatalError("sqlsrv_next_result failed for id=$id.\n"); |
| 55 | + } |
| 56 | + |
| 57 | + $rowCount2 = 0; |
| 58 | + if ($nextResult !== null) { |
| 59 | + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { |
| 60 | + if (!array_key_exists('r2col1', $row)) { |
| 61 | + fatalError("Result set 2 row missing expected column 'r2col1'.\n"); |
| 62 | + } |
| 63 | + if ($row['r2col1'] != $id) { |
| 64 | + fatalError("Result set 2 r2col1 expected $id, got {$row['r2col1']}.\n"); |
| 65 | + } |
| 66 | + $rowCount2++; |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + // Verify row counts based on input |
| 71 | + if ($id == 1) { |
| 72 | + if ($rowCount1 !== 0 || $rowCount2 !== 0) { |
| 73 | + fatalError("Expected empty result sets for id=1.\n"); |
| 74 | + } |
| 75 | + } else { |
| 76 | + if ($rowCount1 !== 1 || $rowCount2 !== 1) { |
| 77 | + fatalError("Expected one row per result set for id=$id.\n"); |
| 78 | + } |
| 79 | + } |
| 80 | +} |
| 81 | +sqlsrv_free_stmt($stmt); |
| 82 | +echo "Test 1 passed: re-execute with next_result\n"; |
| 83 | + |
| 84 | +// Test 2: Re-execute without consuming all result sets (auto-flush) |
| 85 | +// This exercises the flush loop in sqlsrv_execute that calls |
| 86 | +// core_sqlsrv_next_result before the new execute. |
| 87 | +$id = 2; |
| 88 | +$stmt2 = sqlsrv_prepare($conn, $sql, array(&$id)); |
| 89 | +if ($stmt2 === false) { |
| 90 | + fatalError("sqlsrv_prepare failed for test 2.\n"); |
| 91 | +} |
| 92 | +sqlsrv_execute($stmt2); |
| 93 | +$row = sqlsrv_fetch_array($stmt2, SQLSRV_FETCH_ASSOC); |
| 94 | +// Do NOT call sqlsrv_next_result -- just re-execute immediately |
| 95 | +$id = 3; |
| 96 | +if (!sqlsrv_execute($stmt2)) { |
| 97 | + fatalError("sqlsrv_execute failed for test 2 re-execute.\n"); |
| 98 | +} |
| 99 | +$row = sqlsrv_fetch_array($stmt2, SQLSRV_FETCH_ASSOC); |
| 100 | +if (!$row || !array_key_exists('r1col1', $row) || $row['r1col1'] != 3) { |
| 101 | + fatalError("Test 2 failed: unexpected result after re-execute without next_result.\n"); |
| 102 | +} |
| 103 | +sqlsrv_free_stmt($stmt2); |
| 104 | +echo "Test 2 passed: re-execute without next_result\n"; |
| 105 | + |
| 106 | +// Test 3: Re-execute when both result sets have the same number of columns |
| 107 | +// but different column names. |
| 108 | +$sql3 = " |
| 109 | + SET NOCOUNT ON; |
| 110 | + DECLARE @v INT = ?; |
| 111 | + SELECT @v AS col_a, N'first' AS col_b; |
| 112 | + SELECT @v AS col_x, N'second' AS col_y; |
| 113 | +"; |
| 114 | +$val = 0; |
| 115 | +$stmt3 = sqlsrv_prepare($conn, $sql3, array(&$val)); |
| 116 | +if ($stmt3 === false) { |
| 117 | + fatalError("sqlsrv_prepare failed for test 3.\n"); |
| 118 | +} |
| 119 | +for ($val = 1; $val <= 3; $val++) { |
| 120 | + if (!sqlsrv_execute($stmt3)) { |
| 121 | + fatalError("sqlsrv_execute failed for test 3, val=$val.\n"); |
| 122 | + } |
| 123 | + $row1 = sqlsrv_fetch_array($stmt3, SQLSRV_FETCH_ASSOC); |
| 124 | + if (!$row1 || !array_key_exists('col_a', $row1) || $row1['col_a'] != $val) { |
| 125 | + fatalError("Test 3 val=$val: RS1 unexpected result.\n"); |
| 126 | + } |
| 127 | + $next = sqlsrv_next_result($stmt3); |
| 128 | + if ($next === false) { |
| 129 | + fatalError("sqlsrv_next_result failed for test 3, val=$val.\n"); |
| 130 | + } |
| 131 | + $row2 = sqlsrv_fetch_array($stmt3, SQLSRV_FETCH_ASSOC); |
| 132 | + if (!$row2 || !array_key_exists('col_x', $row2) || $row2['col_x'] != $val) { |
| 133 | + fatalError("Test 3 val=$val: RS2 unexpected result.\n"); |
| 134 | + } |
| 135 | +} |
| 136 | +sqlsrv_free_stmt($stmt3); |
| 137 | +echo "Test 3 passed: same column count, different names\n"; |
| 138 | + |
| 139 | +sqlsrv_close($conn); |
| 140 | +echo "Done\n"; |
| 141 | +?> |
| 142 | +--EXPECT-- |
| 143 | +Test 1 passed: re-execute with next_result |
| 144 | +Test 2 passed: re-execute without next_result |
| 145 | +Test 3 passed: same column count, different names |
| 146 | +Done |
0 commit comments