Google Groups Home
Help | Sign in
r4372 - in branches/0.11: lib/Doctrine lib/Doctrine/Connection tests/Query
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  1 message - Collapse all
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
no-re...@phpdoctrine.org  
View profile
 More options May 17, 8:01 am
From: no-re...@phpdoctrine.org
Date: Sat, 17 May 2008 13:01:50 +0100
Local: Sat, May 17 2008 8:01 am
Subject: r4372 - in branches/0.11: lib/Doctrine lib/Doctrine/Connection tests/Query
Author: romanb
Date: 2008-05-17 13:01:48 +0100 (Sat, 17 May 2008)
New Revision: 4372

Modified:
   branches/0.11/lib/Doctrine/Connection.php
   branches/0.11/lib/Doctrine/Connection/Db2.php
   branches/0.11/lib/Doctrine/Connection/Oracle.php
   branches/0.11/lib/Doctrine/Query.php
   branches/0.11/tests/Query/DriverTestCase.php
Log:
Fixed #1039. bruno.p.reis: please take a look at the changeset and verify that the generated SQL is correct. We can't test against a real oracle db yet.

Modified: branches/0.11/lib/Doctrine/Connection/Db2.php
===================================================================
--- branches/0.11/lib/Doctrine/Connection/Db2.php       2008-05-17 01:21:57 UTC (rev 4371)
+++ branches/0.11/lib/Doctrine/Connection/Db2.php       2008-05-17 12:01:48 UTC (rev 4372)
@@ -55,8 +55,8 @@
             $col = explode('select', $select);

             $sql = 'WITH OFFSET AS(' . $select . ', ROW_NUMBER() ' .
-               'OVER(ORDER BY ' . $col[1] . ') AS dctrn_rownum FROM ' . $table . ')' .
-               $select . 'FROM OFFSET WHERE dctrn_rownum BETWEEN ' . $offset .
+               'OVER(ORDER BY ' . $col[1] . ') AS doctrine_rownum FROM ' . $table . ')' .
+               $select . 'FROM OFFSET WHERE doctrine_rownum BETWEEN ' . $offset .
                    'AND ' . ($offset + $limit - 1);
             return $sql;
         }

Modified: branches/0.11/lib/Doctrine/Connection/Oracle.php
===================================================================
--- branches/0.11/lib/Doctrine/Connection/Oracle.php    2008-05-17 01:21:57 UTC (rev 4371)
+++ branches/0.11/lib/Doctrine/Connection/Oracle.php    2008-05-17 12:01:48 UTC (rev 4372)
@@ -82,6 +82,11 @@
      */
     public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false)
     {
+        return $this->_createLimitSubquery($query, $limit, $offset);
+    }
+    
+    private function _createLimitSubquery($query, $limit, $offset, $column = null)
+    {
         $limit = (int) $limit;
         $offset = (int) $offset;
         if (preg_match('/^\s*SELECT/i', $query)) {
@@ -89,20 +94,37 @@
                 $query .= " FROM dual";
             }
             if ($limit > 0) {
-                // taken from http://svn.ez.no/svn/ezcomponents/packages/Database
                 $max = $offset + $limit;
+                $column = $column === null ? '*' : $column;
                 if ($offset > 0) {
                     $min = $offset + 1;
-                    $query = 'SELECT b.* FROM (
-                                 SELECT a.*, ROWNUM AS doctrine_rownum FROM ('
-                                  . $query . ') a
-                              ) b
-                              WHERE b.doctrine_rownum BETWEEN ' . $min .  ' AND ' . $max;
+                    $query = 'SELECT b.'.$column.' FROM ('.
+                                 'SELECT a.*, ROWNUM AS doctrine_rownum FROM ('
+                                   . $query . ') a '.
+                              ') b '.
+                              'WHERE doctrine_rownum BETWEEN ' . $min .  ' AND ' . $max;
                 } else {
-                    $query = 'SELECT a.* FROM (' . $query .') a WHERE ROWNUM <= ' . $max;
+                    $query = 'SELECT a.'.$column.' FROM (' . $query .') a WHERE ROWNUM <= ' . $max;
                 }
             }
         }
         return $query;
     }
+    
+    /**
+     * Creates the SQL for Oracle that can be used in the subquery for the limit-subquery
+     * algorithm.
+     */
+    public function modifyLimitSubquery(Doctrine_Table $rootTable, $query, $limit = false,
+            $offset = false, $isManip = false)
+    {
+        // NOTE: no composite key support
+        $columnNames = $rootTable->getIdentifierColumnNames();
+        if (count($columnNames) > 1) {
+            throw new Doctrine_Connection_Exception("Composite keys in LIMIT queries are "
+                    . "currently not supported.");
+        }
+        $column = $columnNames[0];
+        return $this->_createLimitSubquery($query, $limit, $offset, $column);
+    }
 }
\ No newline at end of file

Modified: branches/0.11/lib/Doctrine/Connection.php
===================================================================
--- branches/0.11/lib/Doctrine/Connection.php   2008-05-17 01:21:57 UTC (rev 4371)
+++ branches/0.11/lib/Doctrine/Connection.php   2008-05-17 12:01:48 UTC (rev 4372)
@@ -1503,12 +1503,24 @@
      *
      * Some dbms require specific functionality for this. Check the other connection adapters for examples
      *
-     * @return void
+     * @return string
      */
     public function modifyLimitQuery($query, $limit = false, $offset = false, $isManip = false)
     {
         return $query;
     }
+    
+    /**
+     * Creates dbms specific LIMIT/OFFSET SQL for the subqueries that are used in the
+     * context of the limit-subquery algorithm.
+     *
+     * @return string
+     */
+    public function modifyLimitSubquery(Doctrine_Table $rootTable, $query, $limit = false,
+            $offset = false, $isManip = false)
+    {
+        return $this->modifyLimitQuery($query, $limit, $offset, $isManip);
+    }

     /**
      * returns a string representation of this object

Modified: branches/0.11/lib/Doctrine/Query.php
===================================================================
--- branches/0.11/lib/Doctrine/Query.php        2008-05-17 01:21:57 UTC (rev 4371)
+++ branches/0.11/lib/Doctrine/Query.php        2008-05-17 12:01:48 UTC (rev 4372)
@@ -1201,7 +1201,6 @@

         $modifyLimit = true;
         if ( ! empty($this->_sqlParts['limit']) || ! empty($this->_sqlParts['offset'])) {
-
             if ($needsSubQuery) {
                 $subquery = $this->getLimitSubquery();
                 // what about composite keys?
@@ -1209,7 +1208,7 @@
                 switch (strtolower($this->_conn->getDriverName())) {
                     case 'mysql':
                         // mysql doesn't support LIMIT in subqueries
-                        $list     = $this->_conn->execute($subquery, $params)->fetchAll(Doctrine::FETCH_COLUMN);
+                        $list = $this->_conn->execute($subquery, $params)->fetchAll(Doctrine::FETCH_COLUMN);
                         $subquery = implode(', ', array_map(array($this->_conn, 'quote'), $list));
                         break;
                     case 'pgsql':
@@ -1263,17 +1262,17 @@
      */
     public function getLimitSubquery()
     {
-        $map    = reset($this->_queryComponents);
-        $table  = $map['table'];
+        $map = reset($this->_queryComponents);
+        $table = $map['table'];
         $componentAlias = key($this->_queryComponents);

         // get short alias
-        $alias      = $this->getTableAlias($componentAlias);
+        $alias = $this->getTableAlias($componentAlias);
         // what about composite keys?
         $primaryKey = $alias . '.' . $table->getColumnName($table->getIdentifier());

         // initialize the base of the subquery
-        $subquery   = 'SELECT DISTINCT ' . $this->_conn->quoteIdentifier($primaryKey);
+        $subquery = 'SELECT DISTINCT ' . $this->_conn->quoteIdentifier($primaryKey);

         $driverName = $this->_conn->getAttribute(Doctrine::ATTR_DRIVER_NAME);

@@ -1331,7 +1330,7 @@
         $subquery .= ( ! empty($this->_sqlParts['orderby']))? ' ORDER BY ' . implode(', ', $this->_sqlParts['orderby'])   : '';

         // add driver specific limit clause
-        $subquery = $this->_conn->modifyLimitQuery($subquery, $this->_sqlParts['limit'], $this->_sqlParts['offset']);
+        $subquery = $this->_conn->modifyLimitSubquery($table, $subquery, $this->_sqlParts['limit'], $this->_sqlParts['offset']);

         $parts = $this->_tokenizer->quoteExplode($subquery, ' ', "'", "'");

Modified: branches/0.11/tests/Query/DriverTestCase.php
===================================================================
--- branches/0.11/tests/Query/DriverTestCase.php        2008-05-17 01:21:57 UTC (rev 4371)
+++ branches/0.11/tests/Query/DriverTestCase.php        2008-05-17 12:01:48 UTC (rev 4372)
@@ -99,6 +99,36 @@

         $q->from('User u')->limit(5)->offset(2);

-        $this->assertEqual($q->getSql(), 'SELECT * FROM (SELECT a.*, ROWNUM dctrn_rownum FROM (SELECT e.id AS e__id, e.name AS e__name, e.loginname AS e__loginname, e.password AS e__password, e.type AS e__type, e.created AS e__created, e.updated AS e__updated, e.email_id AS e__email_id FROM entity e WHERE (e.type = 0)) a WHERE ROWNUM <= 7) WHERE dctrn_rownum >= 3');
+        $this->assertEqual($q->getSql(), 'SELECT b.* FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT e.id AS e__id, e.name AS e__name, e.loginname AS e__loginname, e.password AS e__password, e.type AS e__type, e.created AS e__created, e.updated AS e__updated, e.email_id AS e__email_id FROM entity e WHERE (e.type = 0)) a ) b WHERE doctrine_rownum BETWEEN 3 AND 7');
     }
+    
+    public function testLimitOffsetLimitSubqueriesForOracle()
+    {
+        $this->dbh = new Doctrine_Adapter_Mock('oracle');
+        $conn = $this->manager->openConnection($this->dbh);
+        $q = new Doctrine_Query($conn);
+        $q->from('User u')->innerJoin('u.Phonenumber p')->limit(5)->offset(2);
+        
+        $correctSql = "SELECT e.id AS e__id, e.name AS e__name, e.loginname AS e__loginname, "
+                            . "e.password AS e__password, e.type AS e__type, e.created AS e__created, "
+                            . "e.updated AS e__updated, e.email_id AS e__email_id, p.id AS p__id, "
+                            . "p.phonenumber AS p__phonenumber, p.entity_id AS p__entity_id "
+                            . "FROM entity e "
+                            . "INNER JOIN phonenumber p ON e.id = p.entity_id "
+                            . "WHERE e.id IN ("
+                                . "SELECT b.id FROM ("
+                                    . "SELECT a.*, ROWNUM AS doctrine_rownum "
+                                    . "FROM ("
+                                        . "SELECT DISTINCT e2.id "
+                                        . "FROM entity e2 "
+                                        . "INNER JOIN phonenumber p2 ON e2.id = p2.entity_id "
+                                        . "WHERE (e2.type = 0)"
+                                    . ") a"
+                                . " ) b "
+                                . "WHERE doctrine_rownum BETWEEN 3 AND 7"
+                            . ") AND (e.type = 0)";
+        
+        $this->assertEqual($q->getSql(), $correctSql);
+    }
+    
 }


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2008 Google