3 namespace Doctrine\Tests\DBAL\Functional;
5 use Doctrine\DBAL\Types\Type;
6 use Doctrine\DBAL\Connection;
9 require_once __DIR__ . '/../../TestInit.php';
11 class DataAccessTest extends \Doctrine\Tests\DbalFunctionalTestCase
13 static private $generated = false;
15 public function setUp()
19 if (self::$generated === false) {
20 /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
21 $table = new \Doctrine\DBAL\Schema\Table("fetch_table");
22 $table->addColumn('test_int', 'integer');
23 $table->addColumn('test_string', 'string');
24 $table->addColumn('test_datetime', 'datetime', array('notnull' => false));
25 $table->setPrimaryKey(array('test_int'));
27 $sm = $this->_conn->getSchemaManager();
28 $sm->createTable($table);
30 $this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo', 'test_datetime' => '2010-01-01 10:10:10'));
31 self::$generated = true;
35 public function testPrepareWithBindValue()
37 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
38 $stmt = $this->_conn->prepare($sql);
39 $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
41 $stmt->bindValue(1, 1);
42 $stmt->bindValue(2, 'foo');
45 $row = $stmt->fetch(\PDO::FETCH_ASSOC);
46 $row = array_change_key_case($row, \CASE_LOWER);
47 $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
50 public function testPrepareWithBindParam()
55 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
56 $stmt = $this->_conn->prepare($sql);
57 $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
59 $stmt->bindParam(1, $paramInt);
60 $stmt->bindParam(2, $paramStr);
63 $row = $stmt->fetch(\PDO::FETCH_ASSOC);
64 $row = array_change_key_case($row, \CASE_LOWER);
65 $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
68 public function testPrepareWithFetchAll()
73 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
74 $stmt = $this->_conn->prepare($sql);
75 $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
77 $stmt->bindParam(1, $paramInt);
78 $stmt->bindParam(2, $paramStr);
81 $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
82 $rows[0] = array_change_key_case($rows[0], \CASE_LOWER);
83 $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $rows[0]);
89 public function testPrepareWithFetchAllBoth()
94 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
95 $stmt = $this->_conn->prepare($sql);
96 $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
98 $stmt->bindParam(1, $paramInt);
99 $stmt->bindParam(2, $paramStr);
102 $rows = $stmt->fetchAll(\PDO::FETCH_BOTH);
103 $rows[0] = array_change_key_case($rows[0], \CASE_LOWER);
104 $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo', 0 => 1, 1 => 'foo'), $rows[0]);
107 public function testPrepareWithFetchColumn()
112 $sql = "SELECT test_int FROM fetch_table WHERE test_int = ? AND test_string = ?";
113 $stmt = $this->_conn->prepare($sql);
114 $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
116 $stmt->bindParam(1, $paramInt);
117 $stmt->bindParam(2, $paramStr);
120 $column = $stmt->fetchColumn();
121 $this->assertEquals(1, $column);
124 public function testPrepareWithIterator()
129 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
130 $stmt = $this->_conn->prepare($sql);
131 $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
133 $stmt->bindParam(1, $paramInt);
134 $stmt->bindParam(2, $paramStr);
138 $stmt->setFetchMode(\PDO::FETCH_ASSOC);
139 foreach ($stmt as $row) {
140 $rows[] = array_change_key_case($row, \CASE_LOWER);
143 $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $rows[0]);
146 public function testPrepareWithQuoted()
148 $table = 'fetch_table';
152 $sql = "SELECT test_int, test_string FROM " . $this->_conn->quoteIdentifier($table) . " ".
153 "WHERE test_int = " . $this->_conn->quote($paramInt) . " AND test_string = " . $this->_conn->quote($paramStr);
154 $stmt = $this->_conn->prepare($sql);
155 $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
158 public function testPrepareWithExecuteParams()
163 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
164 $stmt = $this->_conn->prepare($sql);
165 $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
166 $stmt->execute(array($paramInt, $paramStr));
168 $row = $stmt->fetch(\PDO::FETCH_ASSOC);
169 $this->assertTrue($row !== false);
170 $row = array_change_key_case($row, \CASE_LOWER);
171 $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
174 public function testFetchAll()
176 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
177 $data = $this->_conn->fetchAll($sql, array(1, 'foo'));
179 $this->assertEquals(1, count($data));
182 $this->assertEquals(2, count($row));
184 $row = array_change_key_case($row, \CASE_LOWER);
185 $this->assertEquals(1, $row['test_int']);
186 $this->assertEquals('foo', $row['test_string']);
189 public function testFetchBoth()
191 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
192 $row = $this->_conn->executeQuery($sql, array(1, 'foo'))->fetch(\PDO::FETCH_BOTH);
194 $this->assertTrue($row !== false);
196 $row = array_change_key_case($row, \CASE_LOWER);
198 $this->assertEquals(1, $row['test_int']);
199 $this->assertEquals('foo', $row['test_string']);
200 $this->assertEquals(1, $row[0]);
201 $this->assertEquals('foo', $row[1]);
204 public function testFetchRow()
206 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
207 $row = $this->_conn->fetchAssoc($sql, array(1, 'foo'));
209 $this->assertTrue($row !== false);
211 $row = array_change_key_case($row, \CASE_LOWER);
213 $this->assertEquals(1, $row['test_int']);
214 $this->assertEquals('foo', $row['test_string']);
217 public function testFetchArray()
219 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
220 $row = $this->_conn->fetchArray($sql, array(1, 'foo'));
222 $this->assertEquals(1, $row[0]);
223 $this->assertEquals('foo', $row[1]);
226 public function testFetchColumn()
228 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
229 $testInt = $this->_conn->fetchColumn($sql, array(1, 'foo'), 0);
231 $this->assertEquals(1, $testInt);
233 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
234 $testString = $this->_conn->fetchColumn($sql, array(1, 'foo'), 1);
236 $this->assertEquals('foo', $testString);
242 public function testExecuteQueryBindDateTimeType()
244 $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?';
245 $stmt = $this->_conn->executeQuery($sql,
246 array(1 => new \DateTime('2010-01-01 10:10:10')),
247 array(1 => Type::DATETIME)
250 $this->assertEquals(1, $stmt->fetchColumn());
256 public function testExecuteUpdateBindDateTimeType()
258 $datetime = new \DateTime('2010-02-02 20:20:20');
260 $sql = 'INSERT INTO fetch_table (test_int, test_string, test_datetime) VALUES (?, ?, ?)';
261 $affectedRows = $this->_conn->executeUpdate($sql,
262 array(1 => 50, 2 => 'foo', 3 => $datetime),
263 array(1 => PDO::PARAM_INT, 2 => PDO::PARAM_STR, 3 => Type::DATETIME)
266 $this->assertEquals(1, $affectedRows);
267 $this->assertEquals(1, $this->_conn->executeQuery(
268 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?',
269 array(1 => $datetime),
270 array(1 => Type::DATETIME)
277 public function testPrepareQueryBindValueDateTimeType()
279 $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?';
280 $stmt = $this->_conn->prepare($sql);
281 $stmt->bindValue(1, new \DateTime('2010-01-01 10:10:10'), Type::DATETIME);
284 $this->assertEquals(1, $stmt->fetchColumn());
290 public function testNativeArrayListSupport()
292 for ($i = 100; $i < 110; $i++) {
293 $this->_conn->insert('fetch_table', array('test_int' => $i, 'test_string' => 'foo' . $i, 'test_datetime' => '2010-01-01 10:10:10'));
296 $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_int IN (?)',
297 array(array(100, 101, 102, 103, 104)), array(Connection::PARAM_INT_ARRAY));
299 $data = $stmt->fetchAll(PDO::FETCH_NUM);
300 $this->assertEquals(5, count($data));
301 $this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data);
303 $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_string IN (?)',
304 array(array('foo100', 'foo101', 'foo102', 'foo103', 'foo104')), array(Connection::PARAM_STR_ARRAY));
306 $data = $stmt->fetchAll(PDO::FETCH_NUM);
307 $this->assertEquals(5, count($data));
308 $this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data);
314 public function testDateArithmetics()
316 $p = $this->_conn->getDatabasePlatform();
318 $sql .= $p->getDateDiffExpression('test_datetime', $p->getCurrentTimestampSQL()) .' AS diff, ';
319 $sql .= $p->getDateAddDaysExpression('test_datetime', 10) .' AS add_days, ';
320 $sql .= $p->getDateSubDaysExpression('test_datetime', 10) .' AS sub_days, ';
321 $sql .= $p->getDateAddMonthExpression('test_datetime', 2) .' AS add_month, ';
322 $sql .= $p->getDateSubMonthExpression('test_datetime', 2) .' AS sub_month ';
323 $sql .= 'FROM fetch_table';
325 $row = $this->_conn->fetchAssoc($sql);
326 $row = array_change_key_case($row, CASE_LOWER);
328 $diff = floor( (strtotime('2010-01-01')-time()) / 3600 / 24);
329 $this->assertEquals($diff, (int)$row['diff'], "Date difference should be approx. ".$diff." days.", 1);
330 $this->assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), "Adding date should end up on 2010-01-11");
331 $this->assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), "Subtracting date should end up on 2009-12-22");
332 $this->assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), "Adding month should end up on 2010-03-01");
333 $this->assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), "Adding month should end up on 2009-11-01");
336 public function testQuoteSQLInjection()
338 $sql = "SELECT * FROM fetch_table WHERE test_string = " . $this->_conn->quote("bar' OR '1'='1");
339 $rows = $this->_conn->fetchAll($sql);
341 $this->assertEquals(0, count($rows), "no result should be returned, otherwise SQL injection is possible");
347 public function testBitComparisonExpressionSupport()
349 $this->_conn->executeQuery('DELETE FROM fetch_table')->execute();
350 $platform = $this->_conn->getDatabasePlatform();
353 for ($i = 2; $i < 9; $i = $i + 2) {
355 'bit_or' => ($i | 2),
356 'bit_and' => ($i & 2)
358 $this->_conn->insert('fetch_table', array(
360 'test_string' => json_encode($bitmap[$i]),
361 'test_datetime' => '2010-01-01 10:10:10'
366 $sql[] = 'test_int, ';
367 $sql[] = 'test_string, ';
368 $sql[] = $platform->getBitOrComparisonExpression('test_int', 2) . ' AS bit_or, ';
369 $sql[] = $platform->getBitAndComparisonExpression('test_int', 2) . ' AS bit_and ';
370 $sql[] = 'FROM fetch_table';
372 $stmt = $this->_conn->executeQuery(implode(PHP_EOL, $sql));
373 $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
376 $this->assertEquals(4, count($data));
377 $this->assertEquals(count($bitmap), count($data));
378 foreach ($data as $row) {
379 $row = array_change_key_case($row, CASE_LOWER);
381 $this->assertArrayHasKey('test_int', $row);
383 $id = $row['test_int'];
385 $this->assertArrayHasKey($id, $bitmap);
386 $this->assertArrayHasKey($id, $bitmap);
388 $this->assertArrayHasKey('bit_or', $row);
389 $this->assertArrayHasKey('bit_and', $row);
391 $this->assertEquals($row['bit_or'], $bitmap[$id]['bit_or']);
392 $this->assertEquals($row['bit_and'], $bitmap[$id]['bit_and']);
396 public function testSetDefaultFetchMode()
398 $stmt = $this->_conn->query("SELECT * FROM fetch_table");
399 $stmt->setFetchMode(\PDO::FETCH_NUM);
401 $row = array_keys($stmt->fetch());
402 $this->assertEquals(0, count( array_filter($row, function($v) { return ! is_numeric($v); })), "should be no non-numerical elements in the result.");
408 public function testFetchAllSupportFetchClass()
410 $this->skipOci8AndMysqli();
411 $this->setupFixture();
413 $sql = "SELECT test_int, test_string, test_datetime FROM fetch_table";
414 $stmt = $this->_conn->prepare($sql);
417 $results = $stmt->fetchAll(
419 __NAMESPACE__.'\\MyFetchClass'
422 $this->assertEquals(1, count($results));
423 $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
425 $this->assertEquals(1, $results[0]->test_int);
426 $this->assertEquals('foo', $results[0]->test_string);
427 $this->assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
433 public function testFetchAllStyleColumn()
435 $sql = "DELETE FROM fetch_table";
436 $this->_conn->executeUpdate($sql);
438 $this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo'));
439 $this->_conn->insert('fetch_table', array('test_int' => 10, 'test_string' => 'foo'));
441 $sql = "SELECT test_int FROM fetch_table";
442 $rows = $this->_conn->query($sql)->fetchAll(\PDO::FETCH_COLUMN);
444 $this->assertEquals(array(1, 10), $rows);
450 public function testSetFetchModeClassFetchAll()
452 $this->skipOci8AndMysqli();
453 $this->setupFixture();
455 $sql = "SELECT * FROM fetch_table";
456 $stmt = $this->_conn->query($sql);
457 $stmt->setFetchMode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array());
459 $results = $stmt->fetchAll();
461 $this->assertEquals(1, count($results));
462 $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
464 $this->assertEquals(1, $results[0]->test_int);
465 $this->assertEquals('foo', $results[0]->test_string);
466 $this->assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
472 public function testSetFetchModeClassFetch()
474 $this->skipOci8AndMysqli();
475 $this->setupFixture();
477 $sql = "SELECT * FROM fetch_table";
478 $stmt = $this->_conn->query($sql);
479 $stmt->setFetchMode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array());
482 while ($row = $stmt->fetch()) {
486 $this->assertEquals(1, count($results));
487 $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
489 $this->assertEquals(1, $results[0]->test_int);
490 $this->assertEquals('foo', $results[0]->test_string);
491 $this->assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime);
497 public function testEmptyFetchColumnReturnsFalse()
499 $this->_conn->executeQuery('DELETE FROM fetch_table')->execute();
500 $this->assertFalse($this->_conn->fetchColumn('SELECT test_int FROM fetch_table'));
501 $this->assertFalse($this->_conn->query('SELECT test_int FROM fetch_table')->fetchColumn());
507 public function testSetFetchModeOnDbalStatement()
509 $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
510 $stmt = $this->_conn->executeQuery($sql, array(1, "foo"));
511 $stmt->setFetchMode(\PDO::FETCH_NUM);
513 while ($row = $stmt->fetch()) {
514 $this->assertTrue(isset($row[0]));
515 $this->assertTrue(isset($row[1]));
519 private function setupFixture()
521 $this->_conn->executeQuery('DELETE FROM fetch_table')->execute();
522 $this->_conn->insert('fetch_table', array(
524 'test_string' => 'foo',
525 'test_datetime' => '2010-01-01 10:10:10'
529 private function skipOci8AndMysqli()
531 if (isset($GLOBALS['db_type']) && $GLOBALS['db_type'] == "oci8") {
532 $this->markTestSkipped("Not supported by OCI8");
534 if ('mysqli' == $this->_conn->getDriver()->getName()) {
535 $this->markTestSkipped('Mysqli driver dont support this feature.');
542 public $test_int, $test_string, $test_datetime;