StatementTest.php 9.08 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\Tests\DBAL\Functional;

5
use Doctrine\DBAL\Driver\Statement;
6 7
use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
8
use Doctrine\DBAL\Schema\Table;
9
use Doctrine\DBAL\Types\Type;
10 11
use function base64_decode;
use function stream_get_contents;
12 13 14

class StatementTest extends \Doctrine\Tests\DbalFunctionalTestCase
{
15
    protected function setUp()
16
    {
17 18 19
        parent::setUp();

        $table = new Table('stmt_test');
20
        $table->addColumn('id', 'integer');
21
        $table->addColumn('name', 'text', array('notnull' => false));
22 23
        $this->_conn->getSchemaManager()->dropAndCreateTable($table);
    }
24

25 26 27 28 29 30
    public function testStatementIsReusableAfterClosingCursor()
    {
        $this->_conn->insert('stmt_test', array('id' => 1));
        $this->_conn->insert('stmt_test', array('id' => 2));

        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test ORDER BY id');
31 32 33 34

        $stmt->execute();

        $id = $stmt->fetchColumn();
35
        self::assertEquals(1, $id);
36 37 38 39 40

        $stmt->closeCursor();

        $stmt->execute();
        $id = $stmt->fetchColumn();
41
        self::assertEquals(1, $id);
42
        $id = $stmt->fetchColumn();
43
        self::assertEquals(2, $id);
44 45
    }

46 47 48
    public function testReuseStatementWithLongerResults()
    {
        $sm = $this->_conn->getSchemaManager();
49
        $table = new Table('stmt_longer_results');
50 51 52 53 54 55 56 57
        $table->addColumn('param', 'string');
        $table->addColumn('val', 'text');
        $sm->createTable($table);

        $row1 = array(
            'param' => 'param1',
            'val' => 'X',
        );
58
        $this->_conn->insert('stmt_longer_results', $row1);
59

60
        $stmt = $this->_conn->prepare('SELECT param, val FROM stmt_longer_results ORDER BY param');
61
        $stmt->execute();
62
        self::assertArraySubset(array(
63
            array('param1', 'X'),
64
        ), $stmt->fetchAll(FetchMode::NUMERIC));
65 66 67 68 69

        $row2 = array(
            'param' => 'param2',
            'val' => 'A bit longer value',
        );
70
        $this->_conn->insert('stmt_longer_results', $row2);
71 72

        $stmt->execute();
73
        self::assertArraySubset(array(
74 75
            array('param1', 'X'),
            array('param2', 'A bit longer value'),
76
        ), $stmt->fetchAll(FetchMode::NUMERIC));
77
    }
78 79 80 81 82 83 84 85

    public function testFetchLongBlob()
    {
        // make sure memory limit is large enough to not cause false positives,
        // but is still not enough to store a LONGBLOB of the max possible size
        $this->iniSet('memory_limit', '4G');

        $sm = $this->_conn->getSchemaManager();
86
        $table = new Table('stmt_long_blob');
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
        $table->addColumn('contents', 'blob', array(
            'length' => 0xFFFFFFFF,
        ));
        $sm->createTable($table);

        $contents = base64_decode(<<<EOF
H4sICJRACVgCA2RvY3RyaW5lLmljbwDtVNtLFHEU/ia1i9fVzVWxvJSrZmoXS6pd0zK7QhdNc03z
lrpppq1pWqJCFERZkUFEDybYBQqJhB6iUOqhh+whgl4qkF6MfGh+s87O7GVmO6OlBfUfdIZvznxn
fpzznW9gAI4unQ50XwirH2AAkEygEuIwU58ODnPBzXGv14sEq4BrwzKKL4sY++SGTz6PodcutN5x
IPvsFCa+K9CXMfS/cOL5OxesN0Wceygho0WAXVLwcUJBdDVDaqOAij4Rrz640XlXQmAxQ16PHU63
iqdvXbg4JOHLpILBUSdM7XZEVDDcfuZEbI2ASaYguUGAroSh97GMngcSeFFFerMdI+/dyGy1o+GW
Ax5FxfAbFwoviajuc+DCIwn+RTwGRmRIThXxdQJyu+z4/NUDYz2DKCsILuERWsoQfoQhqpLhyhMZ
XfcknBmU0NLvQArpTm0SsI5mqKqKuFoGc8cUcjrtqLohom1AgtujQnapmJJU+BbwCLIwhJXyiKlh
MB4TkFgvIK3JjrRmAefJm+77Eiqvi+SvCq/qJahQyWuVuEpcIa7QLh7Kbsourb9b66/pZdAd1voz
fCNfwsp46OnZQPojSX9UFcNy+mYJNDeJPHtJfqeR/nSaPTzmwlXar5dQ1adpd+B//I9/hi0xuCPQ
Nkvb5um37Wtc+auQXZsVxEVYD5hnCilxTaYYjsuxLlsxXUitzd2hs3GWHLM5UOM7Fy8t3xiat4fb
sneNxmNb/POO1pRXc7vnF2nc13Rq0cFWiyXkuHmzxuOtzUYfC7fEmK/3mx4QZd5u4E7XJWz6+dey
Za4tXHUiPyB8Vm781oaT+3fN6Y/eUFDfPkcNWetNxb+tlxEZsPqPdZMOzS4rxwJ8CDC+ABj1+Tu0
d+N0hqezcjblboJ3Bj8ARJilHX4FAAA=
EOF
    );

Sergei Morozov's avatar
Sergei Morozov committed
109
        $this->_conn->insert('stmt_long_blob', ['contents' => $contents], [ParameterType::LARGE_OBJECT]);
110

111
        $stmt = $this->_conn->prepare('SELECT contents FROM stmt_long_blob');
112 113 114 115 116 117
        $stmt->execute();

        $stream = Type::getType('blob')
            ->convertToPHPValue(
                $stmt->fetchColumn(),
                $this->_conn->getDatabasePlatform()
118 119
            );

120
        self::assertSame($contents, stream_get_contents($stream));
121
    }
122 123 124

    public function testIncompletelyFetchedStatementDoesNotBlockConnection()
    {
125 126
        $this->_conn->insert('stmt_test', array('id' => 1));
        $this->_conn->insert('stmt_test', array('id' => 2));
127

128
        $stmt1 = $this->_conn->prepare('SELECT id FROM stmt_test');
129 130 131 132 133 134
        $stmt1->execute();
        $stmt1->fetch();
        $stmt1->execute();
        // fetching only one record out of two
        $stmt1->fetch();

135
        $stmt2 = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');
136
        $stmt2->execute(array(1));
137
        self::assertEquals(1, $stmt2->fetchColumn());
138 139 140 141
    }

    public function testReuseStatementAfterClosingCursor()
    {
142 143
        $this->_conn->insert('stmt_test', array('id' => 1));
        $this->_conn->insert('stmt_test', array('id' => 2));
144

145
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');
146 147 148

        $stmt->execute(array(1));
        $id = $stmt->fetchColumn();
149
        self::assertEquals(1, $id);
150 151 152 153 154

        $stmt->closeCursor();

        $stmt->execute(array(2));
        $id = $stmt->fetchColumn();
155
        self::assertEquals(2, $id);
156
    }
157

158 159 160 161 162 163 164 165 166 167
    public function testReuseStatementWithParameterBoundByReference()
    {
        $this->_conn->insert('stmt_test', array('id' => 1));
        $this->_conn->insert('stmt_test', array('id' => 2));

        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');
        $stmt->bindParam(1, $id);

        $id = 1;
        $stmt->execute();
168
        self::assertEquals(1, $stmt->fetchColumn());
169 170 171

        $id = 2;
        $stmt->execute();
172
        self::assertEquals(2, $stmt->fetchColumn());
173 174
    }

175 176 177 178 179 180 181 182 183
    public function testReuseStatementWithReboundValue()
    {
        $this->_conn->insert('stmt_test', array('id' => 1));
        $this->_conn->insert('stmt_test', array('id' => 2));

        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');

        $stmt->bindValue(1, 1);
        $stmt->execute();
184
        self::assertEquals(1, $stmt->fetchColumn());
185 186 187

        $stmt->bindValue(1, 2);
        $stmt->execute();
188
        self::assertEquals(2, $stmt->fetchColumn());
189 190 191 192 193 194 195 196 197 198 199 200
    }

    public function testReuseStatementWithReboundParam()
    {
        $this->_conn->insert('stmt_test', array('id' => 1));
        $this->_conn->insert('stmt_test', array('id' => 2));

        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');

        $x = 1;
        $stmt->bindParam(1, $x);
        $stmt->execute();
201
        self::assertEquals(1, $stmt->fetchColumn());
202 203 204 205

        $y = 2;
        $stmt->bindParam(1, $y);
        $stmt->execute();
206
        self::assertEquals(2, $stmt->fetchColumn());
207 208
    }

209 210 211 212 213 214 215
    /**
     * @dataProvider emptyFetchProvider
     */
    public function testFetchFromNonExecutedStatement(callable $fetch, $expected)
    {
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test');

216
        self::assertSame($expected, $fetch($stmt));
217 218 219 220 221 222
    }

    public function testCloseCursorOnNonExecutedStatement()
    {
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test');

223
        self::assertTrue($stmt->closeCursor());
224 225
    }

226 227 228 229 230 231 232 233 234 235
    /**
     * @group DBAL-2637
     */
    public function testCloseCursorAfterCursorEnd()
    {
        $stmt = $this->_conn->prepare('SELECT name FROM stmt_test');

        $stmt->execute();
        $stmt->fetch();

236
        self::assertTrue($stmt->closeCursor());
237 238
    }

239 240 241 242 243 244 245 246
    /**
     * @dataProvider emptyFetchProvider
     */
    public function testFetchFromNonExecutedStatementWithClosedCursor(callable $fetch, $expected)
    {
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test');
        $stmt->closeCursor();

247
        self::assertSame($expected, $fetch($stmt));
248 249 250 251 252 253 254 255 256 257 258 259 260
    }

    /**
     * @dataProvider emptyFetchProvider
     */
    public function testFetchFromExecutedStatementWithClosedCursor(callable $fetch, $expected)
    {
        $this->_conn->insert('stmt_test', array('id' => 1));

        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test');
        $stmt->execute();
        $stmt->closeCursor();

261
        self::assertSame($expected, $fetch($stmt));
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
    }

    public static function emptyFetchProvider()
    {
        return array(
            'fetch' => array(
                function (Statement $stmt) {
                    return $stmt->fetch();
                },
                false,
            ),
            'fetch-column' => array(
                function (Statement $stmt) {
                    return $stmt->fetchColumn();
                },
                false,
            ),
            'fetch-all' => array(
                function (Statement $stmt) {
                    return $stmt->fetchAll();
                },
                array(),
            ),
        );
    }
287 288 289 290 291

    public function testFetchInColumnMode() : void
    {
        $platform = $this->_conn->getDatabasePlatform();
        $query    = $platform->getDummySelectSQL();
292
        $result   = $this->_conn->executeQuery($query)->fetch(FetchMode::COLUMN);
293 294 295

        self::assertEquals(1, $result);
    }
296
}