DB2PlatformTest.php 27.1 KB
Newer Older
1 2 3 4 5 6
<?php

namespace Doctrine\Tests\DBAL\Platforms;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\DB2Platform;
7 8
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ColumnDiff;
9 10
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table;
11 12
use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types\Type;
13 14 15

class DB2PlatformTest extends AbstractPlatformTestCase
{
Sergei Morozov's avatar
Sergei Morozov committed
16
    /** @var DB2Platform */
Sergei Morozov's avatar
Sergei Morozov committed
17
    protected $platform;
18 19 20 21 22 23 24 25

    public function createPlatform()
    {
        return new DB2Platform();
    }

    public function getGenerateAlterTableSql()
    {
Sergei Morozov's avatar
Sergei Morozov committed
26 27 28
        return [
            'ALTER TABLE mytable ALTER COLUMN baz SET DATA TYPE VARCHAR(255)',
            'ALTER TABLE mytable ALTER COLUMN baz SET NOT NULL',
29
            "ALTER TABLE mytable ALTER COLUMN baz SET DEFAULT 'def'",
Sergei Morozov's avatar
Sergei Morozov committed
30 31
            'ALTER TABLE mytable ALTER COLUMN bloo SET DATA TYPE SMALLINT',
            'ALTER TABLE mytable ALTER COLUMN bloo SET NOT NULL',
32
            "ALTER TABLE mytable ALTER COLUMN bloo SET DEFAULT '0'",
Sergei Morozov's avatar
Sergei Morozov committed
33 34 35
            'ALTER TABLE mytable ' .
            'ADD COLUMN quota INTEGER DEFAULT NULL ' .
            'DROP COLUMN foo',
36 37
            "CALL SYSPROC.ADMIN_CMD ('REORG TABLE mytable')",
            'RENAME TABLE mytable TO userlist',
Sergei Morozov's avatar
Sergei Morozov committed
38
        ];
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
    }

    public function getGenerateForeignKeySql()
    {
        return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)';
    }

    public function getGenerateIndexSql()
    {
        return 'CREATE INDEX my_idx ON mytable (user_name, last_login)';
    }

    public function getGenerateTableSql()
    {
        return 'CREATE TABLE test (id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))';
    }

    public function getGenerateTableWithMultiColumnUniqueIndexSql()
    {
Sergei Morozov's avatar
Sergei Morozov committed
58
        return [
59
            'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL)',
Sergei Morozov's avatar
Sergei Morozov committed
60 61
            'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)',
        ];
62 63 64 65 66 67 68 69 70
    }

    public function getGenerateUniqueIndexSql()
    {
        return 'CREATE UNIQUE INDEX index_name ON test (test, test2)';
    }

    protected function getQuotedColumnInForeignKeySQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
71
        return [
72 73 74 75
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL)',
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar")',
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES foo ("create", bar, "foo-bar")',
            'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ("create", foo, "bar") REFERENCES "foo-bar" ("create", bar, "foo-bar")',
Sergei Morozov's avatar
Sergei Morozov committed
76
        ];
77 78 79 80
    }

    protected function getQuotedColumnInIndexSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
81
        return [
82
            'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)',
Sergei Morozov's avatar
Sergei Morozov committed
83 84
            'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")',
        ];
85 86
    }

Markus Fasselt's avatar
Markus Fasselt committed
87 88
    protected function getQuotedNameInIndexSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
89
        return [
Markus Fasselt's avatar
Markus Fasselt committed
90 91
            'CREATE TABLE test (column1 VARCHAR(255) NOT NULL)',
            'CREATE INDEX "key" ON test (column1)',
Sergei Morozov's avatar
Sergei Morozov committed
92
        ];
Markus Fasselt's avatar
Markus Fasselt committed
93 94
    }

95 96
    protected function getQuotedColumnInPrimaryKeySQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
97
        return ['CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))'];
98 99 100 101 102 103 104
    }

    protected function getBitAndComparisonExpressionSql($value1, $value2)
    {
        return 'BITAND(' . $value1 . ', ' . $value2 . ')';
    }

Sergei Morozov's avatar
Sergei Morozov committed
105
    protected function getBitOrComparisonExpressionSql($value1, $value2)
106 107 108 109 110 111
    {
        return 'BITOR(' . $value1 . ', ' . $value2 . ')';
    }

    public function getCreateTableColumnCommentsSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
112 113
        return [
            'CREATE TABLE test (id INTEGER NOT NULL, PRIMARY KEY(id))',
114
            "COMMENT ON COLUMN test.id IS 'This is a comment'",
Sergei Morozov's avatar
Sergei Morozov committed
115
        ];
116 117 118 119
    }

    public function getAlterTableColumnCommentsSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
120 121 122
        return [
            'ALTER TABLE mytable ' .
            'ADD COLUMN quota INTEGER NOT NULL WITH DEFAULT',
123 124 125 126
            "CALL SYSPROC.ADMIN_CMD ('REORG TABLE mytable')",
            "COMMENT ON COLUMN mytable.quota IS 'A comment'",
            "COMMENT ON COLUMN mytable.foo IS ''",
            "COMMENT ON COLUMN mytable.baz IS 'B comment'",
Sergei Morozov's avatar
Sergei Morozov committed
127
        ];
128 129 130 131
    }

    public function getCreateTableColumnTypeCommentsSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
132
        return [
133
            'CREATE TABLE test (id INTEGER NOT NULL, "data" CLOB(1M) NOT NULL, PRIMARY KEY(id))',
134
            'COMMENT ON COLUMN test."data" IS \'(DC2Type:array)\'',
Sergei Morozov's avatar
Sergei Morozov committed
135
        ];
136 137 138 139
    }

    public function testHasCorrectPlatformName()
    {
Sergei Morozov's avatar
Sergei Morozov committed
140
        self::assertEquals('db2', $this->platform->getName());
141 142 143 144 145 146
    }

    public function testGeneratesCreateTableSQLWithCommonIndexes()
    {
        $table = new Table('test');
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
147 148 149 150
        $table->addColumn('name', 'string', ['length' => 50]);
        $table->setPrimaryKey(['id']);
        $table->addIndex(['name']);
        $table->addIndex(['id', 'name'], 'composite_idx');
151

152
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
153
            [
154 155
                'CREATE TABLE test (id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))',
                'CREATE INDEX IDX_D87F7E0C5E237E06 ON test (name)',
Sergei Morozov's avatar
Sergei Morozov committed
156 157
                'CREATE INDEX composite_idx ON test (id, name)',
            ],
Sergei Morozov's avatar
Sergei Morozov committed
158
            $this->platform->getCreateTableSQL($table)
159 160 161 162 163 164 165 166 167
        );
    }

    public function testGeneratesCreateTableSQLWithForeignKeyConstraints()
    {
        $table = new Table('test');
        $table->addColumn('id', 'integer');
        $table->addColumn('fk_1', 'integer');
        $table->addColumn('fk_2', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
168 169
        $table->setPrimaryKey(['id']);
        $table->addForeignKeyConstraint('foreign_table', ['fk_1', 'fk_2'], ['pk_1', 'pk_2']);
170 171
        $table->addForeignKeyConstraint(
            'foreign_table2',
Sergei Morozov's avatar
Sergei Morozov committed
172 173 174
            ['fk_1', 'fk_2'],
            ['pk_1', 'pk_2'],
            [],
175 176 177
            'named_fk'
        );

178
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
179
            [
180 181 182
                'CREATE TABLE test (id INTEGER NOT NULL, fk_1 INTEGER NOT NULL, fk_2 INTEGER NOT NULL)',
                'ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C177612A38E7F4319 FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table (pk_1, pk_2)',
                'ALTER TABLE test ADD CONSTRAINT named_fk FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table2 (pk_1, pk_2)',
Sergei Morozov's avatar
Sergei Morozov committed
183
            ],
Sergei Morozov's avatar
Sergei Morozov committed
184
            $this->platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS)
185 186 187 188 189 190 191
        );
    }

    public function testGeneratesCreateTableSQLWithCheckConstraints()
    {
        $table = new Table('test');
        $table->addColumn('id', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
192 193 194
        $table->addColumn('check_max', 'integer', ['platformOptions' => ['max' => 10]]);
        $table->addColumn('check_min', 'integer', ['platformOptions' => ['min' => 10]]);
        $table->setPrimaryKey(['id']);
195

196
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
197
            ['CREATE TABLE test (id INTEGER NOT NULL, check_max INTEGER NOT NULL, check_min INTEGER NOT NULL, PRIMARY KEY(id), CHECK (check_max <= 10), CHECK (check_min >= 10))'],
Sergei Morozov's avatar
Sergei Morozov committed
198
            $this->platform->getCreateTableSQL($table)
199 200 201 202 203
        );
    }

    public function testGeneratesColumnTypesDeclarationSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
204
        $fullColumnDef = [
205 206 207
            'length' => 10,
            'fixed' => true,
            'unsigned' => true,
Sergei Morozov's avatar
Sergei Morozov committed
208 209
            'autoincrement' => true,
        ];
210

Sergei Morozov's avatar
Sergei Morozov committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
        self::assertEquals('VARCHAR(255)', $this->platform->getVarcharTypeDeclarationSQL([]));
        self::assertEquals('VARCHAR(10)', $this->platform->getVarcharTypeDeclarationSQL(['length' => 10]));
        self::assertEquals('CHAR(254)', $this->platform->getVarcharTypeDeclarationSQL(['fixed' => true]));
        self::assertEquals('CHAR(10)', $this->platform->getVarcharTypeDeclarationSQL($fullColumnDef));

        self::assertEquals('SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL([]));
        self::assertEquals('SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL(['unsigned' => true]));
        self::assertEquals('SMALLINT GENERATED BY DEFAULT AS IDENTITY', $this->platform->getSmallIntTypeDeclarationSQL($fullColumnDef));
        self::assertEquals('INTEGER', $this->platform->getIntegerTypeDeclarationSQL([]));
        self::assertEquals('INTEGER', $this->platform->getIntegerTypeDeclarationSQL(['unsigned' => true]));
        self::assertEquals('INTEGER GENERATED BY DEFAULT AS IDENTITY', $this->platform->getIntegerTypeDeclarationSQL($fullColumnDef));
        self::assertEquals('BIGINT', $this->platform->getBigIntTypeDeclarationSQL([]));
        self::assertEquals('BIGINT', $this->platform->getBigIntTypeDeclarationSQL(['unsigned' => true]));
        self::assertEquals('BIGINT GENERATED BY DEFAULT AS IDENTITY', $this->platform->getBigIntTypeDeclarationSQL($fullColumnDef));
        self::assertEquals('BLOB(1M)', $this->platform->getBlobTypeDeclarationSQL($fullColumnDef));
        self::assertEquals('SMALLINT', $this->platform->getBooleanTypeDeclarationSQL($fullColumnDef));
        self::assertEquals('CLOB(1M)', $this->platform->getClobTypeDeclarationSQL($fullColumnDef));
        self::assertEquals('DATE', $this->platform->getDateTypeDeclarationSQL($fullColumnDef));
        self::assertEquals('TIMESTAMP(0) WITH DEFAULT', $this->platform->getDateTimeTypeDeclarationSQL(['version' => true]));
        self::assertEquals('TIMESTAMP(0)', $this->platform->getDateTimeTypeDeclarationSQL($fullColumnDef));
        self::assertEquals('TIME', $this->platform->getTimeTypeDeclarationSQL($fullColumnDef));
232 233 234 235
    }

    public function testInitializesDoctrineTypeMappings()
    {
Sergei Morozov's avatar
Sergei Morozov committed
236
        $this->platform->initializeDoctrineTypeMappings();
237

Sergei Morozov's avatar
Sergei Morozov committed
238 239
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('smallint'));
        self::assertSame('smallint', $this->platform->getDoctrineTypeMapping('smallint'));
240

Sergei Morozov's avatar
Sergei Morozov committed
241 242
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('bigint'));
        self::assertSame('bigint', $this->platform->getDoctrineTypeMapping('bigint'));
243

Sergei Morozov's avatar
Sergei Morozov committed
244 245
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('integer'));
        self::assertSame('integer', $this->platform->getDoctrineTypeMapping('integer'));
246

Sergei Morozov's avatar
Sergei Morozov committed
247 248
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('time'));
        self::assertSame('time', $this->platform->getDoctrineTypeMapping('time'));
249

Sergei Morozov's avatar
Sergei Morozov committed
250 251
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('date'));
        self::assertSame('date', $this->platform->getDoctrineTypeMapping('date'));
252

Sergei Morozov's avatar
Sergei Morozov committed
253 254
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('varchar'));
        self::assertSame('string', $this->platform->getDoctrineTypeMapping('varchar'));
255

Sergei Morozov's avatar
Sergei Morozov committed
256 257
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('character'));
        self::assertSame('string', $this->platform->getDoctrineTypeMapping('character'));
258

Sergei Morozov's avatar
Sergei Morozov committed
259 260
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('clob'));
        self::assertSame('text', $this->platform->getDoctrineTypeMapping('clob'));
261

Sergei Morozov's avatar
Sergei Morozov committed
262 263
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('blob'));
        self::assertSame('blob', $this->platform->getDoctrineTypeMapping('blob'));
264

Sergei Morozov's avatar
Sergei Morozov committed
265 266
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('decimal'));
        self::assertSame('decimal', $this->platform->getDoctrineTypeMapping('decimal'));
267

Sergei Morozov's avatar
Sergei Morozov committed
268 269
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('double'));
        self::assertSame('float', $this->platform->getDoctrineTypeMapping('double'));
270

Sergei Morozov's avatar
Sergei Morozov committed
271 272
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('real'));
        self::assertSame('float', $this->platform->getDoctrineTypeMapping('real'));
273

Sergei Morozov's avatar
Sergei Morozov committed
274 275
        self::assertTrue($this->platform->hasDoctrineTypeMappingFor('timestamp'));
        self::assertSame('datetime', $this->platform->getDoctrineTypeMapping('timestamp'));
276 277
    }

278 279 280 281
    public function getIsCommentedDoctrineType()
    {
        $data = parent::getIsCommentedDoctrineType();

Sergei Morozov's avatar
Sergei Morozov committed
282
        $data[Type::BOOLEAN] = [Type::getType(Type::BOOLEAN), true];
283 284 285 286

        return $data;
    }

287 288
    public function testGeneratesDDLSnippets()
    {
Sergei Morozov's avatar
Sergei Morozov committed
289 290 291 292 293
        self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar'));
        self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar'));
        self::assertEquals('DECLARE GLOBAL TEMPORARY TABLE', $this->platform->getCreateTemporaryTableSnippetSQL());
        self::assertEquals('TRUNCATE foobar IMMEDIATE', $this->platform->getTruncateTableSQL('foobar'));
        self::assertEquals('TRUNCATE foobar IMMEDIATE', $this->platform->getTruncateTableSQL('foobar'), true);
294 295

        $viewSql = 'SELECT * FROM footable';
Sergei Morozov's avatar
Sergei Morozov committed
296 297
        self::assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->platform->getCreateViewSQL('fooview', $viewSql));
        self::assertEquals('DROP VIEW fooview', $this->platform->getDropViewSQL('fooview'));
298 299 300 301
    }

    public function testGeneratesCreateUnnamedPrimaryKeySQL()
    {
302
        self::assertEquals(
303
            'ALTER TABLE foo ADD PRIMARY KEY (a, b)',
Sergei Morozov's avatar
Sergei Morozov committed
304
            $this->platform->getCreatePrimaryKeySQL(
Sergei Morozov's avatar
Sergei Morozov committed
305
                new Index('any_pk_name', ['a', 'b'], true, true),
306 307 308 309 310 311 312
                'foo'
            )
        );
    }

    public function testGeneratesSQLSnippets()
    {
Sergei Morozov's avatar
Sergei Morozov committed
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
        self::assertEquals('CURRENT DATE', $this->platform->getCurrentDateSQL());
        self::assertEquals('CURRENT TIME', $this->platform->getCurrentTimeSQL());
        self::assertEquals('CURRENT TIMESTAMP', $this->platform->getCurrentTimestampSQL());
        self::assertEquals("'1987/05/02' + 4 DAY", $this->platform->getDateAddDaysExpression("'1987/05/02'", 4));
        self::assertEquals("'1987/05/02' + 12 HOUR", $this->platform->getDateAddHourExpression("'1987/05/02'", 12));
        self::assertEquals("'1987/05/02' + 2 MINUTE", $this->platform->getDateAddMinutesExpression("'1987/05/02'", 2));
        self::assertEquals("'1987/05/02' + 102 MONTH", $this->platform->getDateAddMonthExpression("'1987/05/02'", 102));
        self::assertEquals("'1987/05/02' + 15 MONTH", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5));
        self::assertEquals("'1987/05/02' + 1 SECOND", $this->platform->getDateAddSecondsExpression("'1987/05/02'", 1));
        self::assertEquals("'1987/05/02' + 21 DAY", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3));
        self::assertEquals("'1987/05/02' + 10 YEAR", $this->platform->getDateAddYearsExpression("'1987/05/02'", 10));
        self::assertEquals("DAYS('1987/05/02') - DAYS('1987/04/01')", $this->platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'"));
        self::assertEquals("'1987/05/02' - 4 DAY", $this->platform->getDateSubDaysExpression("'1987/05/02'", 4));
        self::assertEquals("'1987/05/02' - 12 HOUR", $this->platform->getDateSubHourExpression("'1987/05/02'", 12));
        self::assertEquals("'1987/05/02' - 2 MINUTE", $this->platform->getDateSubMinutesExpression("'1987/05/02'", 2));
        self::assertEquals("'1987/05/02' - 102 MONTH", $this->platform->getDateSubMonthExpression("'1987/05/02'", 102));
        self::assertEquals("'1987/05/02' - 15 MONTH", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5));
        self::assertEquals("'1987/05/02' - 1 SECOND", $this->platform->getDateSubSecondsExpression("'1987/05/02'", 1));
        self::assertEquals("'1987/05/02' - 21 DAY", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3));
        self::assertEquals("'1987/05/02' - 10 YEAR", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10));
        self::assertEquals(' WITH RR USE AND KEEP UPDATE LOCKS', $this->platform->getForUpdateSQL());
        self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column'));
        self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column'));
        self::assertEquals('LOCATE(substring_column, string_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1));
        self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', 5));
        self::assertEquals('SUBSTR(column, 5, 2)', $this->platform->getSubstringExpression('column', 5, 2));
339 340 341 342
    }

    public function testModifiesLimitQuery()
    {
343
        self::assertEquals(
344
            'SELECT * FROM user',
Sergei Morozov's avatar
Sergei Morozov committed
345
            $this->platform->modifyLimitQuery('SELECT * FROM user', null, null)
346 347
        );

348
        self::assertEquals(
349
            'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM <= 10',
Sergei Morozov's avatar
Sergei Morozov committed
350
            $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0)
351 352
        );

353
        self::assertEquals(
354
            'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM <= 10',
Sergei Morozov's avatar
Sergei Morozov committed
355
            $this->platform->modifyLimitQuery('SELECT * FROM user', 10)
356 357
        );

358
        self::assertEquals(
359
            'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM >= 6 AND db22.DC_ROWNUM <= 15',
Sergei Morozov's avatar
Sergei Morozov committed
360
            $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 5)
361
        );
362
        self::assertEquals(
363
            'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM >= 6 AND db22.DC_ROWNUM <= 5',
Sergei Morozov's avatar
Sergei Morozov committed
364
            $this->platform->modifyLimitQuery('SELECT * FROM user', 0, 5)
365 366 367 368 369
        );
    }

    public function testPrefersIdentityColumns()
    {
Sergei Morozov's avatar
Sergei Morozov committed
370
        self::assertTrue($this->platform->prefersIdentityColumns());
371 372 373 374
    }

    public function testSupportsIdentityColumns()
    {
Sergei Morozov's avatar
Sergei Morozov committed
375
        self::assertTrue($this->platform->supportsIdentityColumns());
376 377 378 379
    }

    public function testDoesNotSupportSavePoints()
    {
Sergei Morozov's avatar
Sergei Morozov committed
380
        self::assertFalse($this->platform->supportsSavepoints());
381 382 383 384
    }

    public function testDoesNotSupportReleasePoints()
    {
Sergei Morozov's avatar
Sergei Morozov committed
385
        self::assertFalse($this->platform->supportsReleaseSavepoints());
386 387 388 389
    }

    public function testDoesNotSupportCreateDropDatabase()
    {
Sergei Morozov's avatar
Sergei Morozov committed
390
        self::assertFalse($this->platform->supportsCreateDropDatabase());
391 392 393 394
    }

    public function testReturnsSQLResultCasing()
    {
Sergei Morozov's avatar
Sergei Morozov committed
395
        self::assertSame('COL', $this->platform->getSQLResultCasing('cOl'));
396
    }
397 398 399 400 401 402 403 404 405 406 407 408 409

    protected function getBinaryDefaultLength()
    {
        return 1;
    }

    protected function getBinaryMaxLength()
    {
        return 32704;
    }

    public function testReturnsBinaryTypeDeclarationSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
410 411 412
        self::assertSame('VARCHAR(1) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL([]));
        self::assertSame('VARCHAR(255) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0]));
        self::assertSame('VARCHAR(32704) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32704]));
413

Sergei Morozov's avatar
Sergei Morozov committed
414 415
        self::assertSame('CHAR(1) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true]));
        self::assertSame('CHAR(254) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0]));
416 417 418 419
    }

    /**
     * @group legacy
420
     * @expectedDeprecation Binary field length 32705 is greater than supported by the platform (32704). Reduce the field length or use a BLOB field instead.
421 422 423
     */
    public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
424 425
        self::assertSame('BLOB(1M)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32705]));
        self::assertSame('BLOB(1M)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32705]));
426
    }
427 428 429 430 431 432

    /**
     * @group DBAL-234
     */
    protected function getAlterTableRenameIndexSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
433
        return ['RENAME INDEX idx_foo TO idx_bar'];
434 435 436 437 438 439 440
    }

    /**
     * @group DBAL-234
     */
    protected function getQuotedAlterTableRenameIndexSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
441
        return [
442 443
            'RENAME INDEX "create" TO "select"',
            'RENAME INDEX "foo" TO "bar"',
Sergei Morozov's avatar
Sergei Morozov committed
444
        ];
445
    }
446 447 448 449 450 451

    /**
     * {@inheritdoc}
     */
    protected function getQuotedAlterTableRenameColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
452
        return ['ALTER TABLE mytable ' .
453 454 455 456 457 458 459 460
            'RENAME COLUMN unquoted1 TO unquoted ' .
            'RENAME COLUMN unquoted2 TO "where" ' .
            'RENAME COLUMN unquoted3 TO "foo" ' .
            'RENAME COLUMN "create" TO reserved_keyword ' .
            'RENAME COLUMN "table" TO "from" ' .
            'RENAME COLUMN "select" TO "bar" ' .
            'RENAME COLUMN quoted1 TO quoted ' .
            'RENAME COLUMN quoted2 TO "and" ' .
Sergei Morozov's avatar
Sergei Morozov committed
461 462
            'RENAME COLUMN quoted3 TO "baz"',
        ];
463
    }
464

465 466 467 468 469 470 471 472
    /**
     * {@inheritdoc}
     */
    protected function getQuotedAlterTableChangeColumnLengthSQL()
    {
        $this->markTestIncomplete('Not implemented yet');
    }

473 474 475 476 477
    /**
     * @group DBAL-807
     */
    protected function getAlterTableRenameIndexInSchemaSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
478
        return ['RENAME INDEX myschema.idx_foo TO idx_bar'];
479 480 481 482 483 484 485
    }

    /**
     * @group DBAL-807
     */
    protected function getQuotedAlterTableRenameIndexInSchemaSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
486
        return [
487 488
            'RENAME INDEX "schema"."create" TO "select"',
            'RENAME INDEX "schema"."foo" TO "bar"',
Sergei Morozov's avatar
Sergei Morozov committed
489
        ];
490
    }
491 492 493 494 495 496

    /**
     * @group DBAL-423
     */
    public function testReturnsGuidTypeDeclarationSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
497
        self::assertSame('CHAR(36)', $this->platform->getGuidTypeDeclarationSQL([]));
498
    }
499 500 501 502 503 504

    /**
     * {@inheritdoc}
     */
    public function getAlterTableRenameColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
505
        return ['ALTER TABLE foo RENAME COLUMN bar TO baz'];
506
    }
507 508 509 510 511 512

    /**
     * {@inheritdoc}
     */
    protected function getQuotesTableIdentifiersInAlterTableSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
513
        return [
514 515
            'ALTER TABLE "foo" DROP FOREIGN KEY fk1',
            'ALTER TABLE "foo" DROP FOREIGN KEY fk2',
516 517 518 519 520
            'ALTER TABLE "foo" ' .
            'ADD COLUMN bloo INTEGER NOT NULL WITH DEFAULT ' .
            'DROP COLUMN baz ' .
            'ALTER COLUMN bar DROP NOT NULL ' .
            'RENAME COLUMN id TO war',
521 522 523 524
            'CALL SYSPROC.ADMIN_CMD (\'REORG TABLE "foo"\')',
            'RENAME TABLE "foo" TO "table"',
            'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id)',
            'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id)',
Sergei Morozov's avatar
Sergei Morozov committed
525
        ];
526
    }
527 528 529 530 531 532

    /**
     * {@inheritdoc}
     */
    protected function getCommentOnColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
533
        return [
534 535 536
            'COMMENT ON COLUMN foo.bar IS \'comment\'',
            'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'',
            'COMMENT ON COLUMN "select"."from" IS \'comment\'',
Sergei Morozov's avatar
Sergei Morozov committed
537
        ];
538
    }
539 540 541 542 543 544 545

    /**
     * @group DBAL-944
     * @dataProvider getGeneratesAlterColumnSQL
     */
    public function testGeneratesAlterColumnSQL($changedProperty, Column $column, $expectedSQLClause = null)
    {
Sergei Morozov's avatar
Sergei Morozov committed
546 547 548
        $tableDiff                        = new TableDiff('foo');
        $tableDiff->fromTable             = new Table('foo');
        $tableDiff->changedColumns['bar'] = new ColumnDiff('bar', $column, [$changedProperty]);
549

Sergei Morozov's avatar
Sergei Morozov committed
550
        $expectedSQL = [];
551

Sergei Morozov's avatar
Sergei Morozov committed
552
        if ($expectedSQLClause !== null) {
553 554 555 556 557
            $expectedSQL[] = 'ALTER TABLE foo ALTER COLUMN bar ' . $expectedSQLClause;
        }

        $expectedSQL[] = "CALL SYSPROC.ADMIN_CMD ('REORG TABLE foo')";

Sergei Morozov's avatar
Sergei Morozov committed
558
        self::assertSame($expectedSQL, $this->platform->getAlterTableSQL($tableDiff));
559 560 561
    }

    /**
Sergei Morozov's avatar
Sergei Morozov committed
562
     * @return mixed[]
563 564 565
     */
    public function getGeneratesAlterColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
566 567
        return [
            [
568
                'columnDefinition',
Sergei Morozov's avatar
Sergei Morozov committed
569 570 571 572
                new Column('bar', Type::getType('decimal'), ['columnDefinition' => 'MONEY NOT NULL']),
                'MONEY NOT NULL',
            ],
            [
573 574
                'type',
                new Column('bar', Type::getType('integer')),
Sergei Morozov's avatar
Sergei Morozov committed
575 576 577
                'SET DATA TYPE INTEGER',
            ],
            [
578
                'length',
Sergei Morozov's avatar
Sergei Morozov committed
579 580 581 582
                new Column('bar', Type::getType('string'), ['length' => 100]),
                'SET DATA TYPE VARCHAR(100)',
            ],
            [
583
                'precision',
Sergei Morozov's avatar
Sergei Morozov committed
584 585 586 587
                new Column('bar', Type::getType('decimal'), ['precision' => 10, 'scale' => 2]),
                'SET DATA TYPE NUMERIC(10, 2)',
            ],
            [
588
                'scale',
Sergei Morozov's avatar
Sergei Morozov committed
589 590 591 592
                new Column('bar', Type::getType('decimal'), ['precision' => 5, 'scale' => 4]),
                'SET DATA TYPE NUMERIC(5, 4)',
            ],
            [
593
                'fixed',
Sergei Morozov's avatar
Sergei Morozov committed
594 595 596 597
                new Column('bar', Type::getType('string'), ['length' => 20, 'fixed' => true]),
                'SET DATA TYPE CHAR(20)',
            ],
            [
598
                'notnull',
Sergei Morozov's avatar
Sergei Morozov committed
599 600 601 602
                new Column('bar', Type::getType('string'), ['notnull' => true]),
                'SET NOT NULL',
            ],
            [
603
                'notnull',
Sergei Morozov's avatar
Sergei Morozov committed
604 605 606 607
                new Column('bar', Type::getType('string'), ['notnull' => false]),
                'DROP NOT NULL',
            ],
            [
608
                'default',
Sergei Morozov's avatar
Sergei Morozov committed
609 610 611 612
                new Column('bar', Type::getType('string'), ['default' => 'foo']),
                "SET DEFAULT 'foo'",
            ],
            [
613
                'default',
Sergei Morozov's avatar
Sergei Morozov committed
614 615 616 617
                new Column('bar', Type::getType('integer'), ['autoincrement' => true, 'default' => 666]),
                null,
            ],
            [
618 619
                'default',
                new Column('bar', Type::getType('string')),
Sergei Morozov's avatar
Sergei Morozov committed
620 621 622
                'DROP DEFAULT',
            ],
        ];
623
    }
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640

    /**
     * {@inheritdoc}
     */
    protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL()
    {
        return 'CONSTRAINT "select" UNIQUE (foo)';
    }

    /**
     * {@inheritdoc}
     */
    protected function getQuotesReservedKeywordInIndexDeclarationSQL()
    {
        return ''; // not supported by this platform
    }

641 642 643 644 645 646 647 648
    /**
     * {@inheritdoc}
     */
    protected function getQuotesReservedKeywordInTruncateTableSQL()
    {
        return 'TRUNCATE "select" IMMEDIATE';
    }

649 650 651 652 653 654 655
    /**
     * {@inheritdoc}
     */
    protected function supportsInlineIndexDeclaration()
    {
        return false;
    }
656

657 658 659 660 661 662 663 664
    /**
     * {@inheritdoc}
     */
    protected function supportsCommentOnStatement()
    {
        return true;
    }

665 666 667 668 669
    /**
     * {@inheritdoc}
     */
    protected function getAlterStringToFixedStringSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
670
        return [
671 672
            'ALTER TABLE mytable ALTER COLUMN name SET DATA TYPE CHAR(2)',
            'CALL SYSPROC.ADMIN_CMD (\'REORG TABLE mytable\')',
Sergei Morozov's avatar
Sergei Morozov committed
673
        ];
674
    }
675 676 677 678 679 680

    /**
     * {@inheritdoc}
     */
    protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
681
        return ['RENAME INDEX idx_foo TO idx_foo_renamed'];
682
    }
683 684 685 686 687 688

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableColumnsSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
689
        self::assertContains("'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\"), '', true);
690 691 692 693 694 695 696
    }

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableIndexesSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
697
        self::assertContains("'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\"), '', true);
698 699 700 701 702 703 704
    }

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableForeignKeysSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
705
        self::assertContains("'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\"), '', true);
706
    }
707
}