Passed
Pull Request — master (#397)
by Wilmer
02:36
created

CommonCommandTest::testCreateView()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 21
c 1
b 0
f 0
nc 4
nop 0
dl 0
loc 30
rs 9.584
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Tests\Common;
6
7
use Throwable;
8
use Yiisoft\Db\Driver\PDO\ConnectionPDOInterface;
9
use Yiisoft\Db\Exception\Exception;
10
use Yiisoft\Db\Exception\IntegrityException;
11
use Yiisoft\Db\Exception\InvalidCallException;
12
use Yiisoft\Db\Query\Data\DataReaderInterface;
13
use Yiisoft\Db\Query\Query;
14
use Yiisoft\Db\Schema\Schema;
15
use Yiisoft\Db\Tests\AbstractCommandTest;
16
use Yiisoft\Db\Tests\Support\Assert;
17
18
use function setlocale;
19
20
abstract class CommonCommandTest extends AbstractCommandTest
21
{
22
    public function testAlterTable(): void
23
    {
24
        $db = $this->getConnection();
25
26
        $command = $db->createCommand();
27
        $schema = $db->getSchema();
28
29
        if ($schema->getTableSchema('testAlterTable', true) !== null) {
30
            $command->dropTable('testAlterTable')->execute();
31
        }
32
33
        $command->createTable('testAlterTable', ['id' => Schema::TYPE_PK, 'bar' => Schema::TYPE_INTEGER])->execute();
34
        $command->insert('testAlterTable', ['bar' => 1])->execute();
35
        $command->alterColumn('testAlterTable', 'bar', Schema::TYPE_STRING)->execute();
36
        $command->insert('testAlterTable', ['bar' => 'hello'])->execute();
37
        $records = $command->setSql(
38
            <<<SQL
39
            SELECT [[id]], [[bar]] FROM {{testAlterTable}}
40
            SQL
41
        )->queryAll();
42
43
        $this->assertSame([['id' => 1, 'bar' => 1], ['id' => 2, 'bar' => 'hello']], $records);
44
    }
45
46
    /**
47
     * Make sure that `{{something}}` in values will not be encoded.
48
     *
49
     * {@see https://github.com/yiisoft/yii2/issues/11242}
50
     */
51
    public function testBatchInsertSQL(
52
        string $table,
53
        array $columns,
54
        array $values,
55
        string $expected,
56
        array $expectedParams = [],
57
        int $insertedRow = 1,
58
        string $fixture = 'type'
59
    ): void {
60
        $db = $this->getConnection($fixture);
61
62
        $command = $db->createCommand();
63
        $command->batchInsert($table, $columns, $values);
64
        $command->prepare(false);
65
66
        $this->assertSame($expected, $command->getSql());
67
        $this->assertSame($expectedParams, $command->getParams());
68
69
        $command->execute();
70
71
        $this->assertEquals($insertedRow, (new Query($db))->from($table)->count());
72
    }
73
74
    /**
75
     * Test batch insert with different data types.
76
     *
77
     * Ensure double is inserted with `.` decimal separator.
78
     *
79
     * @link https://github.com/yiisoft/yii2/issues/6526
80
     */
81
    public function testBatchInsertDataTypesLocale(): void
82
    {
83
        $locale = setlocale(LC_NUMERIC, 0);
84
85
        if ($locale === false) {
86
            $this->markTestSkipped('Your platform does not support locales.');
87
        }
88
89
        $db = $this->getConnection('type');
90
91
        $command = $db->createCommand();
92
93
        try {
94
            /* This one sets decimal mark to comma sign */
95
            setlocale(LC_NUMERIC, 'ru_RU.utf8');
96
97
            $cols = ['int_col', 'char_col', 'float_col', 'bool_col'];
98
            $data = [[1, 'A', 9.735, true], [2, 'B', -2.123, false], [3, 'C', 2.123, false]];
99
100
            /* clear data in "type" table */
101
            $command->delete('type')->execute();
102
103
            /* change, for point oracle. */
104
            if ($db->getName() === 'oci') {
105
                $command->setSql(
106
                    <<<SQL
107
                    ALTER SESSION SET NLS_NUMERIC_CHARACTERS='.,'
108
                    SQL
109
                )->execute();
110
            }
111
112
            /* batch insert on "type" table */
113
            $command->batchInsert('type', $cols, $data)->execute();
114
            $data = $command->setSql(
115
                <<<SQL
116
                SELECT [[int_col]], [[char_col]], [[float_col]], [[bool_col]] FROM {{type}} WHERE [[int_col]] IN (1,2,3) ORDER BY [[int_col]]
117
                SQL
118
            )->queryAll();
119
120
            $this->assertCount(3, $data);
121
            $this->assertEquals(1, $data[0]['int_col']);
122
            $this->assertEquals(2, $data[1]['int_col']);
123
            $this->assertEquals(3, $data[2]['int_col']);
124
125
            /* rtrim because Postgres padds the column with whitespace */
126
            $this->assertSame('A', rtrim($data[0]['char_col']));
127
            $this->assertSame('B', rtrim($data[1]['char_col']));
128
            $this->assertSame('C', rtrim($data[2]['char_col']));
129
            $this->assertEquals(9.735, $data[0]['float_col']);
130
            $this->assertEquals(-2.123, $data[1]['float_col']);
131
            $this->assertEquals(2.123, $data[2]['float_col']);
132
            $this->assertEquals(1, $data[0]['bool_col']);
133
            Assert::isOneOf($data[1]['bool_col'], ['0', false]);
134
            Assert::isOneOf($data[2]['bool_col'], ['0', false]);
135
        } catch (Exception | Throwable $e) {
136
            setlocale(LC_NUMERIC, $locale);
137
138
            throw $e;
139
        }
140
141
        setlocale(LC_NUMERIC, $locale);
142
    }
143
144
    public function testBatchInsertFailsOld(): void
145
    {
146
        $db = $this->getConnection('customer');
147
148
        $command = $db->createCommand();
149
        $command->batchInsert(
150
            '{{customer}}',
151
            ['email', 'name', 'address'],
152
            [['[email protected]', 'test_name', 'test_address']],
153
        );
154
155
        $this->assertSame(1, $command->execute());
156
157
        $result = (new Query($db))
158
            ->select(['email', 'name', 'address'])
159
            ->from('{{customer}}')
160
            ->where(['=', '[[email]]', '[email protected]'])
161
            ->one();
162
163
        $this->assertCount(3, $result);
164
        $this->assertSame(['email' => '[email protected]', 'name' => 'test_name', 'address' => 'test_address'], $result);
165
    }
166
167
    public function testBatchInsertWithManyData(): void
168
    {
169
        $db = $this->getConnection('customer');
170
171
        $values = [];
172
        $attemptsInsertRows = 200;
173
        $command = $db->createCommand();
174
175
        for ($i = 0; $i < $attemptsInsertRows; $i++) {
176
            $values[$i] = ['t' . $i . '@any.com', 't' . $i, 't' . $i . ' address'];
177
        }
178
179
        $command->batchInsert('{{customer}}', ['email', 'name', 'address'], $values);
180
181
        $this->assertSame($attemptsInsertRows, $command->execute());
182
183
        $insertedRowsCount = (new Query($db))->from('{{customer}}')->count();
184
185
        $this->assertGreaterThanOrEqual($attemptsInsertRows, $insertedRowsCount);
186
    }
187
188
    public function testBatchInsertWithYield(): void
189
    {
190
        $db = $this->getConnection('customer');
191
192
        $rows = (
193
            static function () {
194
                yield ['[email protected]', 'test name', 'test address'];
195
            }
196
        )();
197
        $command = $db->createCommand();
198
        $command->batchInsert('{{customer}}', ['email', 'name', 'address'], $rows);
199
200
        $this->assertSame(1, $command->execute());
201
    }
202
203
    public function testCreateTable(): void
204
    {
205
        $db = $this->getConnection();
206
207
        $command = $db->createCommand();
208
        $schema = $db->getSchema();
209
210
        if ($schema->getTableSchema('testCreateTable', true) !== null) {
211
            $command->dropTable('testCreateTable')->execute();
212
        }
213
214
        $command->createTable('testCreateTable', ['id' => Schema::TYPE_PK, 'bar' => Schema::TYPE_INTEGER])->execute();
215
        $command->insert('testCreateTable', ['bar' => 1])->execute();
216
        $records = $command->setSql(
217
            <<<SQL
218
            SELECT [[id]], [[bar]] FROM {{testCreateTable}};
219
            SQL
220
        )->queryAll();
221
222
        $this->assertEquals([['id' => 1, 'bar' => 1]], $records);
223
    }
224
225
    public function testCreateView(): void
226
    {
227
        $db = $this->getConnection();
228
229
        $command = $db->createCommand();
230
        $schema = $db->getSchema();
231
        $subQuery = (new Query($db))->select('bar')->from('testCreateViewTable')->where(['>', 'bar', '5']);
232
233
        if ($schema->getTableSchema('testCreateView') !== null) {
234
            $command->dropView('testCreateView')->execute();
235
        }
236
237
        if ($schema->getTableSchema('testCreateViewTable')) {
238
            $command->dropTable('testCreateViewTable')->execute();
239
        }
240
241
        $command->createTable(
242
            'testCreateViewTable',
243
            ['id' => Schema::TYPE_PK, 'bar' => Schema::TYPE_INTEGER],
244
        )->execute();
245
        $command->insert('testCreateViewTable', ['bar' => 1])->execute();
246
        $command->insert('testCreateViewTable', ['bar' => 6])->execute();
247
        $command->createView('testCreateView', $subQuery)->execute();
248
        $records = $command->setSql(
249
            <<<SQL
250
            SELECT [[bar]] FROM {{testCreateView}};
251
            SQL
252
        )->queryAll();
253
254
        $this->assertEquals([['bar' => 6]], $records);
255
    }
256
257
    public function testDataReaderRewindException(): void
258
    {
259
        $db = $this->getConnection('customer');
260
261
        $this->expectException(InvalidCallException::class);
262
        $this->expectExceptionMessage('DataReader cannot rewind. It is a forward-only reader.');
263
264
        $command = $db->createCommand();
265
        $reader = $command->setSql(
266
            <<<SQL
267
            SELECT * FROM {{customer}}
268
            SQL
269
        )->query();
270
        $reader->next();
271
        $reader->rewind();
272
    }
273
274
    public function testDropView(): void
275
    {
276
        $db = $this->getConnection('animal');
277
278
        /* since it already exists in the fixtures */
279
        $viewName = 'animal_view';
280
281
        $schema = $db->getSchema();
282
283
        $this->assertNotNull($schema->getTableSchema($viewName));
284
285
        $db->createCommand()->dropView($viewName)->execute();
286
287
        $this->assertNull($schema->getTableSchema($viewName));
288
    }
289
290
    public function testExecute(): void
291
    {
292
        $db = $this->getConnection('customer');
293
294
        $command = $db->createCommand();
295
        $command->setSql(
296
            <<<SQL
297
            INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES ('[email protected]', 'user4', 'address4')
298
            SQL
299
        );
300
301
        $this->assertSame(1, $command->execute());
302
303
        $command = $command->setSql(
304
            <<<SQL
305
            SELECT COUNT(*) FROM {{customer}} WHERE [[name]] = 'user4'
306
            SQL
307
        );
308
309
        $this->assertEquals(1, $command->queryScalar());
310
311
        $command->setSql('bad SQL');
312
        $message = match ($db->getName()) {
313
            'sqlite' => 'SQLSTATE[HY000]: General error: 1 near "bad": syntax error',
314
            'sqlsrv' => 'SQLSTATE[42000]: [Microsoft]',
315
        };
316
317
        $this->expectException(Exception::class);
318
        $this->expectExceptionMessage($message);
319
320
        $command->execute();
321
    }
322
323
    public function testIntegrityViolation(): void
324
    {
325
        $db = $this->getConnection('profile');
326
327
        $this->expectException(IntegrityException::class);
328
329
        $command = $db->createCommand(
330
            <<<SQL
331
            INSERT INTO {{profile}}([[id]], [[description]]) VALUES (123, 'duplicate')
332
            SQL
333
        );
334
        $command->execute();
335
        $command->execute();
336
    }
337
338
    public function testLastInsertId(): void
339
    {
340
        $db = $this->getConnection('profile');
341
342
        $command = $db->createCommand();
343
344
        $sql = <<<SQL
345
        INSERT INTO {{profile}}([[description]]) VALUES ('non duplicate')
346
        SQL;
347
        $command->setSql($sql)->execute();
348
349
        $this->assertSame('3', $db->getLastInsertID());
350
    }
351
352
    public function testNoTablenameReplacement(): void
353
    {
354
        $db = $this->getConnection('customer');
355
356
        $command = $db->createCommand();
357
        $command->insert(
358
            '{{customer}}',
359
            ['name' => 'Some {{weird}} name', 'email' => '[email protected]', 'address' => 'Some {{%weird}} address']
360
        )->execute();
361
362
        if ($db->getName() === 'pgsql') {
363
            $customerId = $db->getLastInsertID('public.customer_id_seq');
364
        } else {
365
            $customerId = $db->getLastInsertID();
366
        }
367
368
        $customer = $command->setSql(
369
            <<<SQL
370
            SELECT [[name]], [[email]], [[address]] FROM {{customer}} WHERE [[id]]=:id
371
            SQL,
372
        )->bindValues([':id' => $customerId])->queryOne();
373
374
        $this->assertIsArray($customer);
375
        $this->assertSame('Some {{weird}} name', $customer['name']);
376
        $this->assertSame('Some {{%weird}} address', $customer['address']);
377
378
        $command->update(
379
            '{{customer}}',
380
            ['name' => 'Some {{updated}} name', 'address' => 'Some {{%updated}} address'],
381
            ['id' => $customerId]
382
        )->execute();
383
        $customer = $command->setSql(
384
            <<<SQL
385
            SELECT [[name]], [[email]], [[address]] FROM {{customer}} WHERE [[id]] = :id
386
            SQL
387
        )->bindValues([':id' => $customerId])->queryOne();
388
389
        $this->assertIsArray($customer);
390
        $this->assertSame('Some {{updated}} name', $customer['name']);
391
        $this->assertSame('Some {{%updated}} address', $customer['address']);
392
    }
393
394
    public function testQuery(): void
395
    {
396
        $db = $this->getConnection('customer');
397
398
        $command = $db->createCommand();
399
400
        $command->setSql(
401
            <<<SQL
402
            SELECT * FROM {{customer}}
403
            SQL
404
        );
405
406
        $this->assertNull($command->getPdoStatement());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $command->getPdoStatement() targeting Yiisoft\Db\Driver\PDO\Co...dPDO::getPdoStatement() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
407
408
        $reader = $command->query();
409
410
        // check tests that the reader is a valid iterator
411
        if ($db->getName() !== 'sqlite' && $db->getName() !== 'pgsql' && $db->getName() !== 'sqlsrv') {
412
            $this->assertEquals(3, $reader->count());
413
        }
414
415
        $this->assertNotNull($command->getPdoStatement());
416
        $this->assertInstanceOf(DataReaderInterface::class, $reader);
417
        $this->assertIsInt($reader->count());
418
419
        foreach ($reader as $row) {
420
            $this->assertIsArray($row);
421
            $this->assertCount(6, $row);
422
        }
423
424
        $command = $db->createCommand('bad SQL');
425
426
        $this->expectException(Exception::class);
427
428
        $command->query();
429
    }
430
431
    public function testQueryAll(): void
432
    {
433
        $db = $this->getConnection('customer');
434
435
        $command = $db->createCommand();
436
437
        $command->setSql(
438
            <<<SQL
439
            SELECT * FROM {{customer}}
440
            SQL
441
        );
442
        $rows = $command->queryAll();
443
444
        $this->assertIsArray($rows);
445
        $this->assertCount(3, $rows);
446
        $this->assertIsArray($rows[0]);
447
        $this->assertCount(6, $rows[0]);
448
449
        $command->setSql('bad SQL');
450
451
        $this->expectException(Exception::class);
452
453
        $command->queryAll();
454
        $command->setSql(
455
            <<<SQL
456
            SELECT * FROM {{customer}} where id = 100
457
            SQL
458
        );
459
        $rows = $command->queryAll();
460
461
        $this->assertIsArray($rows);
462
        $this->assertCount(0, $rows);
463
        $this->assertSame([], $rows);
464
    }
465
466
    public function testQueryOne(): void
467
    {
468
        $db = $this->getConnection('customer');
469
470
        $command = $db->createCommand();
471
        $sql = <<<SQL
472
        SELECT * FROM {{customer}} ORDER BY [[id]]
473
        SQL;
474
        $row = $command->setSql($sql)->queryOne();
475
476
        $this->assertIsArray($row);
477
        $this->assertEquals(1, $row['id']);
478
        $this->assertEquals('user1', $row['name']);
479
480
        $command->setSql($sql)->prepare();
481
        $row = $command->queryOne();
482
483
        $this->assertIsArray($row);
484
        $this->assertEquals(1, $row['id']);
485
        $this->assertEquals('user1', $row['name']);
486
487
        $sql = <<<SQL
488
        SELECT * FROM {{customer}} WHERE [[id]] = 10
489
        SQL;
490
        $command = $command->setSql($sql);
491
492
        $this->assertNull($command->queryOne());
493
    }
494
495
    public function testQueryCache(): void
496
    {
497
        $db = $this->getConnection('customer');
498
499
        $query = (new Query($db))->select(['name'])->from('customer');
500
        $command = $db->createCommand();
501
        $update = $command->setSql(
502
            <<<SQL
503
            UPDATE {{customer}} SET [[name]] = :name WHERE [[id]] = :id
504
            SQL
505
        );
506
507
        $this->assertSame('user1', $query->where(['id' => 1])->scalar(), 'Asserting initial value');
508
509
        /* No cache */
510
        $update->bindValues([':id' => 1, ':name' => 'user11'])->execute();
511
512
        $this->assertSame(
513
            'user11',
514
            $query->where(['id' => 1])->scalar(),
515
            'Query reflects DB changes when caching is disabled',
516
        );
517
518
        /* Connection cache */
519
        $db->cache(
520
            static function (ConnectionPDOInterface $db) use ($query, $update) {
521
                self::assertSame('user2', $query->where(['id' => 2])->scalar(), 'Asserting initial value for user #2');
522
523
                $update->bindValues([':id' => 2, ':name' => 'user22'])->execute();
524
525
                self::assertSame(
526
                    'user2',
527
                    $query->where(['id' => 2])->scalar(),
528
                    'Query does NOT reflect DB changes when wrapped in connection caching',
529
                );
530
531
                $db->noCache(
532
                    static function () use ($query) {
533
                        self::assertSame(
534
                            'user22',
535
                            $query->where(['id' => 2])->scalar(),
536
                            'Query reflects DB changes when wrapped in connection caching and noCache simultaneously',
537
                        );
538
                    }
539
                );
540
541
                self::assertSame(
542
                    'user2',
543
                    $query->where(['id' => 2])->scalar(),
544
                    'Cache does not get changes after getting newer data from DB in noCache block.',
545
                );
546
            },
547
            10,
548
        );
549
550
        $db->queryCacheEnable(false);
551
552
        $db->cache(
553
            static function () use ($query, $update) {
554
                self::assertSame(
555
                    'user22',
556
                    $query->where(['id' => 2])->scalar(),
557
                    'When cache is disabled for the whole connection, Query inside cache block does not get cached',
558
                );
559
560
                $update->bindValues([':id' => 2, ':name' => 'user2'])->execute();
561
562
                self::assertSame('user2', $query->where(['id' => 2])->scalar());
563
            },
564
            10,
565
        );
566
567
        $db->queryCacheEnable(true);
568
        $query->cache();
569
570
        $this->assertSame('user11', $query->where(['id' => 1])->scalar());
571
572
        $update->bindValues([':id' => 1, ':name' => 'user1'])->execute();
573
574
        $this->assertSame(
575
            'user11',
576
            $query->where(['id' => 1])->scalar(),
577
            'When both Connection and Query have cache enabled, we get cached value',
578
        );
579
        $this->assertSame(
580
            'user1',
581
            $query->noCache()->where(['id' => 1])->scalar(),
582
            'When Query has disabled cache, we get actual data',
583
        );
584
585
        $db->cache(
586
            static function () use ($query) {
587
                self::assertSame('user1', $query->noCache()->where(['id' => 1])->scalar());
588
                self::assertSame('user11', $query->cache()->where(['id' => 1])->scalar());
589
            },
590
            10,
591
        );
592
    }
593
594
    public function testQueryColumn(): void
595
    {
596
        $db = $this->getConnection('customer');
597
598
        $command = $db->createCommand();
599
        $command->setSql(
600
            <<<SQL
601
            SELECT * FROM {{customer}}
602
            SQL
603
        );
604
        $rows = $command->queryColumn();
605
606
        $this->assertIsArray($rows);
607
        $this->assertCount(3, $rows);
608
        $this->assertEquals('1', $rows[0]);
609
610
        $command->setSql('bad SQL');
611
612
        $this->expectException(Exception::class);
613
614
        $command->queryColumn();
615
        $command->setSql(
616
            <<<SQL
617
            SELECT * FROM {{customer}} where id = 100
618
            SQL
619
        );
620
        $rows = $command->queryColumn();
621
622
        $this->assertIsArray($rows);
623
        $this->assertCount(0, $rows);
624
        $this->assertSame([], $rows);
625
    }
626
627
    public function testQueryScalar(): void
628
    {
629
        $db = $this->getConnection('customer');
630
631
        $command = $db->createCommand();
632
        $sql = <<<SQL
633
        SELECT * FROM {{customer}} ORDER BY [[id]]
634
        SQL;
635
636
        $this->assertEquals(1, $command->setSql($sql)->queryScalar());
637
638
        $sql = <<<SQL
639
        SELECT [[id]] FROM {{customer}} ORDER BY [[id]]
640
        SQL;
641
        $command->setSql($sql)->prepare();
642
643
        $this->assertEquals(1, $command->queryScalar());
644
645
        $command = $command->setSql(
646
            <<<SQL
647
            SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10
648
            SQL
649
        );
650
651
        $this->assertFalse($command->queryScalar());
652
    }
653
654
    public function testRetryHandler(): void
655
    {
656
        $db = $this->getConnection('profile');
657
658
        $command = $db->createCommand();
659
660
        $this->assertNull($db->getTransaction());
661
662
        $command->setSql(
663
            <<<SQL
664
            INSERT INTO {{profile}}([[description]]) VALUES('command retry')
665
            SQL
666
        )->execute();
667
668
        $this->assertNull($db->getTransaction());
669
        $this->assertEquals(
670
            1,
671
            $command->setSql(
672
                <<<SQL
673
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'command retry'
674
                SQL
675
            )->queryScalar()
676
        );
677
678
        $attempts = null;
679
        $hitHandler = false;
680
        $hitCatch = false;
681
        $command->setSql(
682
            <<<SQL
683
            INSERT INTO {{profile}}([[id]], [[description]]) VALUES(1, 'command retry')
684
            SQL
685
        );
686
687
        Assert::invokeMethod(
688
            $command,
689
            'setRetryHandler',
690
            [static function ($exception, $attempt) use (&$attempts, &$hitHandler) {
691
                $attempts = $attempt;
692
                $hitHandler = true;
693
694
                return $attempt <= 2;
695
            }]
696
        );
697
698
        try {
699
            $command->execute();
700
        } catch (Exception $e) {
701
            $hitCatch = true;
702
703
            $this->assertInstanceOf(IntegrityException::class, $e);
704
        }
705
706
        $this->assertNull($db->getTransaction());
707
        $this->assertSame(3, $attempts);
708
        $this->assertTrue($hitHandler);
709
        $this->assertTrue($hitCatch);
710
    }
711
712
    public function testTransaction(): void
713
    {
714
        $db = $this->getConnection('profile');
715
716
        $this->assertNull($db->getTransaction());
717
718
        $command = $db->createCommand();
719
        $command = $command->setSql(
720
            <<<SQL
721
            INSERT INTO {{profile}}([[description]]) VALUES('command transaction')
722
            SQL
723
        );
724
725
        Assert::invokeMethod($command, 'requireTransaction');
726
727
        $command->execute();
728
729
        $this->assertNull($db->getTransaction());
730
        $this->assertEquals(
731
            1,
732
            $command->setSql(
733
                <<<SQL
734
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'command transaction'
735
                SQL
736
            )->queryScalar(),
737
        );
738
    }
739
740
    public function testUpdate(
741
        string $table,
742
        array $columns,
743
        array|string $conditions,
744
        array $params,
745
        string $expected
746
    ): void {
747
        $db = $this->getConnection();
748
749
        $command = $db->createCommand();
750
        $sql = $command->update($table, $columns, $conditions, $params)->getSql();
751
752
        $this->assertSame($expected, $sql);
753
    }
754
755
    public function testUpsert(array $firstData, array $secondData): void
756
    {
757
        $db = $this->getConnection('customer', 't_upsert');
758
759
        if (version_compare($db->getServerVersion(), '3.8.3', '<')) {
760
            $this->markTestSkipped('SQLite < 3.8.3 does not support "WITH" keyword.');
761
        }
762
763
        $this->assertEquals(0, $db->createCommand('SELECT COUNT(*) FROM {{T_upsert}}')->queryScalar());
764
765
        $this->performAndCompareUpsertResult($db, $firstData);
766
767
        $this->assertEquals(1, $db->createCommand('SELECT COUNT(*) FROM {{T_upsert}}')->queryScalar());
768
769
        $this->performAndCompareUpsertResult($db, $secondData);
770
    }
771
}
772