From 26bdd89be6cbbeebec5d01b1f2d27354b5407a59 Mon Sep 17 00:00:00 2001 From: jwage Date: Mon, 13 Jul 2009 22:59:36 +0000 Subject: [PATCH] [2.0] Test coverage for OFFSET AND LIMIT sql generation for all platforms and Query class with setFirstResult() and setMaxResult() --- .../DBAL/Platforms/AbstractPlatform.php | 10 +- lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php | 18 +- .../DBAL/Platforms/OraclePlatform.php | 13 +- tests/Doctrine/Tests/DBAL/AllTests.php | 1 + .../DBAL/Platforms/MsSqlPlatformTest.php | 28 +- .../DBAL/Platforms/MySqlPlatformTest.php | 14 +- .../DBAL/Platforms/OraclePlatformTest.php | 246 ++++++++++++++++++ .../DBAL/Platforms/PostgreSqlPlatformTest.php | 14 +- .../DBAL/Platforms/SqlitePlatformTest.php | 14 +- .../ORM/Query/SelectSqlGenerationTest.php | 21 +- tests/Doctrine/Tests/TestInit.php | 3 +- 11 files changed, 354 insertions(+), 28 deletions(-) create mode 100644 tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 4a747c8f9..bf0faebb9 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -1538,14 +1538,14 @@ abstract class AbstractPlatform return 'H:i:s'; } - public function modifyLimitQuery($query, $max, $first) + public function modifyLimitQuery($query, $limit, $offset = null) { - if ( ! is_null($first)) { - $query .= ' OFFSET ' . $first; + if ( ! is_null($offset)) { + $query .= ' OFFSET ' . $offset; } - if ( ! is_null($max)) { - $query .= ' LIMIT ' . $max; + if ( ! is_null($limit)) { + $query .= ' LIMIT ' . $limit; } return $query; diff --git a/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php index 14705fe3d..02e84b0e0 100644 --- a/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php @@ -435,7 +435,7 @@ class MsSqlPlatform extends AbstractPlatform * @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html * @return string */ - public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false) + public function modifyLimitQuery($query, $limit, $offset = null) { if ($limit > 0) { $count = intval($limit); @@ -454,18 +454,18 @@ class MsSqlPlatform extends AbstractPlatform $orders = explode(',', $order); for ($i = 0; $i < count($orders); $i++) { - $sorts[$i] = (stripos($orders[$i], ' desc') !== false) ? 'desc' : 'asc'; + $sorts[$i] = (stripos($orders[$i], ' DESC') !== false) ? 'DESC' : 'ASC'; $orders[$i] = trim(preg_replace('/\s+(ASC|DESC)$/i', '', $orders[$i])); // find alias in query string - $helper_string = stristr($query, $orders[$i]); + $helperString = stristr($query, $orders[$i]); - $from_clause_pos = strpos($helper_string, ' FROM '); - $fields_string = substr($helper_string, 0, $from_clause_pos + 1); + $fromClausePos = strpos($helperString, ' FROM '); + $fieldsString = substr($helperString, 0, $fromClausePos + 1); - $field_array = explode(',', $fields_string); - $field_array = array_shift($field_array); - $aux2 = spliti(' as ', $field_array); + $fieldArray = explode(',', $fieldsString); + $fieldArray = array_shift($fieldArray); + $aux2 = preg_split('/ as /i', $fieldArray); $aliases[$i] = trim(end($aux2)); } @@ -492,7 +492,7 @@ class MsSqlPlatform extends AbstractPlatform } $query .= $this->quoteIdentifier('inner_tbl') . '.' . $aliases[$i] . ' '; - $query .= (stripos($sorts[$i], 'asc') !== false) ? 'DESC' : 'ASC'; + $query .= (stripos($sorts[$i], 'ASC') !== false) ? 'DESC' : 'ASC'; } } diff --git a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php index 8fab5fee2..fe62bd2b1 100644 --- a/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -141,11 +141,12 @@ class OraclePlatform extends AbstractPlatform protected function _getTransactionIsolationLevelSql($level) { switch ($level) { - case Doctrine_DBAL_Connection::TRANSACTION_READ_UNCOMMITTED: - case Doctrine_DBAL_Connection::TRANSACTION_READ_COMMITTED: + case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED: + return 'READ UNCOMMITTED'; + case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED: return 'READ COMMITTED'; - case Doctrine_DBAL_Connection::TRANSACTION_REPEATABLE_READ: - case Doctrine_DBAL_Connection::TRANSACTION_SERIALIZABLE: + case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ: + case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE: return 'SERIALIZABLE'; default: return parent::_getTransactionIsolationLevelSql($level); @@ -478,7 +479,7 @@ END;'; * @param integer $offset start reading from given offset * @return string the modified query */ - public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false) + public function modifyLimitQuery($query, $limit, $offset = null) { $limit = (int) $limit; $offset = (int) $offset; @@ -488,7 +489,7 @@ END;'; } if ($limit > 0) { $max = $offset + $limit; - $column = $column === null ? '*' : $this->quoteIdentifier($column); + $column = '*'; if ($offset > 0) { $min = $offset + 1; $query = 'SELECT b.'.$column.' FROM ('. diff --git a/tests/Doctrine/Tests/DBAL/AllTests.php b/tests/Doctrine/Tests/DBAL/AllTests.php index 6291a771d..6192e651b 100644 --- a/tests/Doctrine/Tests/DBAL/AllTests.php +++ b/tests/Doctrine/Tests/DBAL/AllTests.php @@ -28,6 +28,7 @@ class AllTests $suite->addTestSuite('Doctrine\Tests\DBAL\Platforms\MySqlPlatformTest'); $suite->addTestSuite('Doctrine\Tests\DBAL\Platforms\PostgreSqlPlatformTest'); $suite->addTestSuite('Doctrine\Tests\DBAL\Platforms\MsSqlPlatformTest'); + $suite->addTestSuite('Doctrine\Tests\DBAL\Platforms\OraclePlatformTest'); // Type tests $suite->addTestSuite('Doctrine\Tests\DBAL\Types\ArrayTest'); diff --git a/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php index fb257b2bc..390c90223 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/MsSqlPlatformTest.php @@ -13,7 +13,7 @@ class MsSqlPlatformTest extends \Doctrine\Tests\DbalTestCase public function setUp() { - $this->_platform = new MssqlPlatform; + $this->_platform = new MsSqlPlatform; } public function testGeneratesTableCreationSql() @@ -180,4 +180,28 @@ class MsSqlPlatformTest extends \Doctrine\Tests\DbalTestCase $sql = $this->_platform->getCreateForeignKeySql('test', array('foreignTable' => 'other_table', 'local' => 'fk_name_id', 'foreign' => 'id')); $this->assertEquals($sql, 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table(id)'); } -} + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 * FROM user) AS inner_tbl) AS outer_tbl', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 * FROM user) AS inner_tbl) AS outer_tbl', $sql); + } + + public function testModifyLimitQueryWithAscOrderBy() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10); + $this->assertEquals('SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 * FROM user ORDER BY username ASC) AS inner_tbl ORDER BY inner_tbl.u DESC) AS outer_tbl ORDER BY outer_tbl.u ASC', $sql); + } + + public function testModifyLimitQueryWithDescOrderBy() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10); + $this->assertEquals('SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 * FROM user ORDER BY username DESC) AS inner_tbl ORDER BY inner_tbl.u ASC) AS outer_tbl ORDER BY outer_tbl.u DESC', $sql); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php index b9c6ac822..b8a0db2d1 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php @@ -182,4 +182,16 @@ class MySqlPlatformTest extends \Doctrine\Tests\DbalTestCase $sql = $this->_platform->getCreateForeignKeySql('test', array('foreignTable' => 'other_table', 'local' => 'fk_name_id', 'foreign' => 'id')); $this->assertEquals($sql, 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table(id)'); } -} + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT * FROM user OFFSET 0 LIMIT 10', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT * FROM user LIMIT 10', $sql); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php new file mode 100644 index 000000000..0fe977e3f --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php @@ -0,0 +1,246 @@ +_platform = new OraclePlatform; + } + + public function testGeneratesTableCreationSql() + { + $columns = array( + 'id' => array( + 'type' => Type::getType('integer'), + 'autoincrement' => true, + 'primary' => true, + 'notnull' => true + ), + 'test' => array( + 'type' => Type::getType('string'), + 'length' => 255, + 'notnull' => true + ) + ); + + $options = array( + 'primary' => array('id') + ); + + $sql = $this->_platform->getCreateTableSql('test', $columns, $options); + $this->assertEquals('CREATE TABLE test (id NUMBER(10) NOT NULL, test VARCHAR2(255) NOT NULL, PRIMARY KEY(id))', $sql[0]); + } + + public function testGeneratesTableAlterationSql() + { + $changes = array( + 'name' => 'userlist', + 'add' => array( + 'quota' => array( + 'type' => Type::getType('integer'), + 'unsigned' => 1 + ) + )); + + $sql = $this->_platform->getAlterTableSql('mytable', $changes); + + $this->assertEquals( + 'ALTER TABLE mytable ADD (quota NUMBER(10) DEFAULT NULL)', + $sql[0] + ); + + $this->assertEquals( + 'ALTER TABLE mytable RENAME TO userlist', + $sql[1] + ); + } + + /** + * @expectedException Doctrine\Common\DoctrineException + */ + public function testRLike() + { + $this->assertEquals('RLIKE', $this->_platform->getRegexpExpression(), 'Regular expression operator is not correct'); + } + + public function testGeneratesSqlSnippets() + { + $this->assertEquals('"', $this->_platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); + $this->assertEquals('dbms_random.value', $this->_platform->getRandomExpression(), 'Random function is not correct'); + $this->assertEquals('column1 || column2 || column3', $this->_platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); + } + + /** + * @expectedException Doctrine\Common\DoctrineException + */ + public function testGetCharsetFieldDeclaration() + { + $this->assertEquals('CHARACTER SET utf8', $this->_platform->getCharsetFieldDeclaration('utf8'), 'Charset declaration is not correct'); + } + + public function testGeneratesTransactionsCommands() + { + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', + $this->_platform->getSetTransactionIsolationSql(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', + $this->_platform->getSetTransactionIsolationSql(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', + $this->_platform->getSetTransactionIsolationSql(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', + $this->_platform->getSetTransactionIsolationSql(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE) + ); + } + + /** + * @expectedException Doctrine\Common\DoctrineException + */ + public function testShowDatabasesThrowsException() + { + $this->assertEquals('SHOW DATABASES', $this->_platform->getShowDatabasesSql()); + } + + /** + * @expectedException Doctrine\Common\DoctrineException + */ + public function testCreateDatabaseThrowsException() + { + $this->assertEquals('CREATE DATABASE foobar', $this->_platform->getCreateDatabaseSql('foobar')); + } + + public function testDropDatabaseThrowsException() + { + $this->assertEquals('DROP USER foobar CASCADE', $this->_platform->getDropDatabaseSql('foobar')); + } + + public function testDropTable() + { + $this->assertEquals('DROP TABLE foobar', $this->_platform->getDropTableSql('foobar')); + } + + public function testGeneratesTypeDeclarationForIntegers() + { + $this->assertEquals( + 'NUMBER(10)', + $this->_platform->getIntegerTypeDeclarationSql(array()) + ); + $this->assertEquals( + 'NUMBER(10)', + $this->_platform->getIntegerTypeDeclarationSql(array('autoincrement' => true) + )); + $this->assertEquals( + 'NUMBER(10)', + $this->_platform->getIntegerTypeDeclarationSql( + array('autoincrement' => true, 'primary' => true) + )); + } + + public function testGeneratesTypeDeclarationsForStrings() + { + $this->assertEquals( + 'CHAR(10)', + $this->_platform->getVarcharTypeDeclarationSql( + array('length' => 10, 'fixed' => true) + )); + $this->assertEquals( + 'VARCHAR2(50)', + $this->_platform->getVarcharTypeDeclarationSql(array('length' => 50)), + 'Variable string declaration is not correct' + ); + $this->assertEquals( + 'VARCHAR2(4000)', + $this->_platform->getVarcharTypeDeclarationSql(array()), + 'Long string declaration is not correct' + ); + } + + public function testPrefersIdentityColumns() + { + $this->assertFalse($this->_platform->prefersIdentityColumns()); + } + + public function testSupportsIdentityColumns() + { + $this->assertFalse($this->_platform->supportsIdentityColumns()); + } + + public function testSupportsSavePoints() + { + $this->assertTrue($this->_platform->supportsSavepoints()); + } + + public function testGeneratesConstraintCreationSql() + { + $sql = $this->_platform->getCreateConstraintSql('test', 'constraint_name', array('fields' => array('test' => array()))); + $this->assertEquals($sql, 'ALTER TABLE test ADD CONSTRAINT constraint_name (test)'); + } + + public function testGeneratesIndexCreationSql() + { + $indexDef = array( + 'fields' => array( + 'user_name' => array( + 'sorting' => 'ASC', + 'length' => 10 + ), + 'last_login' => array() + ) + ); + + $this->assertEquals( + 'CREATE INDEX my_idx ON mytable (user_name, last_login)', + $this->_platform->getCreateIndexSql('mytable', 'my_idx', $indexDef) + ); + } + + public function testGeneratesUniqueIndexCreationSql() + { + $sql = $this->_platform->getCreateIndexSql('test', 'index_name', array('type' => 'unique', 'fields' => array('test', 'test2'))); + $this->assertEquals($sql, 'CREATE UNIQUE INDEX index_name ON test (test, test2)'); + } + + public function testGeneratesForeignKeyCreationSql() + { + $sql = $this->_platform->getCreateForeignKeySql('test', array('foreignTable' => 'other_table', 'local' => 'fk_name_id', 'foreign' => 'id')); + $this->assertEquals($sql, 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table(id)'); + } + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT a.* FROM (SELECT * FROM user) a WHERE ROWNUM <= 10', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT a.* FROM (SELECT * FROM user) a WHERE ROWNUM <= 10', $sql); + } + + public function testModifyLimitQueryWithAscOrderBy() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10); + $this->assertEquals('SELECT a.* FROM (SELECT * FROM user ORDER BY username ASC) a WHERE ROWNUM <= 10', $sql); + } + + public function testModifyLimitQueryWithDescOrderBy() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10); + $this->assertEquals('SELECT a.* FROM (SELECT * FROM user ORDER BY username DESC) a WHERE ROWNUM <= 10', $sql); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php index 1b2f8426a..69a86b264 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php @@ -208,4 +208,16 @@ class PostgreSqlPlatformTest extends \Doctrine\Tests\DbalTestCase { $this->assertTrue($this->_platform->supportsSequences()); } -} + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT * FROM user OFFSET 0 LIMIT 10', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT * FROM user LIMIT 10', $sql); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php index c4aad2b77..025eb110d 100644 --- a/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php +++ b/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php @@ -110,4 +110,16 @@ class SqlitePlatformTest extends \Doctrine\Tests\DbalTestCase $sql = $this->_platform->getCreateForeignKeySql('test', array('foreignTable' => 'other_table', 'local' => 'fk_name_id', 'foreign' => 'id')); $this->assertEquals('ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table(id)', $sql); } -} + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT * FROM user OFFSET 0 LIMIT 10', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT * FROM user LIMIT 10', $sql); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 3b8616d65..c5e98b456 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -320,4 +320,23 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ); }*/ -} + + public function testLimitFromQueryClass() + { + $q = $this->_em + ->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u') + ->setMaxResults(10); + + $this->assertEquals('SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ LIMIT 10', $q->getSql()); + } + + public function testLimitAndOffsetFromQueryClass() + { + $q = $this->_em + ->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u') + ->setMaxResults(10) + ->setFirstResult(0); + + $this->assertEquals('SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ OFFSET 0 LIMIT 10', $q->getSql()); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/TestInit.php b/tests/Doctrine/Tests/TestInit.php index d36cc63e6..ce85b4ec2 100644 --- a/tests/Doctrine/Tests/TestInit.php +++ b/tests/Doctrine/Tests/TestInit.php @@ -13,5 +13,4 @@ $classLoader = new \Doctrine\Common\ClassLoader(); set_include_path( get_include_path() . PATH_SEPARATOR . __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'lib' -); - +); \ No newline at end of file