Skip to content

Loading…

DDC-669: order of fields in sql query and parameters to be bound to the dbal's statement is different #5179

Closed
doctrinebot opened this Issue · 3 comments

2 participants

@doctrinebot

Jira issue originally created by user sergei.lissovski:

Hi guys,

It seems that I found a bug in the Doctrine\ORM\Persisters\BasicEntityPersister. Let me explain.

Put it simply, I have the following entity:

/****
 * @Entity
 */
class Foo
{
    /****
     * @Id
     * @Column(type="integer")
     * @GeneratedValue(strategy="AUTO")
     */
    private $id;
    /****
     * @ManyToOne(targetEntity="Foo", inversedBy="children")
     * @JoinColumn(name="parent_id", referencedColumnName="id")
     */
    private $parent;
    /****
     * @OneToMany(targetEntity="Foo", mappedBy="parent")
     */
    private $children;
    /****
     * @Column(type="integer", nullable=false)
     */
    private $verticalOrder;

    // a bunch of getters/setters

As you can see, there's a mandatory field called "verticalOrder", it is not intended to be managed manually but rather with a listener attached to onFlush event. ( In that listener, after a value for the verticalOrder is set, the uow::recomputeSingleEntityChangeSet() method is invoked, as it was suggested in documentation ).

The thing is that when I persist an instance of this class and then invoke flush ( without providing a value for it, the verticalOrder ), Doctrine dies silently, with no exception being thrown. The easy fix can be done with adding this piece of source code to the BasicEntityPersister on line 218:

if (!$stmt->execute()) {
    throw new \Exception('Unable to execute query: '.var_export($stmt->errorInfo(), true));
}

That was the first problem I have faced with while trying to find out why my entity is not persisted. After I have delved a bit deeper, I found out
that the problem lies in BasicEntityPersister ::_getInsertColumnList()* or in BasicEntityPersister ::_prepareUpdateData(). The thing is that order of columns in the SQL query generated by the BasicEntityPersister::_getInsertColumnList() and values to be bound to the statement and after executed is different. *Line 214 in BasicEntityPersister is meant here.

In my case it was reversed, instead of parent_id, a value for verticalOrder was inserted and vice versa.

Array of parameters to be bound to the Doctrine\DBAL\Statement:

Array
(
    [verticalOrder] => 1278334736 // at the moment timestamp is used rather than MAX from the table
    [parent_id] => 
)

And the query that will be executed:

INSERT INTO Foo(parent_id, verticalOrder) VALUES (?, ?)

These snippets clearly illustrate the point.

I hope I was clear in my explanations.

I will try to devote some spare time and write tests to lock this issue, but i'm not able to say at the moment when it happens.

All the best,
Sergei Lissovski

@doctrinebot

Comment created by @beberlei:

This issue is a duplicate of DDC-656. which was fixed this weekend. The current master has a fix for it.

@doctrinebot

Issue was closed with resolution "Duplicate"

@doctrinebot

Comment created by sergei.lissovski:

Okay, thank you for a quick response. Will take it into account.

@beberlei beberlei was assigned by doctrinebot
@doctrinebot doctrinebot added this to the 2.0-BETA3 milestone
@doctrinebot doctrinebot closed this
@doctrinebot doctrinebot added the Bug label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.