Zend\Db\Sql fix getSqlString for subqueries #5306

wants to merge 2 commits into


None yet

3 participants


Fixed - root query was generated for source platform, but subqueries was generated for sql92 (decorator not using)

  • allow generate sql not only via the Zend\Db\Sql but also through sql objects
  • added decorators for expression
@turrsis turrsis commented on an outdated diff Oct 22, 2013
@@ -173,11 +173,6 @@ public function testInsert()
$mockInsert = $this->mockSql->insert();
- ->method('prepareStatement')
turrsis Oct 22, 2013

I'm not sure to delete this block

@turrsis turrsis referenced this pull request Oct 24, 2013

Update Mysql.php #5334

Zend Framework member

Hi @turrsis. It seems there's alot going on inside this commit. In addition to fixes, it also appears there are new features in here. Could you break this up into smaller PR's so that we can isolate what each PR will be addressing? If they are inter-dependent, we can say that in the issue text.

Zend Framework member

In all honesty, this PR is too big, I'd like to close it. Do you have a simple fix for ensuring subqueries use the same platform object as their parent?


In the near future i will do split and minimize changes, and #5320 too


minimize changes
splitted to #5537

@turrsis turrsis referenced this pull request Jan 5, 2014

Fixes #5642 #5643


To my mind is no sense for split this PR because they are meaningless without one another.
I was split it to 2 commits :
Step1 : Sql\Platform\Platform optimisation - using one object which can select decorator for target platform
Step2 : fix subqueries
@ralphschindler this will be good for you?
Can you say - why Travis is not started for this PR?

Zend Framework member

I guess first, can you provide a sample reproduction script I can start from that demonstrates the subquery problem? With the expected and actual outputs?


You can try this:

   $select    = $this->sql->select()
                ->join(array('subSelect' => $this->sql->select()->limit(1)), 'XXX')
   $platform = new \ZendTest\Db\TestAsset\TrustingMySqlPlatform();
   $sqlString = $this->sql->getSqlStringForSqlObject($select, $platform);

For MySql platform LIMIT should be integer and MUST NOT be quoted.
But for subquery LIMIT is quoted.
Or see this : https://github.com/zendframework/zf2/pull/5306/files#diff-9cfd58105fcbb3b57a5e7ca293be4652R1188

Zend Framework member

I'm hoping to find a simpler solution to the subselect problem, can you try this patch:

diff --git a/library/Zend/Db/Sql/AbstractSql.php b/library/Zend/Db/Sql/AbstractSql.php
index aad983d..e393643 100644
--- a/library/Zend/Db/Sql/AbstractSql.php
+++ b/library/Zend/Db/Sql/AbstractSql.php
@@ -181,7 +181,14 @@ abstract class AbstractSql
             $sql = $stmtContainer->getSql();
         } else {
-            $sql = $subselect->getSqlString($platform);
+            if ($this instanceof Platform\PlatformDecoratorInterface && $this instanceof SqlInterface) {
+                $decorator = clone $this;
+                $decorator->setSubject($subselect);
+                $sql = $decorator->getSqlString($platform);
+            } else {
+                $sql = $subselect->getSqlString($platform);
+            }
         return $sql;
diff --git a/library/Zend/Db/Sql/Select.php b/library/Zend/Db/Sql/Select.php
index 99cd989..4e438ae 100644
--- a/library/Zend/Db/Sql/Select.php
+++ b/library/Zend/Db/Sql/Select.php
@@ -740,7 +740,7 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface
                 $joinName = $platform->quoteIdentifier($joinName[1]) . $platform->getIdentifierSeparator() . $platform->quoteIdentifier($joinName[0]);
             } else {
                 if ($joinName instanceof Select) {
-                    $joinName = '(' . $joinName->processSubSelect($joinName, $platform, $driver, $parameterContainer) . ')';
+                    $joinName = '(' . $this->processSubSelect($joinName, $platform, $driver, $parameterContainer) . ')';
                 } else {
                     $joinName = $platform->quoteIdentifier($joinName);

This is not only join bug, this is the global bug
We has decorators, with overridings :


In Postgresql function CONCAT - con || cat,
In else db CONCAT - CONCAT('con', 'cat'
So - we need decorator for Expression

Zend Framework member

Why wouldn't the decorator override processExpression ?


Overriding processExpression required for Expressions such as CONCAT
( see this http://www.postgresql.org/docs/9.1/static/functions-string.html and http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_concat)

Decorators use this: https://github.com/turrsis/zf2/blob/hotfix/db-sql-refactor/library/Zend/Db/Sql/Platform/Mysql/SelectDecorator.php#L47 - we must clone decorator, we can`t use same decorator for different statements

Zend Framework member

@ralphschindler Can you mark the milestone for this one, please?

@ralphschindler ralphschindler added this to the 3.0.0 milestone Mar 4, 2014
Zend Framework member

The root problem here was fixed in #5794. I realize this was reaching to solve a few more problems, but I think those should likely be feature requests and isolated to individual PR's per feature.


#5794 is not best idea, because exists TOP and LIMIT (http://technet.microsoft.com/en-us/library/ms189835.aspx , http://dev.mysql.com/doc/refman/5.0/en/delete.html) keywords which should be decorated.

$this->delete->from('foo')->where(array('x'=>new Select('y')));
$sql = new Sql(new Adapter(array('driver'=>'mysqli')));
$sql->getSqlPlatform()->setTypeDecorator('Zend\Db\Sql\Delete', new \...\DeleteDecorator);
$actual = $sql->getSqlStringForSqlObject($this->delete);

is failed, because for Select is using the DeleteDecorator

Zend Framework member

Can you provide your DeleteDecorator?


@ralphschindler I have not the DeleteDecorator, but this is real case, and I'm thinking about it.

@turrsis turrsis deleted the unknown repository branch May 7, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment