Skip to content

Commit 29cc04b

Browse files
bert-wtaylorotwell
andauthored
[13.x] PDO Fetch modes (#55394)
* fetchargs * add fetchArgs() function * fetchargs * add fetchArgs() function * add afterquery callbacks * fix typo * flip afterquerycallback * fix expectations * add expectations * add expectations * add expectations * add raw expression test * rename to fetchUsing * style * Remove test from PR #54396 * Revert most Query\Builder changes * remove DB::raw test * Revert QueryBuilder pluck tests * Add base tests for $query->fetchUsing() * style * formatting * Update Builder.php * Fix filled columns before calling pluck * query db compatibility * remove unrelated test --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 4de9631 commit 29cc04b

9 files changed

+164
-102
lines changed

src/Illuminate/Database/Connection.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -388,11 +388,12 @@ public function selectFromWriteConnection($query, $bindings = [])
388388
* @param string $query
389389
* @param array $bindings
390390
* @param bool $useReadPdo
391+
* @param array $fetchUsing
391392
* @return array
392393
*/
393-
public function select($query, $bindings = [], $useReadPdo = true)
394+
public function select($query, $bindings = [], $useReadPdo = true, array $fetchUsing = [])
394395
{
395-
return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
396+
return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchUsing) {
396397
if ($this->pretending()) {
397398
return [];
398399
}
@@ -408,7 +409,7 @@ public function select($query, $bindings = [], $useReadPdo = true)
408409

409410
$statement->execute();
410411

411-
return $statement->fetchAll();
412+
return $statement->fetchAll(...$fetchUsing);
412413
});
413414
}
414415

@@ -418,11 +419,12 @@ public function select($query, $bindings = [], $useReadPdo = true)
418419
* @param string $query
419420
* @param array $bindings
420421
* @param bool $useReadPdo
422+
* @param array $fetchUsing
421423
* @return array
422424
*/
423-
public function selectResultSets($query, $bindings = [], $useReadPdo = true)
425+
public function selectResultSets($query, $bindings = [], $useReadPdo = true, array $fetchUsing = [])
424426
{
425-
return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
427+
return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchUsing) {
426428
if ($this->pretending()) {
427429
return [];
428430
}
@@ -438,7 +440,7 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true)
438440
$sets = [];
439441

440442
do {
441-
$sets[] = $statement->fetchAll();
443+
$sets[] = $statement->fetchAll(...$fetchUsing);
442444
} while ($statement->nextRowset());
443445

444446
return $sets;
@@ -451,9 +453,10 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true)
451453
* @param string $query
452454
* @param array $bindings
453455
* @param bool $useReadPdo
456+
* @param array $fetchUsing
454457
* @return \Generator<int, \stdClass>
455458
*/
456-
public function cursor($query, $bindings = [], $useReadPdo = true)
459+
public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchUsing = [])
457460
{
458461
$statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
459462
if ($this->pretending()) {
@@ -478,7 +481,7 @@ public function cursor($query, $bindings = [], $useReadPdo = true)
478481
return $statement;
479482
});
480483

481-
while ($record = $statement->fetch()) {
484+
while ($record = $statement->fetch(...$fetchUsing)) {
482485
yield $record;
483486
}
484487
}

src/Illuminate/Database/ConnectionInterface.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,21 @@ public function scalar($query, $bindings = [], $useReadPdo = true);
5151
* @param string $query
5252
* @param array $bindings
5353
* @param bool $useReadPdo
54+
* @param array $fetchUsing
5455
* @return array
5556
*/
56-
public function select($query, $bindings = [], $useReadPdo = true);
57+
public function select($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []);
5758

5859
/**
5960
* Run a select statement against the database and returns a generator.
6061
*
6162
* @param string $query
6263
* @param array $bindings
6364
* @param bool $useReadPdo
65+
* @param array $fetchUsing
6466
* @return \Generator
6567
*/
66-
public function cursor($query, $bindings = [], $useReadPdo = true);
68+
public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []);
6769

6870
/**
6971
* Run an insert statement against the database.

src/Illuminate/Database/Query/Builder.php

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ class Builder implements BuilderContract
249249
*/
250250
public $useWritePdo = false;
251251

252+
/**
253+
* The custom arguments for the PDOStatement::fetchAll / fetch functions.
254+
*
255+
* @var array
256+
*/
257+
public array $fetchUsing = [];
258+
252259
/**
253260
* Create a new query builder instance.
254261
*/
@@ -3088,9 +3095,13 @@ public function soleValue($column)
30883095
*/
30893096
public function get($columns = ['*'])
30903097
{
3091-
$items = new Collection($this->onceWithColumns(Arr::wrap($columns), function () {
3092-
return $this->processor->processSelect($this, $this->runSelect());
3093-
}));
3098+
$original = $this->columns;
3099+
3100+
$this->columns ??= Arr::wrap($columns);
3101+
3102+
$items = new Collection($this->processor->processSelect($this, $this->runSelect()));
3103+
3104+
$this->columns = $original;
30943105

30953106
return $this->applyAfterQueryCallbacks(
30963107
isset($this->groupLimit) ? $this->withoutGroupLimitKeys($items) : $items
@@ -3105,7 +3116,7 @@ public function get($columns = ['*'])
31053116
protected function runSelect()
31063117
{
31073118
return $this->connection->select(
3108-
$this->toSql(), $this->getBindings(), ! $this->useWritePdo
3119+
$this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing
31093120
);
31103121
}
31113122

@@ -3324,7 +3335,7 @@ public function cursor()
33243335

33253336
return (new LazyCollection(function () {
33263337
yield from $this->connection->cursor(
3327-
$this->toSql(), $this->getBindings(), ! $this->useWritePdo
3338+
$this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing
33283339
);
33293340
}))->map(function ($item) {
33303341
return $this->applyAfterQueryCallbacks(new Collection([$item]))->first();
@@ -3660,30 +3671,6 @@ protected function setAggregate($function, $columns)
36603671
return $this;
36613672
}
36623673

3663-
/**
3664-
* Execute the given callback while selecting the given columns.
3665-
*
3666-
* After running the callback, the columns are reset to the original value.
3667-
*
3668-
* @param array $columns
3669-
* @param callable $callback
3670-
* @return mixed
3671-
*/
3672-
protected function onceWithColumns($columns, $callback)
3673-
{
3674-
$original = $this->columns;
3675-
3676-
if (is_null($original)) {
3677-
$this->columns = $columns;
3678-
}
3679-
3680-
$result = $callback();
3681-
3682-
$this->columns = $original;
3683-
3684-
return $result;
3685-
}
3686-
36873674
/**
36883675
* Insert new records into the database.
36893676
*
@@ -4297,6 +4284,19 @@ public function useWritePdo()
42974284
return $this;
42984285
}
42994286

4287+
/**
4288+
* Specify arguments for the PDOStatement::fetchAll / fetch functions.
4289+
*
4290+
* @param mixed ...$fetchUsing
4291+
* @return $this
4292+
*/
4293+
public function fetchUsing(...$fetchUsing)
4294+
{
4295+
$this->fetchUsing = $fetchUsing;
4296+
4297+
return $this;
4298+
}
4299+
43004300
/**
43014301
* Determine if the value is a query builder instance or a Closure.
43024302
*

tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public function testCreateOrFirstMethodAssociatesExistingRelated(): void
8484

8585
$source->getConnection()
8686
->expects('select')
87-
->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true)
87+
->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, [])
8888
->andReturn([[
8989
'id' => 456,
9090
'attr' => 'foo',
@@ -128,6 +128,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAlreadyAssociated
128128
'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1',
129129
[123, 'foo'],
130130
true,
131+
[],
131132
)
132133
->andReturn([[
133134
'id' => 456,
@@ -176,7 +177,7 @@ public function testCreateOrFirstMethodRetrievesExistingRelatedAssociatedJustNow
176177

177178
$source->getConnection()
178179
->expects('select')
179-
->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true)
180+
->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, [])
180181
->andReturn([[
181182
'id' => 456,
182183
'attr' => 'foo',
@@ -199,6 +200,7 @@ public function testCreateOrFirstMethodRetrievesExistingRelatedAssociatedJustNow
199200
'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1',
200201
[123, 'foo'],
201202
false,
203+
[],
202204
)
203205
->andReturn([[
204206
'id' => 456,
@@ -243,6 +245,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAndAssociatesIt()
243245
'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1',
244246
[123, 'foo'],
245247
true,
248+
[],
246249
)
247250
->andReturn([]);
248251

@@ -252,6 +255,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAndAssociatesIt()
252255
'select * from "related_table" where ("attr" = ?) limit 1',
253256
['foo'],
254257
true,
258+
[],
255259
)
256260
->andReturn([[
257261
'id' => 456,
@@ -326,6 +330,7 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore
326330
'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1',
327331
[123, 'foo'],
328332
true,
333+
[],
329334
)
330335
->andReturn([]);
331336

@@ -335,6 +340,7 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore
335340
'select * from "related_table" where ("attr" = ?) limit 1',
336341
['foo'],
337342
true,
343+
[],
338344
)
339345
->andReturn([]);
340346

tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void
6666

6767
$model->getConnection()
6868
->expects('select')
69-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false)
69+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, [])
7070
->andReturn([[
7171
'id' => 123,
7272
'attr' => 'foo',
@@ -95,7 +95,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void
9595

9696
$model->getConnection()
9797
->expects('select')
98-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
98+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
9999
->andReturn([[
100100
'id' => 123,
101101
'attr' => 'foo',
@@ -124,7 +124,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void
124124

125125
$model->getConnection()
126126
->expects('select')
127-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
127+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
128128
->andReturn([]);
129129

130130
$model->getConnection()->expects('insert')->with(
@@ -152,7 +152,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void
152152

153153
$model->getConnection()
154154
->expects('select')
155-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
155+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
156156
->andReturn([]);
157157

158158
$sql = 'insert into "table" ("attr", "val", "updated_at", "created_at") values (?, ?, ?, ?)';
@@ -165,7 +165,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void
165165

166166
$model->getConnection()
167167
->expects('select')
168-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false)
168+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, [])
169169
->andReturn([[
170170
'id' => 123,
171171
'attr' => 'foo',
@@ -194,7 +194,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void
194194

195195
$model->getConnection()
196196
->expects('select')
197-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
197+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
198198
->andReturn([[
199199
'id' => 123,
200200
'attr' => 'foo',
@@ -231,7 +231,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void
231231

232232
$model->getConnection()
233233
->expects('select')
234-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
234+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
235235
->andReturn([]);
236236

237237
$model->getConnection()->expects('insert')->with(
@@ -259,7 +259,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void
259259

260260
$model->getConnection()
261261
->expects('select')
262-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
262+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
263263
->andReturn([]);
264264

265265
$sql = 'insert into "table" ("attr", "val", "updated_at", "created_at") values (?, ?, ?, ?)';
@@ -272,7 +272,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void
272272

273273
$model->getConnection()
274274
->expects('select')
275-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false)
275+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, [])
276276
->andReturn([[
277277
'id' => 123,
278278
'attr' => 'foo',
@@ -309,7 +309,7 @@ public function testIncrementOrCreateMethodIncrementsExistingRecord(): void
309309

310310
$model->getConnection()
311311
->expects('select')
312-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
312+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
313313
->andReturn([[
314314
'id' => 123,
315315
'attr' => 'foo',
@@ -351,7 +351,7 @@ public function testIncrementOrCreateMethodCreatesNewRecord(): void
351351

352352
$model->getConnection()
353353
->expects('select')
354-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
354+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
355355
->andReturn([]);
356356

357357
$model->getConnection()->expects('insert')->with(
@@ -379,7 +379,7 @@ public function testIncrementOrCreateMethodIncrementParametersArePassed(): void
379379

380380
$model->getConnection()
381381
->expects('select')
382-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
382+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
383383
->andReturn([[
384384
'id' => 123,
385385
'attr' => 'foo',
@@ -423,7 +423,7 @@ public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void
423423

424424
$model->getConnection()
425425
->expects('select')
426-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true)
426+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, [])
427427
->andReturn([]);
428428

429429
$sql = 'insert into "table" ("attr", "count", "updated_at", "created_at") values (?, ?, ?, ?)';
@@ -436,7 +436,7 @@ public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void
436436

437437
$model->getConnection()
438438
->expects('select')
439-
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false)
439+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, [])
440440
->andReturn([[
441441
'id' => 123,
442442
'attr' => 'foo',

0 commit comments

Comments
 (0)