doctrine / orm

Doctrine Object Relational Mapper (ORM)
https://www.doctrine-project.org/projects/orm.html
MIT License
9.86k stars 2.5k forks source link

groupBY with identification alias is missing discriminator field #11459

Open kshtompel opened 1 month ago

kshtompel commented 1 month ago

Bug Report

While using groupBy(DQL_ALIAS) for aggregated query resulted SQL with missing discriminator field and this is leading to

[42803] ERROR: column "p0_.type" must appear in the GROUP BY clause or be used in an aggregate function

Q A
BC Break no
Version 2.x.x, 3.x.x, 4.x.x

Summary

Suggestion to fix

class SqlWalker implements TreeWalker
{
    ...

    public function walkGroupByItem($groupByItem)
    {

    ...

       // IdentificationVariable
        $sqlParts = [];

        foreach ($this->getMetadataForDqlAlias($groupByItem)->fieldNames as $field) {
            $item       = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $field);
            $item->type = AST\PathExpression::TYPE_STATE_FIELD;

            $sqlParts[] = $this->walkPathExpression($item);
        }

        foreach ($this->getMetadataForDqlAlias($groupByItem)->associationMappings as $mapping) {
            if ($mapping['isOwningSide'] && $mapping['type'] & ClassMetadata::TO_ONE) {
                $item       = new AST\PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $groupByItem, $mapping['fieldName']);
                $item->type = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;

                $sqlParts[] = $this->walkPathExpression($item);
            }
        }

        ### NEW CODE HERE ###
        if ($this->getMetadataForDqlAlias($groupByItem)->isInheritanceTypeSingleTable()) {
            $field = $this->getMetadataForDqlAlias($groupByItem)->getDiscriminatorColumn()['name'];
            $sqlParts[] = $this->walkIdentificationVariable($groupByItem, $field) . '.' . $field;
        }
        // or add it as part of $this->walkPathExpression($item) with new AST\PathExpression::TYPE_DISCRIMINATOR
        ### END OF NEW CODE ###

        return implode(', ', $sqlParts);

Current behavior

No discriminator field added to GROUP BY clause

How to reproduce

Create aggregated query with group by entity identification alias and entity has discriminator field.

As a result there is no discriminator field in the resulted SQL GROUP BY clause

Expected behavior

All the columns should appear in the SQL GROUP BY clause for aggregated queries

kshtompel commented 1 month ago

Currently can be tackled with inheritance from the base SqlWalker and overriding public function walkGroupByItem($groupByItem): string method

but all the checks from parent should be covered for instance: if $groupByItem is not path_expression, not returning variable, etc..