Zend Framework

Zend_Db_Select generates wrong query when joining

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Duplicate
  • Affects Version/s: 1.6.0RC1, 1.5.3
  • Fix Version/s: 1.8.2
  • Component/s: Zend_Db_Select
  • Labels:
    None

Description

There seems to be a problem with joins generated by Zend_Db_Select.

According to my little reserach query is contructed in _renderFrom it using all tables from $this->_parts[self::FROM], with first table being the table which we're selecting "from" and others are being joined. However this array is ordered diffrently (maybe a problem in _join() ?).

I fixed this by adding a code to _renderFrom which searches for "main" table (joinCondition is empty) and moves it in front of array (yes, I realize this solution is really hacky). Something like this:

@@ -897,6 +897,19 @@
             $this->_parts[self::FROM] = $this->_getDummyTable();
         }

+       // arrange array so first table is first in array. Note this changes state of class
+       // which is not good. We're also not fixing problem but consequence.
+       $first = reset($this->_parts[self::FROM]);
+       if($first["joinCondition"]) {
+               foreach($this->_parts[self::FROM] as $key => $part) {
+                       if($part["joinCondition"]) continue;
+
+                       unset($this->_parts[self::FROM][$key]);
+                       $this->_parts[self::FROM] = array_merge(array($key=>$part), $this->_parts[self::FROM]);
+                       break;
+               }
+       }
+
         $from = array();

         foreach ($this->_parts[self::FROM] as $correlationName => $table) {

this is code snippet demonstrating this behaviour (it's ripped from my project, so it's not really possible to run it by itself - you need so set up adapter and such).

class Model_Runs extends Zend_Db_Table
    protected $_name = "runs";
    protected $_sequence = true;
    protected $_primary = array('id');

    public function blah()
    {
         $select = $this->select();
         $select->join('survey_runs', 'survey_runs.id_run = runs.id', array());
         echo $select->__toString(); die();
    }
}

result:
SELECT "runs".* FROM "survey_runs" INNER JOIN "runs"

expected result:
SELECT "runs".* FROM "runs" INNER JOIN "survey_runs" ON survey_runs.id_run = runs.id

Activity

Hide
Emil Hesslow added a comment -

I ran into the same problem.

A workaround I found was to do

$select = $this->select();
$select->__toString();
$select->join('survey_runs', 'survey_runs.id_run = runs.id', array());

My guess is that when calling __toString it seems that the table name is added to $this->_parts[self::FROM] which means that it is now first in the array and everything works.

Show
Emil Hesslow added a comment - I ran into the same problem. A workaround I found was to do
$select = $this->select();
$select->__toString();
$select->join('survey_runs', 'survey_runs.id_run = runs.id', array());
My guess is that when calling __toString it seems that the table name is added to $this->_parts[self::FROM] which means that it is now first in the array and everything works.
Hide
Ralph Schindler added a comment -

From Christian Grafe

I'd really like to see this bug fixed. If its any help, I think I might
have located the cause for this issue:

// If no fields are specified we assume all fields from primary table
if (!count($fields)) {
     $this->from($primary, self::SQL_WILDCARD, $schema);
     $fields = $this->getPart(Zend_Db_Table_Select::COLUMNS);
}

These lines from Zend_Db_Table_Select::assemble() will add the primary
table to our query, only if we have not joined another table. I would
think that for a Zend_Db_Table_Select query we always want all fields from
the primary table. So, imho the above call to $this->from() should be made
in Zend_Db_Table_Select::__construct(), which fixes the problem for me.

Show
Ralph Schindler added a comment - From Christian Grafe I'd really like to see this bug fixed. If its any help, I think I might have located the cause for this issue:
// If no fields are specified we assume all fields from primary table
if (!count($fields)) {
     $this->from($primary, self::SQL_WILDCARD, $schema);
     $fields = $this->getPart(Zend_Db_Table_Select::COLUMNS);
}
These lines from Zend_Db_Table_Select::assemble() will add the primary table to our query, only if we have not joined another table. I would think that for a Zend_Db_Table_Select query we always want all fields from the primary table. So, imho the above call to $this->from() should be made in Zend_Db_Table_Select::__construct(), which fixes the problem for me.
Hide
Ralph Schindler added a comment -

This has been fixed with the solution in ZF-2546, use $table->select(true) to retrieve a select object with the from part pre-loaded.

Show
Ralph Schindler added a comment - This has been fixed with the solution in ZF-2546, use $table->select(true) to retrieve a select object with the from part pre-loaded.

People

Vote (2)
Watch (3)

Dates

  • Created:
    Updated:
    Resolved: