SqliteSchemaManagerTest.php 9.03 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\Tests\DBAL\Functional\Schema;

Sergei Morozov's avatar
Sergei Morozov committed
5
use Doctrine\DBAL\Driver\Connection;
6
use Doctrine\DBAL\Schema;
Sergei Morozov's avatar
Sergei Morozov committed
7
use Doctrine\DBAL\Schema\Table;
Sergei Morozov's avatar
Sergei Morozov committed
8
use Doctrine\DBAL\Types\BlobType;
9
use Doctrine\DBAL\Types\Type;
Sergei Morozov's avatar
Sergei Morozov committed
10
use SQLite3;
11 12 13 14
use function array_map;
use function dirname;
use function extension_loaded;
use function version_compare;
15

romanb's avatar
romanb committed
16
class SqliteSchemaManagerTest extends SchemaManagerFunctionalTestCase
17
{
romanb's avatar
romanb committed
18
    /**
19
     * SQLITE does not support databases.
20 21
     *
     * @expectedException \Doctrine\DBAL\DBALException
romanb's avatar
romanb committed
22
     */
23 24
    public function testListDatabases()
    {
Sergei Morozov's avatar
Sergei Morozov committed
25
        $this->schemaManager->listDatabases();
26 27 28 29
    }

    public function testCreateAndDropDatabase()
    {
Sergei Morozov's avatar
Sergei Morozov committed
30
        $path = dirname(__FILE__) . '/test_create_and_drop_sqlite_database.sqlite';
31

Sergei Morozov's avatar
Sergei Morozov committed
32
        $this->schemaManager->createDatabase($path);
Gabriel Caruso's avatar
Gabriel Caruso committed
33
        self::assertFileExists($path);
Sergei Morozov's avatar
Sergei Morozov committed
34
        $this->schemaManager->dropDatabase($path);
Gabriel Caruso's avatar
Gabriel Caruso committed
35
        self::assertFileNotExists($path);
jwage's avatar
jwage committed
36
    }
37

38 39 40 41 42
    /**
     * @group DBAL-1220
     */
    public function testDropsDatabaseWithActiveConnections()
    {
Sergei Morozov's avatar
Sergei Morozov committed
43
        $this->schemaManager->dropAndCreateDatabase('test_drop_database');
44

45
        self::assertFileExists('test_drop_database');
46

Sergei Morozov's avatar
Sergei Morozov committed
47
        $params           = $this->connection->getParams();
48 49
        $params['dbname'] = 'test_drop_database';

Sergei Morozov's avatar
Sergei Morozov committed
50
        $user     = $params['user'] ?? null;
51
        $password = $params['password'] ?? null;
52

Sergei Morozov's avatar
Sergei Morozov committed
53
        $connection = $this->connection->getDriver()->connect($params, $user, $password);
54

Sergei Morozov's avatar
Sergei Morozov committed
55
        self::assertInstanceOf(Connection::class, $connection);
56

Sergei Morozov's avatar
Sergei Morozov committed
57
        $this->schemaManager->dropDatabase('test_drop_database');
58

59
        self::assertFileNotExists('test_drop_database');
60 61 62 63

        unset($connection);
    }

64 65
    public function testRenameTable()
    {
66
        $this->createTestTable('oldname');
Sergei Morozov's avatar
Sergei Morozov committed
67
        $this->schemaManager->renameTable('oldname', 'newname');
68

Sergei Morozov's avatar
Sergei Morozov committed
69
        $tables = $this->schemaManager->listTableNames();
70 71
        self::assertContains('newname', $tables);
        self::assertNotContains('oldname', $tables);
72
    }
73

74
    public function createListTableColumns()
75
    {
76 77 78 79
        $table = parent::createListTableColumns();
        $table->getColumn('id')->setAutoincrement(true);

        return $table;
80
    }
81 82 83

    public function testListForeignKeysFromExistingDatabase()
    {
Sergei Morozov's avatar
Sergei Morozov committed
84
        $this->connection->exec(<<<EOS
85 86 87 88 89 90 91 92 93 94
CREATE TABLE user (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    page INTEGER CONSTRAINT FK_1 REFERENCES page (key) DEFERRABLE INITIALLY DEFERRED,
    parent INTEGER REFERENCES user(id) ON DELETE CASCADE,
    log INTEGER,
    CONSTRAINT FK_3 FOREIGN KEY (log) REFERENCES log ON UPDATE SET NULL NOT DEFERRABLE
)
EOS
        );

Sergei Morozov's avatar
Sergei Morozov committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
        $expected = [
            new Schema\ForeignKeyConstraint(
                ['log'],
                'log',
                [null],
                'FK_3',
                ['onUpdate' => 'SET NULL', 'onDelete' => 'NO ACTION', 'deferrable' => false, 'deferred' => false]
            ),
            new Schema\ForeignKeyConstraint(
                ['parent'],
                'user',
                ['id'],
                '1',
                ['onUpdate' => 'NO ACTION', 'onDelete' => 'CASCADE', 'deferrable' => false, 'deferred' => false]
            ),
            new Schema\ForeignKeyConstraint(
                ['page'],
                'page',
                ['key'],
                'FK_1',
                ['onUpdate' => 'NO ACTION', 'onDelete' => 'NO ACTION', 'deferrable' => true, 'deferred' => true]
            ),
        ];
118

Sergei Morozov's avatar
Sergei Morozov committed
119
        self::assertEquals($expected, $this->schemaManager->listTableForeignKeys('user'));
120
    }
Steve Müller's avatar
Steve Müller committed
121

122 123 124 125 126 127 128
    public function testColumnCollation()
    {
        $table = new Schema\Table('test_collation');
        $table->addColumn('id', 'integer');
        $table->addColumn('text', 'text');
        $table->addColumn('foo', 'text')->setPlatformOption('collation', 'BINARY');
        $table->addColumn('bar', 'text')->setPlatformOption('collation', 'NOCASE');
Sergei Morozov's avatar
Sergei Morozov committed
129
        $this->schemaManager->dropAndCreateTable($table);
130

Sergei Morozov's avatar
Sergei Morozov committed
131
        $columns = $this->schemaManager->listTableColumns('test_collation');
132

133 134 135 136
        self::assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions());
        self::assertEquals('BINARY', $columns['text']->getPlatformOption('collation'));
        self::assertEquals('BINARY', $columns['foo']->getPlatformOption('collation'));
        self::assertEquals('NOCASE', $columns['bar']->getPlatformOption('collation'));
137 138
    }

Steve Müller's avatar
Steve Müller committed
139 140 141 142
    public function testListTableWithBinary()
    {
        $tableName = 'test_binary_table';

Sergei Morozov's avatar
Sergei Morozov committed
143
        $table = new Table($tableName);
Steve Müller's avatar
Steve Müller committed
144
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
145 146 147
        $table->addColumn('column_varbinary', 'binary', []);
        $table->addColumn('column_binary', 'binary', ['fixed' => true]);
        $table->setPrimaryKey(['id']);
Steve Müller's avatar
Steve Müller committed
148

Sergei Morozov's avatar
Sergei Morozov committed
149
        $this->schemaManager->createTable($table);
Steve Müller's avatar
Steve Müller committed
150

Sergei Morozov's avatar
Sergei Morozov committed
151
        $table = $this->schemaManager->listTableDetails($tableName);
Steve Müller's avatar
Steve Müller committed
152

Sergei Morozov's avatar
Sergei Morozov committed
153
        self::assertInstanceOf(BlobType::class, $table->getColumn('column_varbinary')->getType());
154
        self::assertFalse($table->getColumn('column_varbinary')->getFixed());
Steve Müller's avatar
Steve Müller committed
155

Sergei Morozov's avatar
Sergei Morozov committed
156
        self::assertInstanceOf(BlobType::class, $table->getColumn('column_binary')->getType());
157
        self::assertFalse($table->getColumn('column_binary')->getFixed());
Steve Müller's avatar
Steve Müller committed
158
    }
159 160 161

    public function testNonDefaultPKOrder()
    {
Sergei Morozov's avatar
Sergei Morozov committed
162
        if (! extension_loaded('sqlite3')) {
163 164 165
            $this->markTestSkipped('This test requires the SQLite3 extension.');
        }

Sergei Morozov's avatar
Sergei Morozov committed
166 167
        $version = SQLite3::version();
        if (version_compare($version['versionString'], '3.7.16', '<')) {
168 169
            $this->markTestSkipped('This version of sqlite doesn\'t return the order of the Primary Key.');
        }
Sergei Morozov's avatar
Sergei Morozov committed
170
        $this->connection->exec(<<<EOS
171 172 173 174 175 176 177 178
CREATE TABLE non_default_pk_order (
    id INTEGER,
    other_id INTEGER,
    PRIMARY KEY(other_id, id)
)
EOS
        );

Sergei Morozov's avatar
Sergei Morozov committed
179
        $tableIndexes = $this->schemaManager->listTableIndexes('non_default_pk_order');
180

Gabriel Caruso's avatar
Gabriel Caruso committed
181
         self::assertCount(1, $tableIndexes);
182

183
        self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.');
Sergei Morozov's avatar
Sergei Morozov committed
184
        self::assertEquals(['other_id', 'id'], array_map('strtolower', $tableIndexes['primary']->getColumns()));
185
    }
186

187 188 189 190 191 192 193 194 195 196 197 198
    /**
     * @group DBAL-1779
     */
    public function testListTableColumnsWithWhitespacesInTypeDeclarations()
    {
        $sql = <<<SQL
CREATE TABLE dbal_1779 (
    foo VARCHAR (64) ,
    bar TEXT (100)
)
SQL;

Sergei Morozov's avatar
Sergei Morozov committed
199
        $this->connection->exec($sql);
200

Sergei Morozov's avatar
Sergei Morozov committed
201
        $columns = $this->schemaManager->listTableColumns('dbal_1779');
202

203
        self::assertCount(2, $columns);
204

205 206
        self::assertArrayHasKey('foo', $columns);
        self::assertArrayHasKey('bar', $columns);
207

208 209
        self::assertSame(Type::getType(Type::STRING), $columns['foo']->getType());
        self::assertSame(Type::getType(Type::TEXT), $columns['bar']->getType());
210

211 212
        self::assertSame(64, $columns['foo']->getLength());
        self::assertSame(100, $columns['bar']->getLength());
213 214
    }

215 216 217 218 219 220 221 222
    /**
     * @dataProvider getDiffListIntegerAutoincrementTableColumnsData
     * @group DBAL-924
     */
    public function testDiffListIntegerAutoincrementTableColumns($integerType, $unsigned, $expectedComparatorDiff)
    {
        $tableName = 'test_int_autoincrement_table';

Sergei Morozov's avatar
Sergei Morozov committed
223 224 225
        $offlineTable = new Table($tableName);
        $offlineTable->addColumn('id', $integerType, ['autoincrement' => true, 'unsigned' => $unsigned]);
        $offlineTable->setPrimaryKey(['id']);
226

Sergei Morozov's avatar
Sergei Morozov committed
227
        $this->schemaManager->dropAndCreateTable($offlineTable);
228

Sergei Morozov's avatar
Sergei Morozov committed
229
        $onlineTable = $this->schemaManager->listTableDetails($tableName);
Sergei Morozov's avatar
Sergei Morozov committed
230 231
        $comparator  = new Schema\Comparator();
        $diff        = $comparator->diffTable($offlineTable, $onlineTable);
232 233

        if ($expectedComparatorDiff) {
Sergei Morozov's avatar
Sergei Morozov committed
234
            self::assertEmpty($this->schemaManager->getDatabasePlatform()->getAlterTableSQL($diff));
235
        } else {
236
            self::assertFalse($diff);
237 238 239 240
        }
    }

    /**
Sergei Morozov's avatar
Sergei Morozov committed
241
     * @return mixed[][]
242 243 244
     */
    public function getDiffListIntegerAutoincrementTableColumnsData()
    {
Sergei Morozov's avatar
Sergei Morozov committed
245 246 247 248 249 250 251 252
        return [
            ['smallint', false, true],
            ['smallint', true, true],
            ['integer', false, false],
            ['integer', true, true],
            ['bigint', false, true],
            ['bigint', true, true],
        ];
253
    }
254 255 256 257 258 259 260 261 262 263

    /**
     * @group DBAL-2921
     */
    public function testPrimaryKeyNoAutoIncrement()
    {
        $table = new Schema\Table('test_pk_auto_increment');
        $table->addColumn('id', 'integer');
        $table->addColumn('text', 'text');
        $table->setPrimaryKey(['id']);
Sergei Morozov's avatar
Sergei Morozov committed
264
        $this->schemaManager->dropAndCreateTable($table);
265

Sergei Morozov's avatar
Sergei Morozov committed
266
        $this->connection->insert('test_pk_auto_increment', ['text' => '1']);
267

Sergei Morozov's avatar
Sergei Morozov committed
268
        $this->connection->query('DELETE FROM test_pk_auto_increment');
269

Sergei Morozov's avatar
Sergei Morozov committed
270
        $this->connection->insert('test_pk_auto_increment', ['text' => '2']);
271

Sergei Morozov's avatar
Sergei Morozov committed
272
        $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = "2"');
273
        $query->execute();
Timo Bakx's avatar
Timo Bakx committed
274
        $lastUsedIdAfterDelete = (int) $query->fetchColumn();
275 276 277 278

        // with an empty table, non autoincrement rowid is always 1
        $this->assertEquals(1, $lastUsedIdAfterDelete);
    }
279
}