Skip to content

Commit 11eefe1

Browse files
committed
Restore stream offsets with subsequent execute
Driver statement instances needs to maintain resources offsets for streams passed to bindValue after the first call to execute. Modified array compare in testBindValueResetsStream to explicitly read the stream and read remaining stream content instead of checking current pointer to conclude the test. Fixed for PDO, SQLite3, SQLSrv, OCI8
1 parent 950dc7f commit 11eefe1

File tree

6 files changed

+41
-42
lines changed

6 files changed

+41
-42
lines changed

src/Driver/OCI8/Statement.php

+6-7
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING): bool
7474
}
7575

7676
if ($type === ParameterType::BINARY || $type === ParameterType::LARGE_OBJECT) {
77-
$this->trackParamResource($value);
77+
$this->trackParamResource($param, $value);
7878
}
7979

8080
return $this->bindParam($param, $value, $type);
@@ -195,16 +195,17 @@ public function execute($params = null): ResultInterface
195195
* Track a binary parameter reference at binding time. These
196196
* are cached for later analysis by the getResourceOffsets.
197197
*
198-
* @param mixed $resource
198+
* @param int|string $param
199+
* @param mixed $resource
199200
*/
200-
private function trackParamResource($resource): void
201+
private function trackParamResource($param, $resource): void
201202
{
202203
if (! is_resource($resource)) {
203204
return;
204205
}
205206

206-
$this->paramResources ??= [];
207-
$this->paramResources[] = $resource;
207+
$this->paramResources ??= [];
208+
$this->paramResources[$param] = $resource;
208209
}
209210

210211
/**
@@ -256,7 +257,5 @@ private function restoreResourceOffsets(?array $resourceOffsets): void
256257
foreach ($resourceOffsets as $index => $offset) {
257258
fseek($this->paramResources[$index], $offset, SEEK_SET);
258259
}
259-
260-
$this->paramResources = null;
261260
}
262261
}

src/Driver/PDO/SQLSrv/Statement.php

+6-7
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING): bool
115115
}
116116

117117
if ($type === ParameterType::LARGE_OBJECT || $type === ParameterType::BINARY) {
118-
$this->trackParamResource($value);
118+
$this->trackParamResource($param, $value);
119119
}
120120

121121
return $this->bindParam($param, $value, $type);
@@ -140,16 +140,17 @@ public function execute($params = null): Result
140140
* Track a binary parameter reference at binding time. These
141141
* are cached for later analysis by the getResourceOffsets.
142142
*
143-
* @param mixed $resource
143+
* @param int|string $param
144+
* @param mixed $resource
144145
*/
145-
private function trackParamResource($resource): void
146+
private function trackParamResource($param, $resource): void
146147
{
147148
if (! is_resource($resource)) {
148149
return;
149150
}
150151

151-
$this->paramResources ??= [];
152-
$this->paramResources[] = $resource;
152+
$this->paramResources ??= [];
153+
$this->paramResources[$param] = $resource;
153154
}
154155

155156
/**
@@ -201,7 +202,5 @@ private function restoreResourceOffsets(?array $resourceOffsets): void
201202
foreach ($resourceOffsets as $index => $offset) {
202203
fseek($this->paramResources[$index], $offset, SEEK_SET);
203204
}
204-
205-
$this->paramResources = null;
206205
}
207206
}

src/Driver/PDO/Statement.php

+6-7
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING)
5454

5555
$pdoType = ParameterTypeMap::convertParamType($type);
5656
if ($pdoType === PDO::PARAM_LOB) {
57-
$this->trackParamResource($value);
57+
$this->trackParamResource($param, $value);
5858
}
5959

6060
try {
@@ -157,16 +157,17 @@ public function execute($params = null): ResultInterface
157157
* Track a binary parameter reference at binding time. These
158158
* are cached for later analysis by the getResourceOffsets.
159159
*
160-
* @param mixed $resource
160+
* @param int|string $param
161+
* @param mixed $resource
161162
*/
162-
private function trackParamResource($resource): void
163+
private function trackParamResource($param, $resource): void
163164
{
164165
if (! is_resource($resource)) {
165166
return;
166167
}
167168

168-
$this->paramResources ??= [];
169-
$this->paramResources[] = $resource;
169+
$this->paramResources ??= [];
170+
$this->paramResources[$param] = $resource;
170171
}
171172

172173
/**
@@ -218,7 +219,5 @@ private function restoreResourceOffsets(?array $resourceOffsets): void
218219
foreach ($resourceOffsets as $index => $offset) {
219220
fseek($this->paramResources[$index], $offset, SEEK_SET);
220221
}
221-
222-
$this->paramResources = null;
223222
}
224223
}

src/Driver/SQLSrv/Statement.php

+6-7
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING): bool
110110
}
111111

112112
if ($type === ParameterType::LARGE_OBJECT || $type === ParameterType::BINARY) {
113-
$this->trackParamResource($value);
113+
$this->trackParamResource($param, $value);
114114
}
115115

116116
$this->variables[$param] = $value;
@@ -248,16 +248,17 @@ private function prepare()
248248
* Track a binary parameter reference at binding time. These
249249
* are cached for later analysis by the getResourceOffsets.
250250
*
251-
* @param mixed $resource
251+
* @param int|string $param
252+
* @param mixed $resource
252253
*/
253-
private function trackParamResource($resource): void
254+
private function trackParamResource($param, $resource): void
254255
{
255256
if (! is_resource($resource)) {
256257
return;
257258
}
258259

259-
$this->paramResources ??= [];
260-
$this->paramResources[] = $resource;
260+
$this->paramResources ??= [];
261+
$this->paramResources[$param] = $resource;
261262
}
262263

263264
/**
@@ -309,7 +310,5 @@ private function restoreResourceOffsets(?array $resourceOffsets): void
309310
foreach ($resourceOffsets as $index => $offset) {
310311
fseek($this->paramResources[$index], $offset, SEEK_SET);
311312
}
312-
313-
$this->paramResources = null;
314313
}
315314
}

src/Driver/SQLite3/Statement.php

+6-7
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING): bool
6868

6969
$sqliteType = $this->convertParamType($type);
7070
if ($sqliteType === SQLITE3_BLOB) {
71-
$this->trackParamResource($value);
71+
$this->trackParamResource($param, $value);
7272
}
7373

7474
return $this->statement->bindValue($param, $value, $sqliteType);
@@ -156,16 +156,17 @@ private function convertParamType(int $type): int
156156
* Track a binary parameter reference at binding time. These
157157
* are cached for later analysis by the getResourceOffsets.
158158
*
159-
* @param mixed $resource
159+
* @param int|string $param
160+
* @param mixed $resource
160161
*/
161-
private function trackParamResource($resource): void
162+
private function trackParamResource($param, $resource): void
162163
{
163164
if (! is_resource($resource)) {
164165
return;
165166
}
166167

167-
$this->paramResources ??= [];
168-
$this->paramResources[] = $resource;
168+
$this->paramResources ??= [];
169+
$this->paramResources[$param] = $resource;
169170
}
170171

171172
/**
@@ -217,7 +218,5 @@ private function restoreResourceOffsets(?array $resourceOffsets): void
217218
foreach ($resourceOffsets as $index => $offset) {
218219
fseek($this->paramResources[$index], $offset, SEEK_SET);
219220
}
220-
221-
$this->paramResources = null;
222221
}
223222
}

tests/Functional/BlobTest.php

+11-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use function assert;
1414
use function fopen;
1515
use function fseek;
16-
use function ftell;
1716
use function fwrite;
1817
use function str_repeat;
1918
use function stream_get_contents;
@@ -229,10 +228,12 @@ public function testBindValueResetsStream(): void
229228
$stmt->bindValue(1, 3, ParameterType::INTEGER);
230229
$stmt->executeStatement();
231230

232-
$rows = array_map(
233-
function (array $row): array {
231+
$blobType = Type::getType(Types::BLOB);
232+
$platform = $this->connection->getDatabasePlatform();
233+
$rows = array_map(
234+
function (array $row) use ($blobType, $platform): array {
234235
$row[0] = $this->connection->convertToPHPValue($row[0], Types::INTEGER);
235-
$row[1] = $this->connection->convertToPHPValue($row[1], Types::STRING);
236+
$row[1] = stream_get_contents($blobType->convertToPHPValue($row[1], $platform));
236237

237238
return $row;
238239
},
@@ -246,9 +247,12 @@ function (array $row): array {
246247
// for this test is that reading the stream to extract the value moves the stream
247248
// pointer, so that using the stream with a new statement (and hence a new call
248249
// to bindValue and a new initial call to execute*) causes a different value to
249-
// be read from the stream results. All that we have learned so far is that bindValue
250-
// reuses the value obtained during the first execution of the statement.
251-
self::assertEquals(2, ftell($stream), 'Resource parameter should be reset to position before execute.');
250+
// be read from the stream results. Currently, we have verified one of two things:
251+
// either the stream is reset with each execute, or that bindValue reuses the value
252+
// obtained during the first execution of the statement. Which of these holds is not
253+
// consistent across implementations. For example, the default pdo_sqlite test target
254+
// does not reread the stream on subsequent executes, but pdo_pgsql does.
255+
self::assertEquals('test', stream_get_contents($stream));
252256
}
253257

254258
private function assertBlobContains(string $text): void

0 commit comments

Comments
 (0)