Passed
Pull Request — master (#397)
by Wilmer
12:50 queued 09:36
created

CommonCommandTest::testsInsertQueryAsColumnValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 44
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 35
nc 2
nop 0
dl 0
loc 44
rs 9.36
c 0
b 0
f 0
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\InvalidArgumentException;
12
use Yiisoft\Db\Exception\InvalidCallException;
13
use Yiisoft\Db\Expression\Expression;
14
use Yiisoft\Db\Query\Data\DataReaderInterface;
15
use Yiisoft\Db\Query\Query;
16
use Yiisoft\Db\Schema\Schema;
17
use Yiisoft\Db\Tests\AbstractCommandTest;
18
use Yiisoft\Db\Tests\Support\Assert;
19
use Yiisoft\Db\Tests\Support\DbHelper;
20
21
use function setlocale;
22
23
abstract class CommonCommandTest extends AbstractCommandTest
24
{
25
    public function testAddCheck(): void
26
    {
27
        $db = $this->getConnection();
28
29
        $command = $db->createCommand();
30
        $schema = $db->getSchema();
31
32
        if ($schema->getTableSchema('{{test_ck}}') !== null) {
33
            $command->dropTable('{{test_ck}}')->execute();
34
        }
35
36
        $command->createTable('{{test_ck}}', ['int1' => 'integer'])->execute();
37
38
        $this->assertEmpty($schema->getTableChecks('{{test_ck}}', true));
39
40
        $command->addCheck('{{test_ck_constraint}}', '{{test_ck}}', 'int1 > 1')->execute();
41
42
        $this->assertMatchesRegularExpression(
43
            '/^.*int1.*>.*1.*$/',
44
            $schema->getTableChecks('{{test_ck}}', true)[0]->getExpression()
45
        );
46
    }
47
48
    public function testAddColumn(): void
49
    {
50
        $db = $this->getConnection('customer');
51
52
        $command = $db->createCommand();
53
        $command->addColumn('{{customer}}', 'city', Schema::TYPE_STRING)->execute();
54
55
        $this->assertTrue($db->getTableSchema('{{customer}}')->getColumn('city') !== null);
56
        $this->assertSame(Schema::TYPE_STRING, $db->getTableSchema('{{customer}}')->getColumn('city')->getType());
57
    }
58
59
    public function testAddCommentOnColumn(): void
60
    {
61
        $db = $this->getConnection('customer');
62
63
        $command = $db->createCommand();
64
        $command->addCommentOnColumn('{{customer}}', 'id', 'Primary key.')->execute();
65
        $commentOnColumn = DbHelper::getCommmentsFromColumn('customer', 'id', $db);
66
67
        $this->assertSame(['value' => 'Primary key.'], $commentOnColumn);
68
    }
69
70
    public function testAddCommentOnTable(): void
71
    {
72
        $db = $this->getConnection('customer');
73
74
        $command = $db->createCommand();
75
        $command->addCommentOnTable('{{customer}}', 'Customer table.')->execute();
76
        $commentOnTable = DbHelper::getCommmentsFromTable('customer', $db);
77
78
        $this->assertSame(['value' => 'Customer table.'], $commentOnTable);
79
    }
80
81
    public function testAddDefaultValue()
82
    {
83
        $db = $this->getConnection();
84
85
        $command = $db->createCommand();
86
        $schema = $db->getSchema();
87
88
        if ($schema->getTableSchema('{{test_def}}') !== null) {
89
            $command->dropTable('{{test_def}}')->execute();
90
        }
91
92
        $command->createTable('{{test_def}}', ['int1' => Schema::TYPE_INTEGER])->execute();
93
94
        $this->assertEmpty($schema->getTableDefaultValues('{{test_def}}', true));
95
96
        $command->addDefaultValue('{{test_def_constraint}}', '{{test_def}}', 'int1', 41)->execute();
97
98
        $this->assertMatchesRegularExpression(
99
            '/^.*41.*$/',
100
            $schema->getTableDefaultValues('{{test_def}}', true)[0]->getValue(),
101
        );
102
    }
103
104
    /**
105
     * @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::addForeignKey()
106
     */
107
    public function testAddForeignKey(
108
        string $name,
109
        string $tableName,
110
        array|string $column1,
111
        array|string $column2
112
    ): void {
113
        $db = $this->getConnection();
114
115
        $command = $db->createCommand();
116
        $schema = $db->getSchema();
117
118
        if ($schema->getTableSchema($tableName) !== null) {
119
            $command->dropTable($tableName)->execute();
120
        }
121
122
        $command->createTable(
123
            $tableName,
124
            [
125
                'int1' => 'integer not null unique',
126
                'int2' => 'integer not null unique',
127
                'int3' => 'integer not null unique',
128
                'int4' => 'integer not null unique',
129
                'unique ([[int1]], [[int2]])',
130
                'unique ([[int3]], [[int4]])',
131
            ],
132
        )->execute();
133
134
        $this->assertEmpty($schema->getTableForeignKeys($tableName, true));
135
136
        $command->addForeignKey($name, $tableName, $column1, $tableName, $column2)->execute();
137
138
        $this->assertSame($name, $schema->getTableForeignKeys($tableName, true)[0]->getName());
139
140
        if (is_string($column1)) {
0 ignored issues
show
introduced by
The condition is_string($column1) is always false.
Loading history...
141
            $column1 = [$column1];
142
        }
143
144
        $this->assertSame($column1, $schema->getTableForeignKeys($tableName, true)[0]->getColumnNames());
145
146
        if (is_string($column2)) {
0 ignored issues
show
introduced by
The condition is_string($column2) is always false.
Loading history...
147
            $column2 = [$column2];
148
        }
149
150
        $this->assertSame($column2, $schema->getTableForeignKeys($tableName, true)[0]->getForeignColumnNames());
151
    }
152
153
    /**
154
     * @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::addPrimaryKey()
155
     */
156
    public function testAddPrimaryKey(string $name, string $tableName, array|string $column): void
157
    {
158
        $db = $this->getConnection();
159
160
        $command = $db->createCommand();
161
        $schema = $db->getSchema();
162
163
        if ($schema->getTableSchema($tableName) !== null) {
164
            $command->dropTable($tableName)->execute();
165
        }
166
167
        $command->createTable($tableName, ['int1' => 'integer not null', 'int2' => 'integer not null'])->execute();
168
169
        $this->assertNull($schema->getTablePrimaryKey($tableName, true));
170
171
        $db->createCommand()->addPrimaryKey($name, $tableName, $column)->execute();
172
173
        if (is_string($column)) {
0 ignored issues
show
introduced by
The condition is_string($column) is always false.
Loading history...
174
            $column = [$column];
175
        }
176
177
        $this->assertSame($column, $schema->getTablePrimaryKey($tableName, true)->getColumnNames());
178
    }
179
180
    /**
181
     * @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::addUnique()
182
     */
183
    public function testAddUnique(string $name, string $tableName, array|string $column): void
184
    {
185
        $db = $this->getConnection();
186
187
        $command = $db->createCommand();
188
        $schema = $db->getSchema();
189
190
        if ($schema->getTableSchema($tableName) !== null) {
191
            $command->dropTable($tableName)->execute();
192
        }
193
194
        $command->createTable($tableName, ['int1' => 'integer not null', 'int2' => 'integer not null'])->execute();
195
196
        $this->assertEmpty($schema->getTableUniques($tableName, true));
197
198
        $command->addUnique($name, $tableName, $column)->execute();
199
200
        if (is_string($column)) {
0 ignored issues
show
introduced by
The condition is_string($column) is always false.
Loading history...
201
            $column = [$column];
202
        }
203
204
        $this->assertSame($column, $schema->getTableUniques($tableName, true)[0]->getColumnNames());
205
    }
206
207
    public function testAlterColumn(): void
208
    {
209
        $db = $this->getConnection('customer');
210
211
        $command = $db->createCommand();
212
        $command->alterColumn('{{customer}}', 'email', 'ntext')->execute();
213
        $schema = $db->getSchema();
214
        $columns = $schema->getTableSchema('{{customer}}')->getColumns();
215
216
        $this->assertArrayHasKey('email', $columns);
217
        $this->assertSame('ntext', $columns['email']->getDbType());
218
    }
219
220
    /**
221
     * Make sure that `{{something}}` in values will not be encoded.
222
     *
223
     * @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::batchInsert()
224
     *
225
     * {@see https://github.com/yiisoft/yii2/issues/11242}
226
     */
227
    public function testBatchInsert(
228
        string $table,
229
        array $columns,
230
        array $values,
231
        string $expected,
232
        array $expectedParams = [],
233
        int $insertedRow = 1
234
    ): void {
235
        $db = $this->getConnection('type');
236
237
        $command = $db->createCommand();
238
        $command->batchInsert($table, $columns, $values);
239
        $command->prepare(false);
240
241
        $this->assertSame($expected, $command->getSql());
242
        $this->assertSame($expectedParams, $command->getParams());
243
244
        $command->execute();
245
246
        $this->assertEquals($insertedRow, (new Query($db))->from($table)->count());
247
    }
248
249
    /**
250
     * Test batch insert with different data types.
251
     *
252
     * Ensure double is inserted with `.` decimal separator.
253
     *
254
     * @link https://github.com/yiisoft/yii2/issues/6526
255
     */
256
    public function testBatchInsertDataTypesLocale(): void
257
    {
258
        $locale = setlocale(LC_NUMERIC, 0);
259
260
        if ($locale === false) {
261
            $this->markTestSkipped('Your platform does not support locales.');
262
        }
263
264
        $db = $this->getConnection('type');
265
266
        $command = $db->createCommand();
267
268
        try {
269
            /* This one sets decimal mark to comma sign */
270
            setlocale(LC_NUMERIC, 'ru_RU.utf8');
271
272
            $cols = ['int_col', 'char_col', 'float_col', 'bool_col'];
273
            $data = [[1, 'A', 9.735, true], [2, 'B', -2.123, false], [3, 'C', 2.123, false]];
274
275
            /* clear data in "type" table */
276
            $command->delete('{{type}}')->execute();
277
278
            /* change, for point oracle. */
279
            if ($db->getName() === 'oci') {
280
                $command->setSql(
281
                    <<<SQL
282
                    ALTER SESSION SET NLS_NUMERIC_CHARACTERS='.,'
283
                    SQL
284
                )->execute();
285
            }
286
287
            /* batch insert on "type" table */
288
            $command->batchInsert('{{type}}', $cols, $data)->execute();
289
            $data = $command->setSql(
290
                <<<SQL
291
                SELECT [[int_col]], [[char_col]], [[float_col]], [[bool_col]] FROM {{type}} WHERE [[int_col]] IN (1,2,3) ORDER BY [[int_col]]
292
                SQL
293
            )->queryAll();
294
295
            $this->assertCount(3, $data);
296
            $this->assertEquals(1, $data[0]['int_col']);
297
            $this->assertEquals(2, $data[1]['int_col']);
298
            $this->assertEquals(3, $data[2]['int_col']);
299
300
            /* rtrim because Postgres padds the column with whitespace */
301
            $this->assertSame('A', rtrim($data[0]['char_col']));
302
            $this->assertSame('B', rtrim($data[1]['char_col']));
303
            $this->assertSame('C', rtrim($data[2]['char_col']));
304
            $this->assertEquals(9.735, $data[0]['float_col']);
305
            $this->assertEquals(-2.123, $data[1]['float_col']);
306
            $this->assertEquals(2.123, $data[2]['float_col']);
307
            $this->assertEquals(1, $data[0]['bool_col']);
308
            Assert::isOneOf($data[1]['bool_col'], ['0', false]);
309
            Assert::isOneOf($data[2]['bool_col'], ['0', false]);
310
        } catch (Exception | Throwable $e) {
311
            setlocale(LC_NUMERIC, $locale);
312
313
            throw $e;
314
        }
315
316
        setlocale(LC_NUMERIC, $locale);
317
    }
318
319
    public function testBatchInsertFailsOld(): void
320
    {
321
        $db = $this->getConnection('customer');
322
323
        $command = $db->createCommand();
324
        $command->batchInsert(
325
            '{{customer}}',
326
            ['email', 'name', 'address'],
327
            [['[email protected]', 'test_name', 'test_address']],
328
        );
329
330
        $this->assertSame(1, $command->execute());
331
332
        $result = (new Query($db))
333
            ->select(['email', 'name', 'address'])
334
            ->from('{{customer}}')
335
            ->where(['=', '[[email]]', '[email protected]'])
336
            ->one();
337
338
        $this->assertCount(3, $result);
339
        $this->assertSame(['email' => '[email protected]', 'name' => 'test_name', 'address' => 'test_address'], $result);
340
    }
341
342
    public function testBatchInsertWithManyData(): void
343
    {
344
        $db = $this->getConnection('customer');
345
346
        $values = [];
347
        $attemptsInsertRows = 200;
348
        $command = $db->createCommand();
349
350
        for ($i = 0; $i < $attemptsInsertRows; $i++) {
351
            $values[$i] = ['t' . $i . '@any.com', 't' . $i, 't' . $i . ' address'];
352
        }
353
354
        $command->batchInsert('{{customer}}', ['email', 'name', 'address'], $values);
355
356
        $this->assertSame($attemptsInsertRows, $command->execute());
357
358
        $insertedRowsCount = (new Query($db))->from('{{customer}}')->count();
359
360
        $this->assertGreaterThanOrEqual($attemptsInsertRows, $insertedRowsCount);
361
    }
362
363
    public function testBatchInsertWithYield(): void
364
    {
365
        $db = $this->getConnection('customer');
366
367
        $rows = (
368
            static function () {
369
                yield ['[email protected]', 'test name', 'test address'];
370
            }
371
        )();
372
        $command = $db->createCommand();
373
        $command->batchInsert('{{customer}}', ['email', 'name', 'address'], $rows);
374
375
        $this->assertSame(1, $command->execute());
376
    }
377
378
    /**
379
     * @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::createIndex()
380
     */
381
    public function testCreateIndex(string $name, string $tableName, array|string $column): void
382
    {
383
        $db = $this->getConnection();
384
385
        $command = $db->createCommand();
386
        $schema = $db->getSchema();
387
388
        if ($schema->getTableSchema($tableName) !== null) {
389
            $command->dropTable($tableName)->execute();
390
        }
391
        $command->createTable($tableName, ['int1' => 'integer not null', 'int2' => 'integer not null'])->execute();
392
393
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
394
395
        $command->createIndex($name, $tableName, $column)->execute();
396
397
        if (is_string($column)) {
0 ignored issues
show
introduced by
The condition is_string($column) is always false.
Loading history...
398
            $column = [$column];
399
        }
400
401
        $this->assertSame($column, $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
402
        $this->assertFalse($schema->getTableIndexes($tableName, true)[0]->isUnique());
403
    }
404
405
    public function testCreateTable(): void
406
    {
407
        $db = $this->getConnection();
408
409
        $command = $db->createCommand();
410
        $schema = $db->getSchema();
411
412
        if ($schema->getTableSchema('{{testCreateTable}}', true) !== null) {
413
            $command->dropTable('{{testCreateTable}}')->execute();
414
        }
415
416
        $command->createTable(
417
            '{{testCreateTable}}',
418
            ['id' => Schema::TYPE_PK, 'bar' => Schema::TYPE_INTEGER],
419
        )->execute();
420
        $command->insert('{{testCreateTable}}', ['bar' => 1])->execute();
421
        $records = $command->setSql(
422
            <<<SQL
423
            SELECT [[id]], [[bar]] FROM {{testCreateTable}};
424
            SQL
425
        )->queryAll();
426
427
        $this->assertEquals([['id' => 1, 'bar' => 1]], $records);
428
    }
429
430
    public function testCreateView(): void
431
    {
432
        $db = $this->getConnection();
433
434
        $command = $db->createCommand();
435
        $schema = $db->getSchema();
436
        $subQuery = (new Query($db))->select('[[bar]]')->from('{{testCreateViewTable}}')->where(['>', 'bar', '5']);
437
438
        if ($schema->getTableSchema('{{testCreateView}}') !== null) {
439
            $command->dropView('{{testCreateView}}')->execute();
440
        }
441
442
        if ($schema->getTableSchema('{{testCreateViewTable}}')) {
443
            $command->dropTable('{{testCreateViewTable}}')->execute();
444
        }
445
446
        $command->createTable(
447
            '{{testCreateViewTable}}',
448
            ['id' => Schema::TYPE_PK, 'bar' => Schema::TYPE_INTEGER],
449
        )->execute();
450
        $command->insert('{{testCreateViewTable}}', ['bar' => 1])->execute();
451
        $command->insert('{{testCreateViewTable}}', ['bar' => 6])->execute();
452
        $command->createView('{{testCreateView}}', $subQuery)->execute();
453
        $records = $command->setSql(
454
            <<<SQL
455
            SELECT [[bar]] FROM {{testCreateView}};
456
            SQL
457
        )->queryAll();
458
459
        $this->assertEquals([['bar' => 6]], $records);
460
    }
461
462
    public function testDataReaderRewindException(): void
463
    {
464
        $db = $this->getConnection('customer');
465
466
        $this->expectException(InvalidCallException::class);
467
        $this->expectExceptionMessage('DataReader cannot rewind. It is a forward-only reader.');
468
469
        $command = $db->createCommand();
470
        $reader = $command->setSql(
471
            <<<SQL
472
            SELECT * FROM {{customer}}
473
            SQL
474
        )->query();
475
        $reader->next();
476
        $reader->rewind();
477
    }
478
479
    public function testDelete(): void
480
    {
481
        $db = $this->getConnection('customer');
482
483
        $command = $db->createCommand();
484
        $command->delete('{{customer}}', ['id' => 2])->execute();
485
        $chekSql = <<<SQL
486
        SELECT COUNT([[id]]) FROM [[customer]]
487
        SQL;
488
        $command->setSql($chekSql);
489
490
        $this->assertSame('2', $command->queryScalar());
491
492
        $command->delete('{{customer}}', ['id' => 3])->execute();
493
        $command->setSql($chekSql);
494
495
        $this->assertSame('1', $command->queryScalar());
496
    }
497
498
    public function testDropCheck()
499
    {
500
        $db = $this->getConnection();
501
502
        $command = $db->createCommand();
503
        $schema = $db->getSchema();
504
505
        if ($schema->getTableSchema('{{test_ck}}') !== null) {
506
            $command->dropTable('{{test_ck}}')->execute();
507
        }
508
509
        $command->createTable('{{test_ck}}', ['int1' => 'integer'])->execute();
510
511
        $this->assertEmpty($schema->getTableChecks('{{test_ck}}', true));
512
513
        $command->addCheck('{{test_ck_constraint}}', '{{test_ck}}', 'int1 > 1')->execute();
514
515
        $this->assertMatchesRegularExpression(
516
            '/^.*int1.*>.*1.*$/',
517
            $schema->getTableChecks('{{test_ck}}', true)[0]->getExpression(),
518
        );
519
520
        $command->dropCheck('{{test_ck_constraint}}', '{{test_ck}}')->execute();
521
522
        $this->assertEmpty($schema->getTableChecks('{{test_ck}}', true));
523
    }
524
525
    public function testDropColumn(): void
526
    {
527
        $db = $this->getConnection();
528
529
        $command = $db->createCommand();
530
        $schema = $db->getSchema();
531
532
        if ($schema->getTableSchema('{{testDropColumn}}', true) !== null) {
533
            $command->dropTable('{{testDropColumn}}')->execute();
534
        }
535
536
        $command->createTable(
537
            '{{testDropColumn}}',
538
            ['id' => Schema::TYPE_PK, 'bar' => Schema::TYPE_INTEGER, 'baz' => Schema::TYPE_INTEGER],
539
        )->execute();
540
        $command->dropColumn('{{testDropColumn}}', 'bar')->execute();
541
542
        $this->assertArrayNotHasKey('bar', $schema->getTableSchema('{{testDropColumn}}')->getColumns());
543
        $this->assertArrayHasKey('baz', $schema->getTableSchema('{{testDropColumn}}')->getColumns());
544
    }
545
546
    public function testDropCommentFromColumn(): void
547
    {
548
        $db = $this->getConnection('customer');
549
550
        $command = $db->createCommand();
551
        $command->addCommentOnColumn('{{customer}}', 'id', 'Primary key.')->execute();
552
        $commentOnColumn = DbHelper::getCommmentsFromColumn('customer', 'id', $db);
553
554
        $this->assertSame(['value' => 'Primary key.'], $commentOnColumn);
555
556
        $command->dropCommentFromColumn('{{customer}}', 'id')->execute();
557
        $commentOnColumn = DbHelper::getCommmentsFromColumn('customer', 'id', $db);
558
559
        $this->assertNull($commentOnColumn);
560
    }
561
562
    public function testDropCommentFromTable(): void
563
    {
564
        $db = $this->getConnection('customer');
565
566
        $command = $db->createCommand();
567
        $command->addCommentOnTable('{{customer}}', 'Customer table.')->execute();
568
        $commentOnTable = DbHelper::getCommmentsFromTable('customer', $db);
569
570
        $this->assertSame(['value' => 'Customer table.'], $commentOnTable);
571
572
        $command->dropCommentFromTable('{{customer}}')->execute();
573
        $commentOnTable = DbHelper::getCommmentsFromTable('customer', $db);
574
575
        $this->assertNull($commentOnTable);
576
    }
577
578
    public function testDropDefaultValue(): void
579
    {
580
        $db = $this->getConnection();
581
582
        $command = $db->createCommand();
583
        $schema = $db->getSchema();
584
585
        if ($schema->getTableSchema('{{test_def}}') !== null) {
586
            $command->dropTable('{{test_def}}')->execute();
587
        }
588
589
        $command->createTable('{{test_def}}', ['int1' => 'integer'])->execute();
590
591
        $this->assertEmpty($schema->getTableDefaultValues('{{test_def}}', true));
592
593
        $command->addDefaultValue('{{test_def_constraint}}', '{{test_def}}', 'int1', 41)->execute();
594
595
        $this->assertMatchesRegularExpression(
596
            '/^.*41.*$/',
597
            $schema->getTableDefaultValues('{{test_def}}', true)[0]->getValue(),
598
        );
599
600
        $command->dropDefaultValue('{{test_def_constraint}}', '{{test_def}}')->execute();
601
602
        $this->assertEmpty($schema->getTableDefaultValues('{{test_def}}', true));
603
    }
604
605
    public function testDropForeignKey(): void
606
    {
607
        $db = $this->getConnection();
608
609
        $command = $db->createCommand();
610
        $schema = $db->getSchema();
611
612
        if ($schema->getTableSchema('{{test_fk}}') !== null) {
613
            $command->dropTable('{{test_fk}}')->execute();
614
        }
615
616
        $command->createTable('{{test_fk}}', ['id' => Schema::TYPE_PK, 'int1' => 'integer'])->execute();
617
618
        $this->assertEmpty($schema->getTableForeignKeys('{{test_fk}}', true));
619
620
        $command->addForeignKey('{{test_fk_constraint}}', '{{test_fk}}', 'int1', '{{test_fk}}', 'id')->execute();
621
622
        $this->assertNotEmpty($schema->getTableForeignKeys('{{test_fk}}', true));
623
624
        $command->dropForeignKey('{{test_fk_constraint}}', '{{test_fk}}')->execute();
625
626
        $this->assertEmpty($schema->getTableForeignKeys('{{test_fk}}', true));
627
    }
628
629
    public function testDropIndex(): void
630
    {
631
        $db = $this->getConnection();
632
633
        $command = $db->createCommand();
634
        $schema = $db->getSchema();
635
636
        if ($schema->getTableSchema('{{test_idx}}') !== null) {
637
            $command->dropTable('{{test_idx}}')->execute();
638
        }
639
640
        $command->createTable('{{test_idx}}', ['int1' => 'integer not null', 'int2' => 'integer not null'])->execute();
641
642
        $this->assertEmpty($schema->getTableIndexes('{[test_idx}}', true));
643
644
        $command->createIndex('{{test_idx_constraint}}', '{{test_idx}}', ['int1', 'int2'], 'UNIQUE')->execute();
645
646
        $this->assertSame(['int1', 'int2'], $schema->getTableIndexes('{{test_idx}}', true)[0]->getColumnNames());
647
        $this->assertTrue($schema->getTableIndexes('{{test_idx}}', true)[0]->isUnique());
648
649
        $command->dropIndex('{{test_idx_constraint}}', '{{test_idx}}')->execute();
650
651
        $this->assertEmpty($schema->getTableIndexes('{{test_idx}}', true));
652
    }
653
654
    public function testDropPrimaryKey(): void
655
    {
656
        $db = $this->getConnection();
657
658
        $command = $db->createCommand();
659
        $schema = $db->getSchema();
660
661
        if ($schema->getTableSchema('{{test_pk}}') !== null) {
662
            $command->dropTable('{{test_pk}}')->execute();
663
        }
664
665
        $command->createTable('{{test_pk}}', ['int1' => 'integer not null', 'int2' => 'integer not null'])->execute();
666
667
        $this->assertEmpty($schema->getTableSchema('{{test_pk}}', true)->getPrimaryKey());
668
669
        $command->addPrimaryKey('{{test_pk_constraint}}', '{{test_pk}}', ['int1', 'int2'])->execute();
670
671
        $this->assertSame(['int1', 'int2'], $schema->getTableSchema('{{test_pk}}', true)->getColumnNames());
672
673
        $command->dropPrimaryKey('{{test_pk_constraint}}', '{{test_pk}}')->execute();
674
675
        $this->assertEmpty($schema->getTableSchema('{{test_pk}}', true)->getPrimaryKey());
676
    }
677
678
    public function testDropTable(): void
679
    {
680
        $db = $this->getConnection();
681
682
        $command = $db->createCommand();
683
        $schema = $db->getSchema();
684
685
        if ($schema->getTableSchema('{{testDropTable}]') !== null) {
686
            $command->dropTable('{{testDropTable}}')->execute();
687
        }
688
689
        $command->createTable('{{testDropTable}}', ['id' => Schema::TYPE_PK, 'foo' => 'integer'])->execute();
690
691
        $this->assertNotNull($schema->getTableSchema('{{testDropTable}}', true));
692
693
        $command->dropTable('{{testDropTable}}')->execute();
694
695
        $this->assertNull($schema->getTableSchema('{{testDropTable}}', true));
696
    }
697
698
    public function testDropUnique(): void
699
    {
700
        $db = $this->getConnection();
701
702
        $command = $db->createCommand();
703
        $schema = $db->getSchema();
704
705
        if ($schema->getTableSchema('{{test_uq}}') !== null) {
706
            $command->dropTable('{{test_uq}}')->execute();
707
        }
708
709
        $command->createTable('{{test_uq}}', ['int1' => 'integer not null', 'int2' => 'integer not null'])->execute();
710
711
        $this->assertEmpty($schema->getTableUniques('{{test_uq}}', true));
712
713
        $command->addUnique('{{test_uq_constraint}}', '{{test_uq}}', ['int1'])->execute();
714
715
        $this->assertSame(['int1'], $schema->getTableUniques('{{test_uq}}', true)[0]->getColumnNames());
716
717
        $command->dropUnique('{{test_uq_constraint}}', '{{test_uq}}')->execute();
718
719
        $this->assertEmpty($schema->getTableUniques('{{test_uq}}', true));
720
    }
721
722
    public function testDropView(): void
723
    {
724
        $db = $this->getConnection('animal');
725
726
        /* since it already exists in the fixtures */
727
        $viewName = '{{animal_view}}';
728
729
        $schema = $db->getSchema();
730
731
        $this->assertNotNull($schema->getTableSchema($viewName));
732
733
        $db->createCommand()->dropView($viewName)->execute();
734
735
        $this->assertNull($schema->getTableSchema($viewName));
736
    }
737
738
    public function testExecute(): void
739
    {
740
        $db = $this->getConnection('customer');
741
742
        $command = $db->createCommand();
743
        $command->setSql(
744
            <<<SQL
745
            INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES ('[email protected]', 'user4', 'address4')
746
            SQL
747
        );
748
749
        $this->assertSame(1, $command->execute());
750
751
        $command = $command->setSql(
752
            <<<SQL
753
            SELECT COUNT(*) FROM {{customer}} WHERE [[name]] = 'user4'
754
            SQL
755
        );
756
757
        $this->assertEquals(1, $command->queryScalar());
758
759
        $command->setSql('bad SQL');
760
        $message = match ($db->getName()) {
761
            'sqlite' => 'SQLSTATE[HY000]: General error: 1 near "bad": syntax error',
762
            'sqlsrv' => 'SQLSTATE[42000]: [Microsoft]',
763
        };
764
765
        $this->expectException(Exception::class);
766
        $this->expectExceptionMessage($message);
767
768
        $command->execute();
769
    }
770
771
    public function testExecuteWithoutSql(): void
772
    {
773
        $db = $this->getConnection();
774
775
        $command = $db->createCommand();
776
        $result = $command->setSql('')->execute();
777
778
        $this->assertSame(0, $result);
779
    }
780
781
    public function testInsert(): void
782
    {
783
        $db = $this->getConnection('customer');
784
785
        $db->createCommand(
786
            <<<SQL
787
            DELETE FROM {{customer}}
788
            SQL
789
        )->execute();
790
        $command = $db->createCommand();
791
        $command
792
            ->insert('{{customer}}', ['email' => '[email protected]', 'name' => 'test', 'address' => 'test address'])
793
            ->execute();
794
795
        $this->assertEquals(
796
            1,
797
            $db->createCommand(
798
                <<<SQL
799
                SELECT COUNT(*) FROM {{customer}};
800
                SQL
801
            )->queryScalar(),
802
        );
803
804
        $record = $db->createCommand(
805
            <<<SQL
806
            SELECT [[email]], [[name]], [[address]] FROM {{customer}}
807
            SQL
808
        )->queryOne();
809
810
        $this->assertSame(['email' => '[email protected]', 'name' => 'test', 'address' => 'test address'], $record);
811
    }
812
813
    public function testInsertExpression(): void
814
    {
815
        $db = $this->getConnection('order_with_null');
816
817
        $command = $db->createCommand();
818
        $command->setSql(
819
            <<<SQL
820
            DELETE FROM {{order_with_null_fk}}
821
            SQL
822
        )->execute();
823
        $expression = match ($db->getName()) {
824
            'mysql' => 'YEAR(NOW())',
825
            'pgsql' => "EXTRACT(YEAR FROM TIMESTAMP 'now')",
826
            'sqlite' => "strftime('%Y')",
827
            'sqlsrv' => 'YEAR(GETDATE())',
828
        };
829
        $command->insert(
830
            '{{order_with_null_fk}}',
831
            ['created_at' => new Expression($expression), 'total' => 1],
832
        )->execute();
833
834
        $this->assertEquals(
835
            1,
836
            $command->setSql(
837
                <<<SQL
838
                SELECT COUNT(*) FROM {{order_with_null_fk}}
839
                SQL
840
            )->queryScalar(),
841
        );
842
843
        $record = $command->setSql(
844
            <<<SQL
845
            SELECT [[created_at]] FROM {{order_with_null_fk}}
846
            SQL
847
        )->queryOne();
848
849
        $this->assertEquals(['created_at' => date('Y')], $record);
850
    }
851
852
    public function testsInsertQueryAsColumnValue(): void
853
    {
854
        $db = $this->getConnection('order', 'order_with_null');
855
856
        $command = $db->createCommand();
857
        $time = time();
858
        $command->setSql(
859
            <<<SQL
860
            DELETE FROM {{order_with_null_fk}}
861
            SQL
862
        )->execute();
863
        $command->insert('{{order}}', ['customer_id' => 1, 'created_at' => $time, 'total' => 42])->execute();
864
865
        if ($db->getName() === 'pgsql') {
866
            $orderId = $db->getLastInsertID('public.order_id_seq');
867
        } else {
868
            $orderId = $db->getLastInsertID();
869
        }
870
871
        $columnValueQuery = (new Query($db))->select('[[created_at]]')->from('{{order}}')->where(['id' => $orderId]);
872
        $command->insert(
873
            '{{order_with_null_fk}}',
874
            ['customer_id' => $orderId, 'created_at' => $columnValueQuery, 'total' => 42],
875
        )->execute();
876
877
        $this->assertEquals(
878
            $time,
879
            $command->setSql(
880
                <<<SQL
881
                SELECT [[created_at]] FROM {{order_with_null_fk}} WHERE [[customer_id]] = :id
882
                SQL
883
            )->bindValues([':id' => $orderId])->queryScalar(),
884
        );
885
886
        $command->setSql(
887
            <<<SQL
888
            DELETE FROM {{order_with_null_fk}}
889
            SQL
890
        )->execute();
891
        $command->setSql(
892
            <<<SQL
893
            DELETE FROM {{order}}
894
            SQL
895
        )->execute();
896
    }
897
898
    public function testInsertSelect(): void
899
    {
900
        $db = $this->getConnection('customer');
901
902
        $command = $db->createCommand();
903
        $command->setSql(
904
            <<<SQL
905
            DELETE FROM {{customer}}
906
            SQL
907
        )->execute();
908
        $command->insert(
909
            '{{customer}}',
910
            ['email' => '[email protected]', 'name' => 'test', 'address' => 'test address']
911
        )->execute();
912
        $query = (new Query($db))
913
            ->select(['{{customer}}.[[email]] as name', '[[name]] as email', '[[address]]'])
914
            ->from('{{customer}}')
915
            ->where(['and', ['<>', 'name', 'foo'], ['status' => [0, 1, 2, 3]]]);
916
        $command->insert('{{customer}}', $query)->execute();
917
918
        $this->assertEquals(
919
            2,
920
            $command->setSql(
921
                <<<SQL
922
                SELECT COUNT(*) FROM {{customer}}
923
                SQL
924
            )->queryScalar(),
925
        );
926
927
        $record = $command->setSql(
928
            <<<SQL
929
            SELECT [[email]], [[name]], [[address]] FROM {{customer}}
930
            SQL
931
        )->queryAll();
932
933
        $this->assertSame(
934
            [
935
                ['email' => '[email protected]', 'name' => 'test', 'address' => 'test address'],
936
                ['email' => 'test', 'name' => '[email protected]', 'address' => 'test address'],
937
            ],
938
            $record,
939
        );
940
    }
941
942
    public function testInsertSelectAlias(): void
943
    {
944
        $db = $this->getConnection('customer');
945
946
        $command = $db->createCommand();
947
        $command->setSql(
948
            <<<SQL
949
            DELETE FROM {{customer}}
950
            SQL
951
        )->execute();
952
        $command->insert(
953
            '{{customer}}',
954
            [
955
                'email' => '[email protected]',
956
                'name' => 'test',
957
                'address' => 'test address',
958
            ]
959
        )->execute();
960
        $query = (new Query($db))
961
            ->select(['email' => '{{customer}}.[[email]]', 'address' => 'name', 'name' => 'address'])
962
            ->from('{{customer}}')
963
            ->where(['and', ['<>', 'name', 'foo'], ['status' => [0, 1, 2, 3]]]);
964
        $command->insert('{{customer}}', $query)->execute();
965
966
        $this->assertEquals(
967
            2,
968
            $command->setSql(
969
                <<<SQL
970
                SELECT COUNT(*) FROM {{customer}}
971
                SQL
972
            )->queryScalar(),
973
        );
974
975
        $record = $command->setSql(
976
            <<<SQL
977
            SELECT [[email]], [[name]], [[address]] FROM {{customer}}
978
            SQL
979
        )->queryAll();
980
981
        $this->assertSame(
982
            [
983
                ['email' => '[email protected]', 'name' => 'test', 'address' => 'test address'],
984
                ['email' => '[email protected]', 'name' => 'test address', 'address' => 'test'],
985
            ],
986
            $record,
987
        );
988
    }
989
990
    /**
991
     * Test INSERT INTO ... SELECT SQL statement with wrong query object.
992
     *
993
     * @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::invalidSelectColumns()
994
     *
995
     * @throws Exception
996
     * @throws Throwable
997
     */
998
    public function testInsertSelectFailed(array|ExpressionInterface|string $invalidSelectColumns): void
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Tests\Common\ExpressionInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
999
    {
1000
        $db = $this->getConnection();
1001
1002
        $query = new Query($db);
1003
        $query->select($invalidSelectColumns)->from('{{customer}}');
1004
        $command = $db->createCommand();
1005
1006
        $this->expectException(InvalidArgumentException::class);
1007
        $this->expectExceptionMessage('Expected select query object with enumerated (named) parameters');
1008
1009
        $command->insert('{{customer}}', $query)->execute();
1010
    }
1011
1012
    public function testInsertToBlob(): void
1013
    {
1014
        $db = $this->getConnection('type');
1015
1016
        $command = $db->createCommand();
1017
        $command->delete('{{type}}')->execute();
1018
        $columns = [
1019
            'int_col' => 1,
1020
            'char_col' => 'test',
1021
            'float_col' => 3.14,
1022
            'bool_col' => true,
1023
            'blob_col' => serialize(['test' => 'data', 'num' => 222]),
1024
        ];
1025
        $command->insert('{{type}}', $columns)->execute();
1026
        $result = $command->setSql(
1027
            <<<SQL
1028
            SELECT [[blob_col]] FROM {{type}}
1029
            SQL
1030
        )->queryOne();
1031
1032
        $this->assertIsArray($result);
1033
1034
        $resultBlob = is_resource($result['blob_col']) ? stream_get_contents($result['blob_col']) : $result['blob_col'];
1035
1036
        $this->assertSame($columns['blob_col'], $resultBlob);
1037
    }
1038
1039
    public function testIntegrityViolation(): void
1040
    {
1041
        $db = $this->getConnection('profile');
1042
1043
        $this->expectException(IntegrityException::class);
1044
1045
        $command = $db->createCommand(
1046
            <<<SQL
1047
            INSERT INTO {{profile}}([[id]], [[description]]) VALUES (123, 'duplicate')
1048
            SQL
1049
        );
1050
        $command->execute();
1051
        $command->execute();
1052
    }
1053
1054
    public function testNoTablenameReplacement(): void
1055
    {
1056
        $db = $this->getConnection('customer');
1057
1058
        $command = $db->createCommand();
1059
        $command->insert(
1060
            '{{customer}}',
1061
            ['name' => 'Some {{weird}} name', 'email' => '[email protected]', 'address' => 'Some {{%weird}} address']
1062
        )->execute();
1063
1064
        if ($db->getName() === 'pgsql') {
1065
            $customerId = $db->getLastInsertID('public.customer_id_seq');
1066
        } else {
1067
            $customerId = $db->getLastInsertID();
1068
        }
1069
1070
        $customer = $command->setSql(
1071
            <<<SQL
1072
            SELECT [[name]], [[email]], [[address]] FROM {{customer}} WHERE [[id]]=:id
1073
            SQL,
1074
        )->bindValues([':id' => $customerId])->queryOne();
1075
1076
        $this->assertIsArray($customer);
1077
        $this->assertSame('Some {{weird}} name', $customer['name']);
1078
        $this->assertSame('Some {{%weird}} address', $customer['address']);
1079
1080
        $command->update(
1081
            '{{customer}}',
1082
            ['name' => 'Some {{updated}} name', 'address' => 'Some {{%updated}} address'],
1083
            ['id' => $customerId]
1084
        )->execute();
1085
        $customer = $command->setSql(
1086
            <<<SQL
1087
            SELECT [[name]], [[email]], [[address]] FROM {{customer}} WHERE [[id]] = :id
1088
            SQL
1089
        )->bindValues([':id' => $customerId])->queryOne();
1090
1091
        $this->assertIsArray($customer);
1092
        $this->assertSame('Some {{updated}} name', $customer['name']);
1093
        $this->assertSame('Some {{%updated}} address', $customer['address']);
1094
    }
1095
1096
    public function testQuery(): void
1097
    {
1098
        $db = $this->getConnection('customer');
1099
1100
        $command = $db->createCommand();
1101
1102
        $command->setSql(
1103
            <<<SQL
1104
            SELECT * FROM {{customer}}
1105
            SQL
1106
        );
1107
1108
        $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...
1109
1110
        $reader = $command->query();
1111
1112
        // check tests that the reader is a valid iterator
1113
        if ($db->getName() !== 'sqlite' && $db->getName() !== 'pgsql' && $db->getName() !== 'sqlsrv') {
1114
            $this->assertEquals(3, $reader->count());
1115
        }
1116
1117
        $this->assertNotNull($command->getPdoStatement());
1118
        $this->assertInstanceOf(DataReaderInterface::class, $reader);
1119
        $this->assertIsInt($reader->count());
1120
1121
        foreach ($reader as $row) {
1122
            $this->assertIsArray($row);
1123
            $this->assertCount(6, $row);
1124
        }
1125
1126
        $command = $db->createCommand('bad SQL');
1127
1128
        $this->expectException(Exception::class);
1129
1130
        $command->query();
1131
    }
1132
1133
    public function testQueryAll(): void
1134
    {
1135
        $db = $this->getConnection('customer');
1136
1137
        $command = $db->createCommand();
1138
1139
        $command->setSql(
1140
            <<<SQL
1141
            SELECT * FROM {{customer}}
1142
            SQL
1143
        );
1144
        $rows = $command->queryAll();
1145
1146
        $this->assertIsArray($rows);
1147
        $this->assertCount(3, $rows);
1148
        $this->assertIsArray($rows[0]);
1149
        $this->assertCount(6, $rows[0]);
1150
1151
        $command->setSql('bad SQL');
1152
1153
        $this->expectException(Exception::class);
1154
1155
        $command->queryAll();
1156
        $command->setSql(
1157
            <<<SQL
1158
            SELECT * FROM {{customer}} where id = 100
1159
            SQL
1160
        );
1161
        $rows = $command->queryAll();
1162
1163
        $this->assertIsArray($rows);
1164
        $this->assertCount(0, $rows);
1165
        $this->assertSame([], $rows);
1166
    }
1167
1168
    public function testQueryCache(): void
1169
    {
1170
        $db = $this->getConnection('customer');
1171
1172
        $query = (new Query($db))->select(['name'])->from('customer');
1173
        $command = $db->createCommand();
1174
        $update = $command->setSql(
1175
            <<<SQL
1176
            UPDATE {{customer}} SET [[name]] = :name WHERE [[id]] = :id
1177
            SQL
1178
        );
1179
1180
        $this->assertSame('user1', $query->where(['id' => 1])->scalar(), 'Asserting initial value');
1181
1182
        /* No cache */
1183
        $update->bindValues([':id' => 1, ':name' => 'user11'])->execute();
1184
1185
        $this->assertSame(
1186
            'user11',
1187
            $query->where(['id' => 1])->scalar(),
1188
            'Query reflects DB changes when caching is disabled',
1189
        );
1190
1191
        /* Connection cache */
1192
        $db->cache(
1193
            static function (ConnectionPDOInterface $db) use ($query, $update) {
1194
                self::assertSame('user2', $query->where(['id' => 2])->scalar(), 'Asserting initial value for user #2');
1195
1196
                $update->bindValues([':id' => 2, ':name' => 'user22'])->execute();
1197
1198
                self::assertSame(
1199
                    'user2',
1200
                    $query->where(['id' => 2])->scalar(),
1201
                    'Query does NOT reflect DB changes when wrapped in connection caching',
1202
                );
1203
1204
                $db->noCache(
1205
                    static function () use ($query) {
1206
                        self::assertSame(
1207
                            'user22',
1208
                            $query->where(['id' => 2])->scalar(),
1209
                            'Query reflects DB changes when wrapped in connection caching and noCache simultaneously',
1210
                        );
1211
                    }
1212
                );
1213
1214
                self::assertSame(
1215
                    'user2',
1216
                    $query->where(['id' => 2])->scalar(),
1217
                    'Cache does not get changes after getting newer data from DB in noCache block.',
1218
                );
1219
            },
1220
            10,
1221
        );
1222
1223
        $db->queryCacheEnable(false);
1224
1225
        $db->cache(
1226
            static function () use ($query, $update) {
1227
                self::assertSame(
1228
                    'user22',
1229
                    $query->where(['id' => 2])->scalar(),
1230
                    'When cache is disabled for the whole connection, Query inside cache block does not get cached',
1231
                );
1232
1233
                $update->bindValues([':id' => 2, ':name' => 'user2'])->execute();
1234
1235
                self::assertSame('user2', $query->where(['id' => 2])->scalar());
1236
            },
1237
            10,
1238
        );
1239
1240
        $db->queryCacheEnable(true);
1241
        $query->cache();
1242
1243
        $this->assertSame('user11', $query->where(['id' => 1])->scalar());
1244
1245
        $update->bindValues([':id' => 1, ':name' => 'user1'])->execute();
1246
1247
        $this->assertSame(
1248
            'user11',
1249
            $query->where(['id' => 1])->scalar(),
1250
            'When both Connection and Query have cache enabled, we get cached value',
1251
        );
1252
        $this->assertSame(
1253
            'user1',
1254
            $query->noCache()->where(['id' => 1])->scalar(),
1255
            'When Query has disabled cache, we get actual data',
1256
        );
1257
1258
        $db->cache(
1259
            static function () use ($query) {
1260
                self::assertSame('user1', $query->noCache()->where(['id' => 1])->scalar());
1261
                self::assertSame('user11', $query->cache()->where(['id' => 1])->scalar());
1262
            },
1263
            10,
1264
        );
1265
    }
1266
1267
    public function testQueryColumn(): void
1268
    {
1269
        $db = $this->getConnection('customer');
1270
1271
        $command = $db->createCommand();
1272
        $command->setSql(
1273
            <<<SQL
1274
            SELECT * FROM {{customer}}
1275
            SQL
1276
        );
1277
        $rows = $command->queryColumn();
1278
1279
        $this->assertIsArray($rows);
1280
        $this->assertCount(3, $rows);
1281
        $this->assertEquals('1', $rows[0]);
1282
1283
        $command->setSql('bad SQL');
1284
1285
        $this->expectException(Exception::class);
1286
1287
        $command->queryColumn();
1288
        $command->setSql(
1289
            <<<SQL
1290
            SELECT * FROM {{customer}} where id = 100
1291
            SQL
1292
        );
1293
        $rows = $command->queryColumn();
1294
1295
        $this->assertIsArray($rows);
1296
        $this->assertCount(0, $rows);
1297
        $this->assertSame([], $rows);
1298
    }
1299
1300
    public function testQueryOne(): void
1301
    {
1302
        $db = $this->getConnection('customer');
1303
1304
        $command = $db->createCommand();
1305
        $sql = <<<SQL
1306
        SELECT * FROM {{customer}} ORDER BY [[id]]
1307
        SQL;
1308
        $row = $command->setSql($sql)->queryOne();
1309
1310
        $this->assertIsArray($row);
1311
        $this->assertEquals(1, $row['id']);
1312
        $this->assertEquals('user1', $row['name']);
1313
1314
        $command->setSql($sql)->prepare();
1315
        $row = $command->queryOne();
1316
1317
        $this->assertIsArray($row);
1318
        $this->assertEquals(1, $row['id']);
1319
        $this->assertEquals('user1', $row['name']);
1320
1321
        $sql = <<<SQL
1322
        SELECT * FROM {{customer}} WHERE [[id]] = 10
1323
        SQL;
1324
        $command = $command->setSql($sql);
1325
1326
        $this->assertNull($command->queryOne());
1327
    }
1328
1329
    public function testQueryScalar(): void
1330
    {
1331
        $db = $this->getConnection('customer');
1332
1333
        $command = $db->createCommand();
1334
        $sql = <<<SQL
1335
        SELECT * FROM {{customer}} ORDER BY [[id]]
1336
        SQL;
1337
1338
        $this->assertEquals(1, $command->setSql($sql)->queryScalar());
1339
1340
        $sql = <<<SQL
1341
        SELECT [[id]] FROM {{customer}} ORDER BY [[id]]
1342
        SQL;
1343
        $command->setSql($sql)->prepare();
1344
1345
        $this->assertEquals(1, $command->queryScalar());
1346
1347
        $command = $command->setSql(
1348
            <<<SQL
1349
            SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10
1350
            SQL
1351
        );
1352
1353
        $this->assertFalse($command->queryScalar());
1354
    }
1355
1356
    public function testRenameColumn(): void
1357
    {
1358
        $db = $this->getConnection('customer');
1359
1360
        $command = $db->createCommand();
1361
        $schema = $db->getSchema();
1362
1363
        $command->renameColumn('{{customer}}', 'address', 'address_city')->execute();
1364
1365
        $this->assertContains('address_city', $schema->getTableSchema('{{customer}}')->getColumnNames());
1366
        $this->assertNotContains('address', $schema->getTableSchema('{{customer}}')->getColumnNames());
1367
    }
1368
1369
    public function testRenameTable(): void
1370
    {
1371
        $db = $this->getConnection('type');
1372
1373
        $command = $db->createCommand();
1374
        $schema = $db->getSchema();
1375
1376
        if ($schema->getTableSchema('{{new_type}}') !== null) {
1377
            $command->dropTable('{{new_type}}')->execute();
1378
        }
1379
1380
        $this->assertNotNull($schema->getTableSchema('{{type}}'));
1381
        $this->assertNull($schema->getTableSchema('{{new_type}}'));
1382
1383
        $command->renameTable('{{type}}', '{{new_type}}')->execute();
1384
1385
        $this->assertNull($schema->getTableSchema('{{type}}', true));
1386
        $this->assertNotNull($schema->getTableSchema('{{new_type}}', true));
1387
    }
1388
1389
    public function testSetRetryHandler(): void
1390
    {
1391
        $db = $this->getConnection('profile');
1392
1393
        $command = $db->createCommand();
1394
1395
        $this->assertNull($db->getTransaction());
1396
1397
        $command->setSql(
1398
            <<<SQL
1399
            INSERT INTO {{profile}}([[description]]) VALUES('command retry')
1400
            SQL
1401
        )->execute();
1402
1403
        $this->assertNull($db->getTransaction());
1404
        $this->assertEquals(
1405
            1,
1406
            $command->setSql(
1407
                <<<SQL
1408
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'command retry'
1409
                SQL
1410
            )->queryScalar()
1411
        );
1412
1413
        $attempts = null;
1414
        $hitHandler = false;
1415
        $hitCatch = false;
1416
        $command->setSql(
1417
            <<<SQL
1418
            INSERT INTO {{profile}}([[id]], [[description]]) VALUES(1, 'command retry')
1419
            SQL
1420
        );
1421
1422
        Assert::invokeMethod(
1423
            $command,
1424
            'setRetryHandler',
1425
            [static function ($exception, $attempt) use (&$attempts, &$hitHandler) {
1426
                $attempts = $attempt;
1427
                $hitHandler = true;
1428
1429
                return $attempt <= 2;
1430
            }]
1431
        );
1432
1433
        try {
1434
            $command->execute();
1435
        } catch (Exception $e) {
1436
            $hitCatch = true;
1437
1438
            $this->assertInstanceOf(IntegrityException::class, $e);
1439
        }
1440
1441
        $this->assertNull($db->getTransaction());
1442
        $this->assertSame(3, $attempts);
1443
        $this->assertTrue($hitHandler);
1444
        $this->assertTrue($hitCatch);
1445
    }
1446
1447
    public function testTransaction(): void
1448
    {
1449
        $db = $this->getConnection('profile');
1450
1451
        $this->assertNull($db->getTransaction());
1452
1453
        $command = $db->createCommand();
1454
        $command = $command->setSql(
1455
            <<<SQL
1456
            INSERT INTO {{profile}}([[description]]) VALUES('command transaction')
1457
            SQL
1458
        );
1459
1460
        Assert::invokeMethod($command, 'requireTransaction');
1461
1462
        $command->execute();
1463
1464
        $this->assertNull($db->getTransaction());
1465
        $this->assertEquals(
1466
            1,
1467
            $command->setSql(
1468
                <<<SQL
1469
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'command transaction'
1470
                SQL
1471
            )->queryScalar(),
1472
        );
1473
    }
1474
1475
    public function testTruncateTable(): void
1476
    {
1477
        $db = $this->getConnection('animal');
1478
1479
        $command = $db->createCommand();
1480
        $rows = $command->setSql(
1481
            <<<SQL
1482
            SELECT * FROM {{animal}}
1483
            SQL
1484
        )->queryAll();
1485
1486
        $this->assertCount(2, $rows);
1487
1488
        $command->truncateTable('animal')->execute();
1489
        $rows = $command->setSql(
1490
            <<<SQL
1491
            SELECT * FROM {{animal}}
1492
            SQL
1493
        )->queryAll();
1494
1495
        $this->assertCount(0, $rows);
1496
    }
1497
1498
    /**
1499
     * @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::update()
1500
     */
1501
    public function testUpdate(
1502
        string $table,
1503
        array $columns,
1504
        array|string $conditions,
1505
        array $params,
1506
        string $expected
1507
    ): void {
1508
        $db = $this->getConnection();
1509
1510
        $command = $db->createCommand();
1511
        $sql = $command->update($table, $columns, $conditions, $params)->getSql();
1512
1513
        $this->assertSame($expected, $sql);
1514
    }
1515
1516
    /**
1517
     * @dataProvider \Yiisoft\Db\Tests\Provider\CommandProvider::upsert()
1518
     */
1519
    public function testUpsert(array $firstData, array $secondData): void
1520
    {
1521
        $db = $this->getConnection('customer', 't_upsert');
1522
1523
        $this->assertEquals(0, $db->createCommand('SELECT COUNT(*) FROM {{T_upsert}}')->queryScalar());
1524
1525
        $this->performAndCompareUpsertResult($db, $firstData);
1526
1527
        $this->assertEquals(1, $db->createCommand('SELECT COUNT(*) FROM {{T_upsert}}')->queryScalar());
1528
1529
        $this->performAndCompareUpsertResult($db, $secondData);
1530
    }
1531
1532
    protected function performAndCompareUpsertResult(ConnectionPDOInterface $db, array $data): void
1533
    {
1534
        $params = $data['params'];
1535
        $expected = $data['expected'] ?? $params[1];
1536
1537
        $command = $db->createCommand();
1538
1539
        call_user_func_array([$command, 'upsert'], $params);
1540
1541
        $command->execute();
1542
1543
        $actual = (new Query($db))
1544
            ->select(['email', 'address' => new Expression($this->upsertTestCharCast), 'status'])
1545
            ->from('T_upsert')
1546
            ->one();
1547
        $this->assertEquals($expected, $actual, $this->upsertTestCharCast);
1548
    }
1549
}
1550