DDC-1298: SqlWalker->walkSelectClause imploding empty strings results in invalid query #1631

Closed
opened 2026-01-22 13:20:28 +01:00 by admin · 3 comments
Owner

Originally created by @doctrinebot on GitHub (Jul 27, 2011).

Originally assigned to: @beberlei on GitHub.

Jira issue originally created by user tbo:

Given the following MySQL structure

CREATE TABLE `bar` (
  `barID` int(11) NOT NULL AUTO_INCREMENT,
  `barReference` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`barID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='module=bug';

CREATE TABLE `foo` (
  `fooID` int(11) NOT NULL AUTO_INCREMENT,
  `fooReference` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`fooID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='module=bug';

CREATE TABLE `fooBar` (
  `fooID` int(11) NOT NULL,
  `barID` int(11) NOT NULL,
  PRIMARY KEY (`fooID`,`barID`),
  KEY `fk_foo1` (`fooID`),
  KEY `fk_bar1` (`barID`),
  CONSTRAINT `fk*table1*foo1` FOREIGN KEY (`fooID`) REFERENCES `foo` (`fooID`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `fk*table1*bar1` FOREIGN KEY (`barID`) REFERENCES `bar` (`barID`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='module=bug';

INSERT INTO `bar` (`barID`, `barReference`)
VALUES
    (1, 'bar1'),
    (2, 'bar2');

INSERT INTO `foo` (`fooID`, `fooReference`)
VALUES
    (1, 'foo1');

INSERT INTO `fooBar` (`fooID`, `barID`)
VALUES
    (1, 1);

the following models:

use Doctrine\ORM\Mapping as ORM;

/****
 * Model for foo
 *
 * @category Application
 * @package Bug
 * @subpackage Model
 * @ORM\Table(name="foo")
 * @ORM\Entity
 */
class Bug*Model*Foo
{
    /****
     * @var integer fooID
     * @ORM\Column(name="fooID", type="integer", nullable=false)
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Id
     */
    protected $_fooID = null;

    /****
     * @var string fooReference
     * @ORM\Column(name="fooReference", type="string", nullable=true, length=45)
     */
    protected $_fooReference = null;

    /****
     * @ORM\OneToMany(targetEntity="Bug*Model_FooBar", mappedBy="*foo",
     * cascade={"persist"})
     */
    protected $_fooBarRefFoo = null;

    /****
     * Constructor
     *
     * @param array|Zend_Config|null $options
     * @return Bug*Model*Foo
     */
    public function **construct($options = null)
    {
        $this->_fooBarRefFoo = new \Doctrine\Common\Collections\ArrayCollection();
        parent::**construct($options);
    }

}
use Doctrine\ORM\Mapping as ORM;

/****
 * Model for bar
 *
 * @category Application
 * @package Bug
 * @subpackage Model
 * @ORM\Table(name="bar")
 * @ORM\Entity
 */
class Bug*Model*Bar
{
    /****
     * @var integer barID
     * @ORM\Column(name="barID", type="integer", nullable=false)
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Id
     */
    protected $_barID = null;

    /****
     * @var string barReference
     * @ORM\Column(name="barReference", type="string", nullable=true, length=45)
     */
    protected $_barReference = null;

    /****
     * @ORM\OneToMany(targetEntity="Bug*Model_FooBar", mappedBy="*bar",
     * cascade={"persist"})
     */
    protected $_fooBarRefBar = null;

    /****
     * Constructor
     *
     * @param array|Zend_Config|null $options
     * @return Bug*Model*Bar
     */
    public function **construct($options = null)
    {
        $this->_fooBarRefBar = new \Doctrine\Common\Collections\ArrayCollection();
        parent::**construct($options);
    }
}

use Doctrine\ORM\Mapping as ORM;

/****
 * Model for fooBar
 *
 * @category Application
 * @package Bug
 * @subpackage Model
 * @ORM\Table(name="fooBar")
 * @ORM\Entity
 */
class Bug*Model*FooBar
{
    /****
     * @ORM\ManyToOne(targetEntity="Bug*Model*Foo")
     * @ORM\JoinColumn(name="fooID", referencedColumnName="fooID")
     * @ORM\Id
     */
    protected $_foo = null;

    /****
     * @ORM\ManyToOne(targetEntity="Bug*Model*Bar")
     * @ORM\JoinColumn(name="barID", referencedColumnName="barID")
     * @ORM\Id
     */
    protected $_bar = null;

}

and using the following DQL:

SELECT 
    f, b, fb 
FROM 
    Bug*Model*Foo f 
JOIN 
    f._fooBarRefFoo fb
JOIN
    fb._bar b

will result in the following sql query:

SELECT f0*.fooID AS fooID0, f0_.fooReference AS fooReference1, , b1_.barID AS barID2, b1_.barReference AS barReference3, f2_.fooID AS fooID4, f2_.barID AS barID5 FROM foo f0_ INNER JOIN fooBar f2_ ON f0_.fooID = f2_.fooID INNER JOIN bar b1_ ON f2_.barID = b1*.barID

there are 2 comma's between "f0_.fooReference AS fooReference1" and "b1_.barID AS barID2" resulting in an invalid query.

The first line of the walkSelectClause function in Doctrine/ORM/Query/SqlWalker.php will implode the result of the array_map.
But you receive an empty result from processing the data for the selectExpression "fb" explaining why you got the extra comma.

This worked in a previous version when 2.1 was still in development.

Originally created by @doctrinebot on GitHub (Jul 27, 2011). Originally assigned to: @beberlei on GitHub. Jira issue originally created by user tbo: Given the following MySQL structure ``` CREATE TABLE `bar` ( `barID` int(11) NOT NULL AUTO_INCREMENT, `barReference` varchar(45) DEFAULT NULL, PRIMARY KEY (`barID`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='module=bug'; CREATE TABLE `foo` ( `fooID` int(11) NOT NULL AUTO_INCREMENT, `fooReference` varchar(45) DEFAULT NULL, PRIMARY KEY (`fooID`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='module=bug'; CREATE TABLE `fooBar` ( `fooID` int(11) NOT NULL, `barID` int(11) NOT NULL, PRIMARY KEY (`fooID`,`barID`), KEY `fk_foo1` (`fooID`), KEY `fk_bar1` (`barID`), CONSTRAINT `fk*table1*foo1` FOREIGN KEY (`fooID`) REFERENCES `foo` (`fooID`) ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT `fk*table1*bar1` FOREIGN KEY (`barID`) REFERENCES `bar` (`barID`) ON DELETE CASCADE ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='module=bug'; INSERT INTO `bar` (`barID`, `barReference`) VALUES (1, 'bar1'), (2, 'bar2'); INSERT INTO `foo` (`fooID`, `fooReference`) VALUES (1, 'foo1'); INSERT INTO `fooBar` (`fooID`, `barID`) VALUES (1, 1); ``` the following models: ``` use Doctrine\ORM\Mapping as ORM; /**** * Model for foo * * @category Application * @package Bug * @subpackage Model * @ORM\Table(name="foo") * @ORM\Entity */ class Bug*Model*Foo { /**** * @var integer fooID * @ORM\Column(name="fooID", type="integer", nullable=false) * @ORM\GeneratedValue(strategy="IDENTITY") * @ORM\Id */ protected $_fooID = null; /**** * @var string fooReference * @ORM\Column(name="fooReference", type="string", nullable=true, length=45) */ protected $_fooReference = null; /**** * @ORM\OneToMany(targetEntity="Bug*Model_FooBar", mappedBy="*foo", * cascade={"persist"}) */ protected $_fooBarRefFoo = null; /**** * Constructor * * @param array|Zend_Config|null $options * @return Bug*Model*Foo */ public function **construct($options = null) { $this->_fooBarRefFoo = new \Doctrine\Common\Collections\ArrayCollection(); parent::**construct($options); } } ``` ``` use Doctrine\ORM\Mapping as ORM; /**** * Model for bar * * @category Application * @package Bug * @subpackage Model * @ORM\Table(name="bar") * @ORM\Entity */ class Bug*Model*Bar { /**** * @var integer barID * @ORM\Column(name="barID", type="integer", nullable=false) * @ORM\GeneratedValue(strategy="IDENTITY") * @ORM\Id */ protected $_barID = null; /**** * @var string barReference * @ORM\Column(name="barReference", type="string", nullable=true, length=45) */ protected $_barReference = null; /**** * @ORM\OneToMany(targetEntity="Bug*Model_FooBar", mappedBy="*bar", * cascade={"persist"}) */ protected $_fooBarRefBar = null; /**** * Constructor * * @param array|Zend_Config|null $options * @return Bug*Model*Bar */ public function **construct($options = null) { $this->_fooBarRefBar = new \Doctrine\Common\Collections\ArrayCollection(); parent::**construct($options); } } ``` ``` use Doctrine\ORM\Mapping as ORM; /**** * Model for fooBar * * @category Application * @package Bug * @subpackage Model * @ORM\Table(name="fooBar") * @ORM\Entity */ class Bug*Model*FooBar { /**** * @ORM\ManyToOne(targetEntity="Bug*Model*Foo") * @ORM\JoinColumn(name="fooID", referencedColumnName="fooID") * @ORM\Id */ protected $_foo = null; /**** * @ORM\ManyToOne(targetEntity="Bug*Model*Bar") * @ORM\JoinColumn(name="barID", referencedColumnName="barID") * @ORM\Id */ protected $_bar = null; } ``` and using the following DQL: ``` SELECT f, b, fb FROM Bug*Model*Foo f JOIN f._fooBarRefFoo fb JOIN fb._bar b ``` will result in the following sql query: ``` SELECT f0*.fooID AS fooID0, f0_.fooReference AS fooReference1, , b1_.barID AS barID2, b1_.barReference AS barReference3, f2_.fooID AS fooID4, f2_.barID AS barID5 FROM foo f0_ INNER JOIN fooBar f2_ ON f0_.fooID = f2_.fooID INNER JOIN bar b1_ ON f2_.barID = b1*.barID ``` there are 2 comma's between "f0_.fooReference AS fooReference1" and "b1_.barID AS barID2" resulting in an invalid query. The first line of the walkSelectClause function in Doctrine/ORM/Query/SqlWalker.php will implode the result of the array_map. But you receive an empty result from processing the data for the selectExpression "fb" explaining why you got the extra comma. This worked in a previous version when 2.1 was still in development.
admin added the Bug label 2026-01-22 13:20:28 +01:00
admin closed this issue 2026-01-22 13:20:29 +01:00
Author
Owner

@doctrinebot commented on GitHub (Jul 27, 2011):

Comment created by tbo:

I have fixed it and made a pull request: https://github.com/doctrine/doctrine2/pull/96

@doctrinebot commented on GitHub (Jul 27, 2011): Comment created by tbo: I have fixed it and made a pull request: https://github.com/doctrine/doctrine2/pull/96
Author
Owner

@doctrinebot commented on GitHub (Jul 28, 2011):

Comment created by @beberlei:

Fixed

@doctrinebot commented on GitHub (Jul 28, 2011): Comment created by @beberlei: Fixed
Author
Owner

@doctrinebot commented on GitHub (Jul 28, 2011):

Issue was closed with resolution "Fixed"

@doctrinebot commented on GitHub (Jul 28, 2011): Issue was closed with resolution "Fixed"
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#1631