Passed
Pull Request — develop (#3154)
by Sergei
06:09
created

StatementTest::testFetchBeforeExecute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Doctrine\Tests\DBAL\Functional;
4
5
use Doctrine\DBAL\Driver\DriverException;
6
use Doctrine\DBAL\Driver\Statement;
7
use Doctrine\DBAL\FetchMode;
8
use Doctrine\DBAL\ParameterType;
9
use Doctrine\DBAL\Schema\Table;
10
use Doctrine\DBAL\Types\Type;
11
use function base64_decode;
12
use function stream_get_contents;
13
14
class StatementTest extends \Doctrine\Tests\DbalFunctionalTestCase
15
{
16
    protected function setUp()
17
    {
18
        parent::setUp();
19
20
        $table = new Table('stmt_test');
21
        $table->addColumn('id', 'integer');
22
        $table->addColumn('name', 'text', array('notnull' => false));
23
        $this->_conn->getSchemaManager()->dropAndCreateTable($table);
24
    }
25
26
    public function testStatementIsReusableAfterClosingCursor()
27
    {
28
        $this->_conn->insert('stmt_test', array('id' => 1));
29
        $this->_conn->insert('stmt_test', array('id' => 2));
30
31
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test ORDER BY id');
32
33
        $stmt->execute();
34
35
        $id = $stmt->fetchColumn();
36
        self::assertEquals(1, $id);
37
38
        $stmt->closeCursor();
39
40
        $stmt->execute();
41
        $id = $stmt->fetchColumn();
42
        self::assertEquals(1, $id);
43
        $id = $stmt->fetchColumn();
44
        self::assertEquals(2, $id);
45
    }
46
47
    public function testReuseStatementWithLongerResults()
48
    {
49
        $sm = $this->_conn->getSchemaManager();
50
        $table = new Table('stmt_longer_results');
51
        $table->addColumn('param', 'string');
52
        $table->addColumn('val', 'text');
53
        $sm->createTable($table);
54
55
        $row1 = array(
56
            'param' => 'param1',
57
            'val' => 'X',
58
        );
59
        $this->_conn->insert('stmt_longer_results', $row1);
60
61
        $stmt = $this->_conn->prepare('SELECT param, val FROM stmt_longer_results ORDER BY param');
62
        $stmt->execute();
63
        self::assertArraySubset(array(
64
            array('param1', 'X'),
65
        ), $stmt->fetchAll(FetchMode::NUMERIC));
66
67
        $row2 = array(
68
            'param' => 'param2',
69
            'val' => 'A bit longer value',
70
        );
71
        $this->_conn->insert('stmt_longer_results', $row2);
72
73
        $stmt->execute();
74
        self::assertArraySubset(array(
75
            array('param1', 'X'),
76
            array('param2', 'A bit longer value'),
77
        ), $stmt->fetchAll(FetchMode::NUMERIC));
78
    }
79
80
    public function testFetchLongBlob()
81
    {
82
        // make sure memory limit is large enough to not cause false positives,
83
        // but is still not enough to store a LONGBLOB of the max possible size
84
        $this->iniSet('memory_limit', '4G');
85
86
        $sm = $this->_conn->getSchemaManager();
87
        $table = new Table('stmt_long_blob');
88
        $table->addColumn('contents', 'blob', array(
89
            'length' => 0xFFFFFFFF,
90
        ));
91
        $sm->createTable($table);
92
93
        $contents = base64_decode(<<<EOF
94
H4sICJRACVgCA2RvY3RyaW5lLmljbwDtVNtLFHEU/ia1i9fVzVWxvJSrZmoXS6pd0zK7QhdNc03z
95
lrpppq1pWqJCFERZkUFEDybYBQqJhB6iUOqhh+whgl4qkF6MfGh+s87O7GVmO6OlBfUfdIZvznxn
96
fpzznW9gAI4unQ50XwirH2AAkEygEuIwU58ODnPBzXGv14sEq4BrwzKKL4sY++SGTz6PodcutN5x
97
IPvsFCa+K9CXMfS/cOL5OxesN0Wceygho0WAXVLwcUJBdDVDaqOAij4Rrz640XlXQmAxQ16PHU63
98
iqdvXbg4JOHLpILBUSdM7XZEVDDcfuZEbI2ASaYguUGAroSh97GMngcSeFFFerMdI+/dyGy1o+GW
99
Ax5FxfAbFwoviajuc+DCIwn+RTwGRmRIThXxdQJyu+z4/NUDYz2DKCsILuERWsoQfoQhqpLhyhMZ
100
XfcknBmU0NLvQArpTm0SsI5mqKqKuFoGc8cUcjrtqLohom1AgtujQnapmJJU+BbwCLIwhJXyiKlh
101
MB4TkFgvIK3JjrRmAefJm+77Eiqvi+SvCq/qJahQyWuVuEpcIa7QLh7Kbsourb9b66/pZdAd1voz
102
fCNfwsp46OnZQPojSX9UFcNy+mYJNDeJPHtJfqeR/nSaPTzmwlXar5dQ1adpd+B//I9/hi0xuCPQ
103
Nkvb5um37Wtc+auQXZsVxEVYD5hnCilxTaYYjsuxLlsxXUitzd2hs3GWHLM5UOM7Fy8t3xiat4fb
104
sneNxmNb/POO1pRXc7vnF2nc13Rq0cFWiyXkuHmzxuOtzUYfC7fEmK/3mx4QZd5u4E7XJWz6+dey
105
Za4tXHUiPyB8Vm781oaT+3fN6Y/eUFDfPkcNWetNxb+tlxEZsPqPdZMOzS4rxwJ8CDC+ABj1+Tu0
106
d+N0hqezcjblboJ3Bj8ARJilHX4FAAA=
107
EOF
108
    );
109
110
        $this->_conn->insert('stmt_long_blob', ['contents' => $contents], [ParameterType::LARGE_OBJECT]);
111
112
        $stmt = $this->_conn->prepare('SELECT contents FROM stmt_long_blob');
113
        $stmt->execute();
114
115
        $stream = Type::getType('blob')
116
            ->convertToPHPValue(
117
                $stmt->fetchColumn(),
118
                $this->_conn->getDatabasePlatform()
119
            );
120
121
        self::assertSame($contents, stream_get_contents($stream));
0 ignored issues
show
Bug introduced by
$stream of type false|string is incompatible with the type resource expected by parameter $handle of stream_get_contents(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

121
        self::assertSame($contents, stream_get_contents(/** @scrutinizer ignore-type */ $stream));
Loading history...
122
    }
123
124
    public function testIncompletelyFetchedStatementDoesNotBlockConnection()
125
    {
126
        $this->_conn->insert('stmt_test', array('id' => 1));
127
        $this->_conn->insert('stmt_test', array('id' => 2));
128
129
        $stmt1 = $this->_conn->prepare('SELECT id FROM stmt_test');
130
        $stmt1->execute();
131
        $stmt1->fetch();
132
        $stmt1->execute();
133
        // fetching only one record out of two
134
        $stmt1->fetch();
135
136
        $stmt2 = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');
137
        $stmt2->execute(array(1));
138
        self::assertEquals(1, $stmt2->fetchColumn());
139
    }
140
141
    public function testReuseStatementAfterClosingCursor()
142
    {
143
        $this->_conn->insert('stmt_test', array('id' => 1));
144
        $this->_conn->insert('stmt_test', array('id' => 2));
145
146
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');
147
148
        $stmt->execute(array(1));
149
        $id = $stmt->fetchColumn();
150
        self::assertEquals(1, $id);
151
152
        $stmt->closeCursor();
153
154
        $stmt->execute(array(2));
155
        $id = $stmt->fetchColumn();
156
        self::assertEquals(2, $id);
157
    }
158
159
    public function testReuseStatementWithParameterBoundByReference()
160
    {
161
        $this->_conn->insert('stmt_test', array('id' => 1));
162
        $this->_conn->insert('stmt_test', array('id' => 2));
163
164
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');
165
        $stmt->bindParam(1, $id);
166
167
        $id = 1;
0 ignored issues
show
Unused Code introduced by
The assignment to $id is dead and can be removed.
Loading history...
168
        $stmt->execute();
169
        self::assertEquals(1, $stmt->fetchColumn());
170
171
        $id = 2;
172
        $stmt->execute();
173
        self::assertEquals(2, $stmt->fetchColumn());
174
    }
175
176
    public function testReuseStatementWithReboundValue()
177
    {
178
        $this->_conn->insert('stmt_test', array('id' => 1));
179
        $this->_conn->insert('stmt_test', array('id' => 2));
180
181
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');
182
183
        $stmt->bindValue(1, 1);
184
        $stmt->execute();
185
        self::assertEquals(1, $stmt->fetchColumn());
186
187
        $stmt->bindValue(1, 2);
188
        $stmt->execute();
189
        self::assertEquals(2, $stmt->fetchColumn());
190
    }
191
192
    public function testReuseStatementWithReboundParam()
193
    {
194
        $this->_conn->insert('stmt_test', array('id' => 1));
195
        $this->_conn->insert('stmt_test', array('id' => 2));
196
197
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test WHERE id = ?');
198
199
        $x = 1;
200
        $stmt->bindParam(1, $x);
201
        $stmt->execute();
202
        self::assertEquals(1, $stmt->fetchColumn());
203
204
        $y = 2;
205
        $stmt->bindParam(1, $y);
206
        $stmt->execute();
207
        self::assertEquals(2, $stmt->fetchColumn());
208
    }
209
210
    /**
211
     * @dataProvider fetchProvider
212
     */
213
    public function testFetchFromNonExecutedStatement(callable $fetch)
214
    {
215
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test');
216
217
        self::expectException(DriverException::class);
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

217
        self::/** @scrutinizer ignore-call */ 
218
              expectException(DriverException::class);
Loading history...
218
        $fetch($stmt);
219
    }
220
221
    /**
222
     * @dataProvider fetchProvider
223
     */
224
    public function testCloseCursorOnNonExecutedStatement(callable $fetch)
225
    {
226
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test');
227
        $stmt->closeCursor();
228
229
        self::expectException(DriverException::class);
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

229
        self::/** @scrutinizer ignore-call */ 
230
              expectException(DriverException::class);
Loading history...
230
        $fetch($stmt);
231
    }
232
233
    /**
234
     * @group DBAL-2637
235
     */
236
    public function testCloseCursorAfterCursorEnd()
237
    {
238
        $stmt = $this->_conn->prepare('SELECT name FROM stmt_test');
239
240
        $stmt->execute();
241
        self::assertFalse($stmt->fetch());
242
243
        $stmt->closeCursor();
244
245
        self::expectException(DriverException::class);
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

245
        self::/** @scrutinizer ignore-call */ 
246
              expectException(DriverException::class);
Loading history...
246
        $stmt->fetch();
247
    }
248
249
    /**
250
     * @dataProvider fetchProvider
251
     */
252
    public function testFetchFromNonExecutedStatementWithClosedCursor(callable $fetch)
253
    {
254
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test');
255
        $stmt->closeCursor();
256
257
        self::expectException(DriverException::class);
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

257
        self::/** @scrutinizer ignore-call */ 
258
              expectException(DriverException::class);
Loading history...
258
        $fetch($stmt);
259
    }
260
261
    /**
262
     * @dataProvider fetchProvider
263
     */
264
    public function testFetchFromExecutedStatementWithClosedCursor(callable $fetch)
265
    {
266
        $this->_conn->insert('stmt_test', array('id' => 1));
267
268
        $stmt = $this->_conn->prepare('SELECT id FROM stmt_test');
269
        $stmt->execute();
270
        $stmt->closeCursor();
271
272
        self::expectException(DriverException::class);
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

272
        self::/** @scrutinizer ignore-call */ 
273
              expectException(DriverException::class);
Loading history...
273
        $fetch($stmt);
274
    }
275
276
    /**
277
     * @dataProvider fetchProvider
278
     */
279
    public function testFetchBeforeExecute(callable $fetch) : void
280
    {
281
        $platform = $this->_conn->getDatabasePlatform();
282
        $query    = $platform->getDummySelectSQL();
283
        $stmt     = $this->_conn->prepare($query);
284
285
        self::expectException(DriverException::class);
0 ignored issues
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

285
        self::/** @scrutinizer ignore-call */ 
286
              expectException(DriverException::class);
Loading history...
286
        $fetch($stmt);
287
    }
288
289
    public static function fetchProvider()
290
    {
291
        return array(
292
            'fetch' => array(
293
                function (Statement $stmt) {
294
                    return $stmt->fetch();
295
                },
296
            ),
297
            'fetch-column' => array(
298
                function (Statement $stmt) {
299
                    return $stmt->fetchColumn();
300
                },
301
            ),
302
            'fetch-all' => array(
303
                function (Statement $stmt) {
304
                    return $stmt->fetchAll();
305
                },
306
            ),
307
        );
308
    }
309
310
    public function testFetchInColumnMode() : void
311
    {
312
        $platform = $this->_conn->getDatabasePlatform();
313
        $query    = $platform->getDummySelectSQL();
314
        $result   = $this->_conn->executeQuery($query)->fetch(FetchMode::COLUMN);
315
316
        self::assertEquals(1, $result);
317
    }
318
}
319