Select New operator doesn't support NULL #6808

Open
opened 2026-01-22 15:39:07 +01:00 by admin · 3 comments
Owner

Originally created by @carnage on GitHub (Aug 14, 2021).

Bug Report

Q A
BC Break no
Version 2.10.x

Summary

        $dql = "
            SELECT
                new Doctrine\Tests\Models\CMS\CmsUserDTO(
                    u.name,
                    'fabio.bat.silva@gmail.com',
                    null,
                    123
                )
            FROM
                Doctrine\Tests\Models\CMS\CmsUser u
            JOIN
                u.email e
            JOIN
                u.address a
            JOIN
                u.phonenumbers p
            GROUP BY
                u, e, a
            ORDER BY
                u.name";

Results in the error: Doctrine\ORM\Query\QueryException: [Syntax Error] line 0, col 175: Error: Unexpected 'null'

Documentation says you can use any scalar expression in the fields of the new statement

Current behavior

True, false, ints and strings are supported, null should be included for completeness

How to reproduce

Here's a test case

   public function testShouldSupportNullInNewExpression(): void
    {
        $dql = "
            SELECT
                new Doctrine\Tests\Models\CMS\CmsUserDTO(
                    u.name,
                    'fabio.bat.silva@gmail.com',
                    null,
                    123
                )
            FROM
                Doctrine\Tests\Models\CMS\CmsUser u
            JOIN
                u.email e
            JOIN
                u.address a
            JOIN
                u.phonenumbers p
            GROUP BY
                u, e, a
            ORDER BY
                u.name";

        $query  = $this->_em->createQuery($dql);
        $result = $query->getResult();

        self::assertCount(3, $result);

        self::assertInstanceOf(CmsUserDTO::class, $result[0]);
        self::assertInstanceOf(CmsUserDTO::class, $result[1]);
        self::assertInstanceOf(CmsUserDTO::class, $result[2]);

        self::assertEquals($this->fixtures[0]->name, $result[0]->name);
        self::assertEquals($this->fixtures[1]->name, $result[1]->name);
        self::assertEquals($this->fixtures[2]->name, $result[2]->name);

        self::assertEquals('fabio.bat.silva@gmail.com', $result[0]->email);
        self::assertEquals('fabio.bat.silva@gmail.com', $result[1]->email);
        self::assertEquals('fabio.bat.silva@gmail.com', $result[2]->email);

        self::assertNull($result[0]->address);
        self::assertNull($result[1]->address);
        self::assertNull($result[2]->address);

        self::assertEquals(123, $result[0]->phonenumbers);
        self::assertEquals(123, $result[1]->phonenumbers);
        self::assertEquals(123, $result[2]->phonenumbers);
    }
Originally created by @carnage on GitHub (Aug 14, 2021). ### Bug Report | Q | A |------------ | ------ | BC Break | no | Version | 2.10.x #### Summary ``` $dql = " SELECT new Doctrine\Tests\Models\CMS\CmsUserDTO( u.name, 'fabio.bat.silva@gmail.com', null, 123 ) FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.email e JOIN u.address a JOIN u.phonenumbers p GROUP BY u, e, a ORDER BY u.name"; ``` Results in the error: `Doctrine\ORM\Query\QueryException: [Syntax Error] line 0, col 175: Error: Unexpected 'null'` Documentation says you can use any scalar expression in the fields of the new statement #### Current behavior True, false, ints and strings are supported, null should be included for completeness #### How to reproduce Here's a test case ``` public function testShouldSupportNullInNewExpression(): void { $dql = " SELECT new Doctrine\Tests\Models\CMS\CmsUserDTO( u.name, 'fabio.bat.silva@gmail.com', null, 123 ) FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.email e JOIN u.address a JOIN u.phonenumbers p GROUP BY u, e, a ORDER BY u.name"; $query = $this->_em->createQuery($dql); $result = $query->getResult(); self::assertCount(3, $result); self::assertInstanceOf(CmsUserDTO::class, $result[0]); self::assertInstanceOf(CmsUserDTO::class, $result[1]); self::assertInstanceOf(CmsUserDTO::class, $result[2]); self::assertEquals($this->fixtures[0]->name, $result[0]->name); self::assertEquals($this->fixtures[1]->name, $result[1]->name); self::assertEquals($this->fixtures[2]->name, $result[2]->name); self::assertEquals('fabio.bat.silva@gmail.com', $result[0]->email); self::assertEquals('fabio.bat.silva@gmail.com', $result[1]->email); self::assertEquals('fabio.bat.silva@gmail.com', $result[2]->email); self::assertNull($result[0]->address); self::assertNull($result[1]->address); self::assertNull($result[2]->address); self::assertEquals(123, $result[0]->phonenumbers); self::assertEquals(123, $result[1]->phonenumbers); self::assertEquals(123, $result[2]->phonenumbers); } ```
Author
Owner

@SenseException commented on GitHub (Aug 14, 2021):

PHP's is_scalar doesn't see null as scalar too (https://3v4l.org/SaZGu) but I actually would like to see null to be supported. I would consider this a feature request.

@SenseException commented on GitHub (Aug 14, 2021): PHP's `is_scalar` doesn't see `null` as scalar too (https://3v4l.org/SaZGu) but I actually would like to see null to be supported. I would consider this a feature request.
Author
Owner

@carnage commented on GitHub (Aug 15, 2021):

Looked into this and its going to be a nightmare to fix, parser dosent seem to accept null as a literal /anywhere/

class Literal extends Node
{
    public const STRING  = 1;
    public const BOOLEAN = 2;
    public const NUMERIC = 3;
}

So the first thing to decide is: will there be any side effects from adding a case for null to the literal class; how should they be handled; would it be better to add a specific Null AST node which can then be restricted to only being used in specific context's such as New expressions?

@carnage commented on GitHub (Aug 15, 2021): Looked into this and its going to be a nightmare to fix, parser dosent seem to accept null as a literal /anywhere/ ``` class Literal extends Node { public const STRING = 1; public const BOOLEAN = 2; public const NUMERIC = 3; } ``` So the first thing to decide is: will there be any side effects from adding a case for null to the literal class; how should they be handled; would it be better to add a specific Null AST node which can then be restricted to only being used in specific context's such as New expressions?
Author
Owner

@greg0ire commented on GitHub (Aug 15, 2021):

I also looked into it, and saw that occurrences of NULL were supported as part of a comparison:
d636d79686/lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php (L24)

That makes sense since NULL is special in SQL. Here, we are talking about PHP's null though, since we are constructing a PHP object.

IMO a specific AST node would be better. I suggest NewObjectNullArg as a name.

@greg0ire commented on GitHub (Aug 15, 2021): I also looked into it, and saw that occurrences of `NULL` were supported as part of a comparison: https://github.com/doctrine/orm/blob/d636d796868e90c43889e5510598686427e29dc7/lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php#L24 That makes sense since `NULL` is special in SQL. Here, we are talking about PHP's `null` though, since we are constructing a PHP object. IMO a specific AST node would be better. I suggest `NewObjectNullArg` as a name.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6808