DB2PlatformTest.php 27.3 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
use Doctrine\DBAL\Types\Types;
14 15 16

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

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

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

    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
59
        return [
60
            'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL)',
Sergei Morozov's avatar
Sergei Morozov committed
61 62
            'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)',
        ];
63 64 65 66 67 68 69 70 71
    }

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

    protected function getQuotedColumnInForeignKeySQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
72
        return [
73 74 75 76
            '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
77
        ];
78 79 80 81
    }

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

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

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

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

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

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

    public function getAlterTableColumnCommentsSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
121 122 123
        return [
            'ALTER TABLE mytable ' .
            'ADD COLUMN quota INTEGER NOT NULL WITH DEFAULT',
124 125 126 127
            "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
128
        ];
129 130 131 132
    }

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

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

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

153
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
154
            [
155 156
                '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
157 158
                'CREATE INDEX composite_idx ON test (id, name)',
            ],
Sergei Morozov's avatar
Sergei Morozov committed
159
            $this->platform->getCreateTableSQL($table)
160 161 162 163 164 165 166 167 168
        );
    }

    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
169 170
        $table->setPrimaryKey(['id']);
        $table->addForeignKeyConstraint('foreign_table', ['fk_1', 'fk_2'], ['pk_1', 'pk_2']);
171 172
        $table->addForeignKeyConstraint(
            'foreign_table2',
Sergei Morozov's avatar
Sergei Morozov committed
173 174 175
            ['fk_1', 'fk_2'],
            ['pk_1', 'pk_2'],
            [],
176 177 178
            'named_fk'
        );

179
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
180
            [
181 182 183
                '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
184
            ],
Sergei Morozov's avatar
Sergei Morozov committed
185
            $this->platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS)
186 187 188 189 190 191 192
        );
    }

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

197
        self::assertEquals(
Sergei Morozov's avatar
Sergei Morozov committed
198
            ['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
199
            $this->platform->getCreateTableSQL($table)
200 201 202 203 204
        );
    }

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

Sergei Morozov's avatar
Sergei Morozov committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
        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));
233 234 235 236
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

283
        $data[Types::BOOLEAN] = [Type::getType(Types::BOOLEAN), true];
284 285 286 287

        return $data;
    }

288 289
    public function testGeneratesDDLSnippets()
    {
Sergei Morozov's avatar
Sergei Morozov committed
290 291 292 293 294
        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);
295 296

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

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

    public function testGeneratesSQLSnippets()
    {
Sergei Morozov's avatar
Sergei Morozov committed
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 339
        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));
340 341 342 343
    }

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

349
        self::assertEquals(
350
            '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
351
            $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0)
352 353
        );

354
        self::assertEquals(
355
            '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
356
            $this->platform->modifyLimitQuery('SELECT * FROM user', 10)
357 358
        );

359
        self::assertEquals(
360
            '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
361
            $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 5)
362
        );
363
        self::assertEquals(
364
            '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
365
            $this->platform->modifyLimitQuery('SELECT * FROM user', 0, 5)
366 367 368 369 370
        );
    }

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

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

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

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

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

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

    protected function getBinaryDefaultLength()
    {
        return 1;
    }

    protected function getBinaryMaxLength()
    {
        return 32704;
    }

    public function testReturnsBinaryTypeDeclarationSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
411 412 413
        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]));
414

Sergei Morozov's avatar
Sergei Morozov committed
415 416
        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]));
417 418 419 420
    }

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

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

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

    /**
     * {@inheritdoc}
     */
    protected function getQuotedAlterTableRenameColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
453
        return ['ALTER TABLE mytable ' .
454 455 456 457 458 459 460 461
            '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
462 463
            'RENAME COLUMN quoted3 TO "baz"',
        ];
464
    }
465

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

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

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

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

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

    /**
     * {@inheritdoc}
     */
    protected function getQuotesTableIdentifiersInAlterTableSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
514
        return [
515 516
            'ALTER TABLE "foo" DROP FOREIGN KEY fk1',
            'ALTER TABLE "foo" DROP FOREIGN KEY fk2',
517 518 519 520 521
            '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',
522 523 524 525
            '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
526
        ];
527
    }
528 529 530 531 532 533

    /**
     * {@inheritdoc}
     */
    protected function getCommentOnColumnSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
534
        return [
535 536 537
            '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
538
        ];
539
    }
540 541 542 543 544 545 546

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

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

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

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

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

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

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

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

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

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

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

666 667 668 669 670
    /**
     * {@inheritdoc}
     */
    protected function getAlterStringToFixedStringSQL()
    {
Sergei Morozov's avatar
Sergei Morozov committed
671
        return [
672 673
            '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
674
        ];
675
    }
676 677 678 679 680 681

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

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableColumnsSQL()
    {
690 691 692 693
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\'",
            $this->platform->getListTableColumnsSQL("Foo'Bar\\")
        );
694 695 696 697 698 699 700
    }

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableIndexesSQL()
    {
701 702 703 704
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\'",
            $this->platform->getListTableIndexesSQL("Foo'Bar\\")
        );
705 706 707 708 709 710 711
    }

    /**
     * @group DBAL-2436
     */
    public function testQuotesTableNameInListTableForeignKeysSQL()
    {
712 713 714 715
        self::assertStringContainsStringIgnoringCase(
            "'Foo''Bar\\'",
            $this->platform->getListTableForeignKeysSQL("Foo'Bar\\")
        );
716
    }
717
}