ModifyLimitQueryTest.php 7.39 KB
Newer Older
1 2
<?php

3
namespace Doctrine\DBAL\Tests\Functional;
Sergei Morozov's avatar
Sergei Morozov committed
4 5

use Doctrine\DBAL\Schema\Table;
6
use Doctrine\DBAL\Tests\FunctionalTestCase;
7

8 9
use function array_change_key_case;
use function count;
10

Grégoire Paris's avatar
Grégoire Paris committed
11
use const CASE_LOWER;
12

13
class ModifyLimitQueryTest extends FunctionalTestCase
14
{
Sergei Morozov's avatar
Sergei Morozov committed
15
    /** @var bool */
16
    private static $tableCreated = false;
17

18
    protected function setUp(): void
19 20 21
    {
        parent::setUp();

Sergei Morozov's avatar
Sergei Morozov committed
22 23
        if (! self::$tableCreated) {
            $table = new Table('modify_limit_table');
24
            $table->addColumn('test_int', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
25
            $table->setPrimaryKey(['test_int']);
26

Sergei Morozov's avatar
Sergei Morozov committed
27 28
            $table2 = new Table('modify_limit_table2');
            $table2->addColumn('id', 'integer', ['autoincrement' => true]);
29
            $table2->addColumn('test_int', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
30
            $table2->setPrimaryKey(['id']);
31

Sergei Morozov's avatar
Sergei Morozov committed
32
            $sm = $this->connection->getSchemaManager();
33 34 35 36
            $sm->createTable($table);
            $sm->createTable($table2);
            self::$tableCreated = true;
        }
Grégoire Paris's avatar
Grégoire Paris committed
37

Sergei Morozov's avatar
Sergei Morozov committed
38 39
        $this->connection->exec($this->connection->getDatabasePlatform()->getTruncateTableSQL('modify_limit_table'));
        $this->connection->exec($this->connection->getDatabasePlatform()->getTruncateTableSQL('modify_limit_table2'));
40
    }
41

42
    public function testModifyLimitQuerySimpleQuery(): void
43
    {
Sergei Morozov's avatar
Sergei Morozov committed
44 45 46 47
        $this->connection->insert('modify_limit_table', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table', ['test_int' => 2]);
        $this->connection->insert('modify_limit_table', ['test_int' => 3]);
        $this->connection->insert('modify_limit_table', ['test_int' => 4]);
48

Sergei Morozov's avatar
Sergei Morozov committed
49
        $sql = 'SELECT * FROM modify_limit_table ORDER BY test_int ASC';
50

Sergei Morozov's avatar
Sergei Morozov committed
51 52 53 54
        $this->assertLimitResult([1, 2, 3, 4], $sql, 10, 0);
        $this->assertLimitResult([1, 2], $sql, 2, 0);
        $this->assertLimitResult([3, 4], $sql, 2, 2);
        $this->assertLimitResult([2, 3, 4], $sql, null, 1);
55
    }
56

57
    public function testModifyLimitQueryJoinQuery(): void
58
    {
Sergei Morozov's avatar
Sergei Morozov committed
59 60
        $this->connection->insert('modify_limit_table', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table', ['test_int' => 2]);
61

Sergei Morozov's avatar
Sergei Morozov committed
62 63 64 65 66
        $this->connection->insert('modify_limit_table2', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table2', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table2', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table2', ['test_int' => 2]);
        $this->connection->insert('modify_limit_table2', ['test_int' => 2]);
67

Sergei Morozov's avatar
Sergei Morozov committed
68
        $sql = 'SELECT modify_limit_table.test_int FROM modify_limit_table INNER JOIN modify_limit_table2 ON modify_limit_table.test_int = modify_limit_table2.test_int ORDER BY modify_limit_table.test_int DESC';
69

Sergei Morozov's avatar
Sergei Morozov committed
70 71 72
        $this->assertLimitResult([2, 2, 1, 1, 1], $sql, 10, 0);
        $this->assertLimitResult([1, 1, 1], $sql, 3, 2);
        $this->assertLimitResult([2, 2], $sql, 2, 0);
73
    }
74

75
    public function testModifyLimitQueryNonDeterministic(): void
76
    {
Sergei Morozov's avatar
Sergei Morozov committed
77 78 79 80
        $this->connection->insert('modify_limit_table', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table', ['test_int' => 2]);
        $this->connection->insert('modify_limit_table', ['test_int' => 3]);
        $this->connection->insert('modify_limit_table', ['test_int' => 4]);
81

Sergei Morozov's avatar
Sergei Morozov committed
82
        $sql = 'SELECT * FROM modify_limit_table';
83

Sergei Morozov's avatar
Sergei Morozov committed
84 85 86
        $this->assertLimitResult([4, 3, 2, 1], $sql, 10, 0, false);
        $this->assertLimitResult([4, 3], $sql, 2, 0, false);
        $this->assertLimitResult([2, 1], $sql, 2, 2, false);
87
    }
88

89
    public function testModifyLimitQueryGroupBy(): void
90
    {
Sergei Morozov's avatar
Sergei Morozov committed
91 92
        $this->connection->insert('modify_limit_table', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table', ['test_int' => 2]);
Sergei Morozov's avatar
Sergei Morozov committed
93

Sergei Morozov's avatar
Sergei Morozov committed
94 95 96 97 98
        $this->connection->insert('modify_limit_table2', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table2', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table2', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table2', ['test_int' => 2]);
        $this->connection->insert('modify_limit_table2', ['test_int' => 2]);
Sergei Morozov's avatar
Sergei Morozov committed
99 100 101 102 103 104 105 106

        $sql = 'SELECT modify_limit_table.test_int FROM modify_limit_table ' .
               'INNER JOIN modify_limit_table2 ON modify_limit_table.test_int = modify_limit_table2.test_int ' .
               'GROUP BY modify_limit_table.test_int ' .
               'ORDER BY modify_limit_table.test_int ASC';
        $this->assertLimitResult([1, 2], $sql, 10, 0);
        $this->assertLimitResult([1], $sql, 1, 0);
        $this->assertLimitResult([2], $sql, 1, 1);
107
    }
108

109
    public function testModifyLimitQuerySubSelect(): void
110
    {
Sergei Morozov's avatar
Sergei Morozov committed
111 112 113 114
        $this->connection->insert('modify_limit_table', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table', ['test_int' => 2]);
        $this->connection->insert('modify_limit_table', ['test_int' => 3]);
        $this->connection->insert('modify_limit_table', ['test_int' => 4]);
115

Sergei Morozov's avatar
Sergei Morozov committed
116
        $sql = 'SELECT modify_limit_table.*, (SELECT COUNT(*) FROM modify_limit_table) AS cnt FROM modify_limit_table ORDER BY test_int DESC';
117

Sergei Morozov's avatar
Sergei Morozov committed
118 119 120
        $this->assertLimitResult([4, 3, 2, 1], $sql, 10, 0);
        $this->assertLimitResult([4, 3], $sql, 2, 0);
        $this->assertLimitResult([2, 1], $sql, 2, 2);
121 122
    }

123
    public function testModifyLimitQueryFromSubSelect(): void
124
    {
Sergei Morozov's avatar
Sergei Morozov committed
125 126 127 128
        $this->connection->insert('modify_limit_table', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table', ['test_int' => 2]);
        $this->connection->insert('modify_limit_table', ['test_int' => 3]);
        $this->connection->insert('modify_limit_table', ['test_int' => 4]);
129

Sergei Morozov's avatar
Sergei Morozov committed
130
        $sql = 'SELECT * FROM (SELECT * FROM modify_limit_table) sub ORDER BY test_int DESC';
131

Sergei Morozov's avatar
Sergei Morozov committed
132 133 134
        $this->assertLimitResult([4, 3, 2, 1], $sql, 10, 0);
        $this->assertLimitResult([4, 3], $sql, 2, 0);
        $this->assertLimitResult([2, 1], $sql, 2, 2);
135 136
    }

137
    public function testModifyLimitQueryLineBreaks(): void
138
    {
Sergei Morozov's avatar
Sergei Morozov committed
139 140 141
        $this->connection->insert('modify_limit_table', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table', ['test_int' => 2]);
        $this->connection->insert('modify_limit_table', ['test_int' => 3]);
142 143 144 145 146 147 148 149 150 151 152 153

        $sql = <<<SQL
SELECT
*
FROM
modify_limit_table
ORDER
BY
test_int
ASC
SQL;

Sergei Morozov's avatar
Sergei Morozov committed
154
        $this->assertLimitResult([2], $sql, 1, 1);
155 156
    }

157
    public function testModifyLimitQueryZeroOffsetNoLimit(): void
158
    {
Sergei Morozov's avatar
Sergei Morozov committed
159 160
        $this->connection->insert('modify_limit_table', ['test_int' => 1]);
        $this->connection->insert('modify_limit_table', ['test_int' => 2]);
161

Sergei Morozov's avatar
Sergei Morozov committed
162
        $sql = 'SELECT test_int FROM modify_limit_table ORDER BY test_int ASC';
163

Sergei Morozov's avatar
Sergei Morozov committed
164
        $this->assertLimitResult([1, 2], $sql, null, 0);
165 166
    }

167 168 169
    /**
     * @param array<int, int> $expectedResults
     */
170
    private function assertLimitResult(array $expectedResults, string $sql, ?int $limit, int $offset, bool $deterministic = true): void
171
    {
Sergei Morozov's avatar
Sergei Morozov committed
172
        $p    = $this->connection->getDatabasePlatform();
Sergei Morozov's avatar
Sergei Morozov committed
173
        $data = [];
174
        foreach ($this->connection->fetchAllAssociative($p->modifyLimitQuery($sql, $limit, $offset)) as $row) {
Sergei Morozov's avatar
Sergei Morozov committed
175
            $row    = array_change_key_case($row, CASE_LOWER);
176
            $data[] = $row['test_int'];
177
        }
178 179 180 181 182

        /**
         * Do not assert the order of results when results are non-deterministic
         */
        if ($deterministic) {
183
            self::assertEquals($expectedResults, $data);
184
        } else {
185
            self::assertCount(count($expectedResults), $data);
186
        }
187
    }
188
}