Issues (201)

tests/Functional/WriteTest.php (2 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Tests\Functional;
6
7
use DateTime;
8
use Doctrine\DBAL\Driver\DriverException;
9
use Doctrine\DBAL\ParameterType;
10
use Doctrine\DBAL\Schema\Sequence;
11
use Doctrine\DBAL\Schema\Table;
12
use Doctrine\DBAL\Tests\FunctionalTestCase;
13
use Throwable;
14
use function array_filter;
15
use function strtolower;
16
17
class WriteTest extends FunctionalTestCase
18
{
19
    protected function setUp() : void
20
    {
21
        parent::setUp();
22
23
        $table = new Table('write_table');
24
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
25
        $table->addColumn('test_int', 'integer');
26
        $table->addColumn('test_string', 'string', [
27
            'length' => 32,
28
            'notnull' => false,
29
        ]);
30
        $table->setPrimaryKey(['id']);
31
32
        $this->connection->getSchemaManager()->dropAndCreateTable($table);
33
34
        $this->connection->executeUpdate('DELETE FROM write_table');
35
    }
36
37
    public function testExecuteUpdate() : void
38
    {
39
        $sql      = 'INSERT INTO write_table (test_int) VALUES (1)';
40
        $affected = $this->connection->executeUpdate($sql);
41
42
        self::assertEquals(1, $affected, 'executeUpdate() should return the number of affected rows!');
43
    }
44
45
    public function testExecuteUpdateWithTypes() : void
46
    {
47
        $sql      = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)';
48
        $affected = $this->connection->executeUpdate(
49
            $sql,
50
            [1, 'foo'],
51
            [ParameterType::INTEGER, ParameterType::STRING]
52
        );
53
54
        self::assertEquals(1, $affected, 'executeUpdate() should return the number of affected rows!');
55
    }
56
57
    public function testPrepareRowCountReturnsAffectedRows() : void
58
    {
59
        $sql  = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)';
60
        $stmt = $this->connection->prepare($sql);
61
62
        $stmt->bindValue(1, 1);
63
        $stmt->bindValue(2, 'foo');
64
        $stmt->execute();
65
66
        self::assertEquals(1, $stmt->rowCount());
67
    }
68
69
    public function testPrepareWithPdoTypes() : void
70
    {
71
        $sql  = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)';
72
        $stmt = $this->connection->prepare($sql);
73
74
        $stmt->bindValue(1, 1, ParameterType::INTEGER);
75
        $stmt->bindValue(2, 'foo', ParameterType::STRING);
76
        $stmt->execute();
77
78
        self::assertEquals(1, $stmt->rowCount());
79
    }
80
81
    public function testPrepareWithDbalTypes() : void
82
    {
83
        $sql  = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)';
84
        $stmt = $this->connection->prepare($sql);
85
86
        $stmt->bindValue(1, 1, ParameterType::INTEGER);
87
        $stmt->bindValue(2, 'foo', ParameterType::STRING);
88
        $stmt->execute();
89
90
        self::assertEquals(1, $stmt->rowCount());
91
    }
92
93
    public function testPrepareWithDbalTypeNames() : void
94
    {
95
        $sql  = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)';
96
        $stmt = $this->connection->prepare($sql);
97
98
        $stmt->bindValue(1, 1, ParameterType::INTEGER);
99
        $stmt->bindValue(2, 'foo', ParameterType::STRING);
100
        $stmt->execute();
101
102
        self::assertEquals(1, $stmt->rowCount());
103
    }
104
105
    public function insertRows() : void
106
    {
107
        self::assertEquals(1, $this->connection->insert('write_table', ['test_int' => 1, 'test_string' => 'foo']));
108
        self::assertEquals(1, $this->connection->insert('write_table', ['test_int' => 2, 'test_string' => 'bar']));
109
    }
110
111
    public function testInsert() : void
112
    {
113
        $this->insertRows();
114
    }
115
116
    public function testDelete() : void
117
    {
118
        $this->insertRows();
119
120
        self::assertEquals(1, $this->connection->delete('write_table', ['test_int' => 2]));
121
        self::assertCount(1, $this->connection->fetchAll('SELECT * FROM write_table'));
122
123
        self::assertEquals(1, $this->connection->delete('write_table', ['test_int' => 1]));
124
        self::assertCount(0, $this->connection->fetchAll('SELECT * FROM write_table'));
125
    }
126
127
    public function testUpdate() : void
128
    {
129
        $this->insertRows();
130
131
        self::assertEquals(1, $this->connection->update('write_table', ['test_string' => 'bar'], ['test_string' => 'foo']));
132
        self::assertEquals(2, $this->connection->update('write_table', ['test_string' => 'baz'], ['test_string' => 'bar']));
133
        self::assertEquals(0, $this->connection->update('write_table', ['test_string' => 'baz'], ['test_string' => 'bar']));
134
    }
135
136
    public function testLastInsertId() : void
137
    {
138
        if (! $this->connection->getDatabasePlatform()->prefersIdentityColumns()) {
139
            self::markTestSkipped('Test only works on platforms with identity columns.');
140
        }
141
142
        self::assertEquals(1, $this->connection->insert('write_table', ['test_int' => 2, 'test_string' => 'bar']));
143
        $num = $this->lastInsertId();
144
145
        self::assertGreaterThan(0, $num, 'LastInsertId() should be non-negative number.');
146
    }
147
148
    public function testLastInsertIdSequence() : void
149
    {
150
        if (! $this->connection->getDatabasePlatform()->supportsSequences()) {
151
            self::markTestSkipped('Test only works on platforms with sequences.');
152
        }
153
154
        $sequence = new Sequence('write_table_id_seq');
155
        try {
156
            $this->connection->getSchemaManager()->createSequence($sequence);
157
        } catch (Throwable $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
158
        }
159
160
        $sequences = $this->connection->getSchemaManager()->listSequences();
161
        self::assertCount(1, array_filter($sequences, static function ($sequence) : bool {
162
            return strtolower($sequence->getName()) === 'write_table_id_seq';
163
        }));
164
165
        $stmt            = $this->connection->query($this->connection->getDatabasePlatform()->getSequenceNextValSQL('write_table_id_seq'));
166
        $nextSequenceVal = $stmt->fetchColumn();
167
168
        $lastInsertId = $this->lastInsertId('write_table_id_seq');
169
170
        self::assertGreaterThan(0, $lastInsertId);
171
        self::assertEquals($nextSequenceVal, $lastInsertId);
172
    }
173
174
    public function testLastInsertIdNoSequenceGiven() : void
175
    {
176
        if (! $this->connection->getDatabasePlatform()->supportsSequences() || $this->connection->getDatabasePlatform()->supportsIdentityColumns()) {
177
            self::markTestSkipped("Test only works consistently on platforms that support sequences and don't support identity columns.");
178
        }
179
180
        $this->expectException(DriverException::class);
181
        $this->lastInsertId();
182
    }
183
184
    /**
185
     * @group DBAL-445
186
     */
187
    public function testInsertWithKeyValueTypes() : void
188
    {
189
        $testString = new DateTime('2013-04-14 10:10:10');
190
191
        $this->connection->insert(
192
            'write_table',
193
            ['test_int' => '30', 'test_string' => $testString],
194
            ['test_string' => 'datetime', 'test_int' => 'integer']
195
        );
196
197
        $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30');
198
199
        self::assertEquals($testString->format($this->connection->getDatabasePlatform()->getDateTimeFormatString()), $data);
200
    }
201
202
    /**
203
     * @group DBAL-445
204
     */
205
    public function testUpdateWithKeyValueTypes() : void
206
    {
207
        $testString = new DateTime('2013-04-14 10:10:10');
208
209
        $this->connection->insert(
210
            'write_table',
211
            ['test_int' => '30', 'test_string' => $testString],
212
            ['test_string' => 'datetime', 'test_int' => 'integer']
213
        );
214
215
        $testString = new DateTime('2013-04-15 10:10:10');
216
217
        $this->connection->update(
218
            'write_table',
219
            ['test_string' => $testString],
220
            ['test_int' => '30'],
221
            ['test_string' => 'datetime', 'test_int' => 'integer']
222
        );
223
224
        $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30');
225
226
        self::assertEquals($testString->format($this->connection->getDatabasePlatform()->getDateTimeFormatString()), $data);
227
    }
228
229
    /**
230
     * @group DBAL-445
231
     */
232
    public function testDeleteWithKeyValueTypes() : void
233
    {
234
        $val = new DateTime('2013-04-14 10:10:10');
235
        $this->connection->insert(
236
            'write_table',
237
            ['test_int' => '30', 'test_string' => $val],
238
            ['test_string' => 'datetime', 'test_int' => 'integer']
239
        );
240
241
        $this->connection->delete('write_table', ['test_int' => 30, 'test_string' => $val], ['test_string' => 'datetime', 'test_int' => 'integer']);
242
243
        $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30');
244
245
        self::assertFalse($data);
246
    }
247
248
    public function testEmptyIdentityInsert() : void
249
    {
250
        $platform = $this->connection->getDatabasePlatform();
251
252
        if (! ($platform->supportsIdentityColumns() || $platform->usesSequenceEmulatedIdentityColumns())) {
253
            self::markTestSkipped(
254
                'Test only works on platforms with identity columns or sequence emulated identity columns.'
255
            );
256
        }
257
258
        $table = new Table('test_empty_identity');
259
        $table->addColumn('id', 'integer', ['autoincrement' => true]);
260
        $table->setPrimaryKey(['id']);
261
262
        try {
263
            $this->connection->getSchemaManager()->dropTable($table->getQuotedName($platform));
264
        } catch (Throwable $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
265
        }
266
267
        foreach ($platform->getCreateTableSQL($table) as $sql) {
268
            $this->connection->exec($sql);
269
        }
270
271
        $seqName = $platform->usesSequenceEmulatedIdentityColumns()
272
            ? $platform->getIdentitySequenceName('test_empty_identity', 'id')
273
            : null;
274
275
        $sql = $platform->getEmptyIdentityInsertSQL('test_empty_identity', 'id');
276
277
        $this->connection->exec($sql);
278
279
        $firstId = $this->lastInsertId($seqName);
280
281
        $this->connection->exec($sql);
282
283
        $secondId = $this->lastInsertId($seqName);
284
285
        self::assertGreaterThan($firstId, $secondId);
286
    }
287
288
    /**
289
     * @group DBAL-2688
290
     */
291
    public function testUpdateWhereIsNull() : void
292
    {
293
        $this->connection->insert(
294
            'write_table',
295
            ['test_int' => '30', 'test_string' => null],
296
            ['test_string' => 'string', 'test_int' => 'integer']
297
        );
298
299
        $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30');
300
301
        self::assertCount(1, $data);
302
303
        $this->connection->update('write_table', ['test_int' => 10], ['test_string' => null], ['test_string' => 'string', 'test_int' => 'integer']);
304
305
        $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30');
306
307
        self::assertCount(0, $data);
308
    }
309
310
    public function testDeleteWhereIsNull() : void
311
    {
312
        $this->connection->insert(
313
            'write_table',
314
            ['test_int' => '30', 'test_string' => null],
315
            ['test_string' => 'string', 'test_int' => 'integer']
316
        );
317
318
        $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30');
319
320
        self::assertCount(1, $data);
321
322
        $this->connection->delete('write_table', ['test_string' => null], ['test_string' => 'string']);
323
324
        $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30');
325
326
        self::assertCount(0, $data);
327
    }
328
329
    /**
330
     * Returns the ID of the last inserted row or skips the test if the currently used driver
331
     * doesn't support this feature
332
     *
333
     * @throws DriverException
334
     */
335
    private function lastInsertId(?string $name = null) : string
336
    {
337
        try {
338
            return $this->connection->lastInsertId($name);
339
        } catch (DriverException $e) {
340
            if ($e->getSQLState() === 'IM001') {
341
                self::markTestSkipped($e->getMessage());
342
            }
343
344
            throw $e;
345
        }
346
    }
347
}
348