static bool finalize_grouping_exprs_walker()

in src/backend/parser/cypher_parse_agg.c [510:652]


static bool finalize_grouping_exprs_walker(Node *node,
                                           check_ungrouped_columns_context *context)
{
    ListCell *gl;

    if (node == NULL)
        return false;
    if (IsA(node, Const) || IsA(node, Param))
        return false; /* constants are always acceptable */

    if (IsA(node, Aggref))
    {
        Aggref *agg = (Aggref *) node;

        if ((int) agg->agglevelsup == context->sublevels_up)
        {
            /*
             * If we find an aggregate call of the original level, do not
             * recurse into its normal arguments, ORDER BY arguments, or
             * filter; GROUPING exprs of this level are not allowed there. But
             * check direct arguments as though they weren't in an aggregate.
             */
            bool result;

            Assert(!context->in_agg_direct_args);
            context->in_agg_direct_args = true;
            result = finalize_grouping_exprs_walker((Node *) agg->aggdirectargs,
                                                context);
            context->in_agg_direct_args = false;
            return result;
        }

        /*
         * We can skip recursing into aggregates of higher levels altogether,
         * since they could not possibly contain exprs of concern to us (see
         * transformAggregateCall).  We do need to look at aggregates of lower
         * levels, however.
         */
        if ((int) agg->agglevelsup > context->sublevels_up)
            return false;
    }

    if (IsA(node, GroupingFunc))
    {
        GroupingFunc *grp = (GroupingFunc *) node;

        /*
         * We only need to check GroupingFunc nodes at the exact level to
         * which they belong, since they cannot mix levels in arguments.
         */

        if ((int) grp->agglevelsup == context->sublevels_up)
        {
            ListCell *lc;
            List *ref_list = NIL;

            foreach(lc, grp->args)
            {
                Node *expr = lfirst(lc);
                Index ref = 0;

                if (context->root)
                {
                    expr = flatten_join_alias_vars(context->root,
                                                   (Query *)context->root,
                                                   expr);
                }

                /*
                 * Each expression must match a grouping entry at the current
                 * query level. Unlike the general expression case, we don't
                 * allow functional dependencies or outer references.
                 */

                if (IsA(expr, Var))
                {
                    Var *var = (Var *) expr;

                    if (var->varlevelsup == context->sublevels_up)
                    {
                        foreach(gl, context->groupClauses)
                        {
                            TargetEntry *tle = lfirst(gl);
                            Var *gvar = (Var *) tle->expr;

                            if (IsA(gvar, Var) &&
                                gvar->varno == var->varno &&
                                gvar->varattno == var->varattno &&
                                gvar->varlevelsup == 0)
                            {
                                ref = tle->ressortgroupref;
                                break;
                            }
                        }
                    }
                }
                else if (context->have_non_var_grouping &&
                         context->sublevels_up == 0)
                {
                    foreach(gl, context->groupClauses)
                    {
                        TargetEntry *tle = lfirst(gl);

                        if (equal(expr, tle->expr))
                        {
                           ref = tle->ressortgroupref;
                           break;
                        }
                    }
                }

                if (ref == 0)
                    ereport(ERROR,
                            (errcode(ERRCODE_GROUPING_ERROR),
                             errmsg("arguments to GROUPING must be grouping expressions of the associated query level"),
                             parser_errposition(context->pstate,
                             exprLocation(expr))));

                ref_list = lappend_int(ref_list, ref);
            }

            grp->refs = ref_list;
        }

        if ((int) grp->agglevelsup > context->sublevels_up)
            return false;
    }

    if (IsA(node, Query))
    {
        /* Recurse into subselects */
        bool result;

        context->sublevels_up++;
        result = query_tree_walker((Query *) node,
                                   finalize_grouping_exprs_walker,
                                   (void *) context, 0);
        context->sublevels_up--;
        return result;
    }
    return expression_tree_walker(node, finalize_grouping_exprs_walker,
                                  (void *) context);
}