static bool convert_cypher_walker()

in src/backend/parser/cypher_analyze.c [122:265]


static bool convert_cypher_walker(Node *node, ParseState *pstate)
{
    if (!node)
        return false;

    if (IsA(node, RangeTblEntry))
    {
        RangeTblEntry *rte = (RangeTblEntry *)node;

        switch (rte->rtekind)
        {
        case RTE_SUBQUERY:
            /* traverse other RTE_SUBQUERYs */
            return convert_cypher_walker((Node *)rte->subquery, pstate);
        case RTE_FUNCTION:
            if (is_rte_cypher(rte))
                convert_cypher_to_subquery(rte, pstate);
            return false;
        default:
            return false;
        }
    }

    /*
     * This handles a cypher() call with other function calls in a ROWS FROM
     * expression. We can let the FuncExpr case below handle it but do this
     * here to throw a better error message.
     */
    if (IsA(node, RangeTblFunction))
    {
        RangeTblFunction *rtfunc = (RangeTblFunction *)node;
        FuncExpr *funcexpr = (FuncExpr *)rtfunc->funcexpr;

        /*
         * It is better to throw a kind error message here instead of the
         * internal error message that cypher() throws later when it is called.
         */
        if (is_func_cypher(funcexpr))
        {
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("cypher(...) in ROWS FROM is not supported"),
                     parser_errposition(pstate, exprLocation((Node *)funcexpr))));
        }

        /*
         * From PG -
         * SQLValueFunction - parameterless functions with special grammar
         *                    productions.
         * CoerceViaIO - represents a type coercion between two types whose textual
         *               representations are compatible
         * Var - expression node representing a variable (ie, a table column)
         * OpExpr - expression node for an operator invocation
         * Const - constant value or expression node
         * BoolExpr - expression node for the basic Boolean operators AND, OR, NOT
         *
         * These are a special case that needs to be ignored.
         *
         */
        if (IsA(funcexpr, SQLValueFunction)
                || IsA(funcexpr, CoerceViaIO)
                || IsA(funcexpr, Var)   || IsA(funcexpr, OpExpr)
                || IsA(funcexpr, Const) || IsA(funcexpr, BoolExpr))
        {
            return false;
        }

        return expression_tree_walker((Node *)funcexpr->args,
                                      convert_cypher_walker, pstate);
    }

    /*
     * This handles cypher() calls in expressions. Those in RTE_FUNCTIONs are
     * handled by either convert_cypher_to_subquery() or the RangeTblFunction
     * case above.
     */
    if (IsA(node, FuncExpr))
    {
        FuncExpr *funcexpr = (FuncExpr *)node;

        if (is_func_cypher(funcexpr))
        {
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("cypher(...) in expressions is not supported"),
                     errhint("Use subquery instead if possible."),
                     parser_errposition(pstate, exprLocation(node))));
        }

        return expression_tree_walker((Node *)funcexpr->args,
                                      convert_cypher_walker, pstate);
    }

    if (IsA(node, Query))
    {
        int flags;
        bool result = false;
        Query *query = (Query *)node;

        /*
         * If this is a utility command, we need to unwrap the internal query
         * and pass it as the query.
         *
         * NOTE: This code only "knows" about the following utility commands -
         *
         * CREATE TABLE AS
         *
         * Others need to be added on a case by case basis.
         */
        if (query->utilityStmt != NULL &&
            IsA(query->utilityStmt, CreateTableAsStmt))
        {
            CreateTableAsStmt *ctas = (CreateTableAsStmt *)query->utilityStmt;

            if (IsA(ctas->query, Query))
            {
                query = (Query *)ctas->query;
            }
        }

        /*
         * QTW_EXAMINE_RTES
         *     We convert RTE_FUNCTION (cypher()) to RTE_SUBQUERY (SELECT)
         *     in-place.
         *
         * QTW_IGNORE_RT_SUBQUERIES
         *     After the conversion, we don't need to traverse the resulting
         *     RTE_SUBQUERY. However, we need to traverse other RTE_SUBQUERYs.
         *     This is done manually by the RTE_SUBQUERY case above.
         *
         * QTW_IGNORE_JOINALIASES
         *     We are not interested in this.
         */
        flags = QTW_EXAMINE_RTES_BEFORE | QTW_IGNORE_RT_SUBQUERIES |
                QTW_IGNORE_JOINALIASES;

        /* recurse on query */
        result = query_tree_walker(query, convert_cypher_walker, pstate, flags);

        return result;
    }

    return expression_tree_walker(node, convert_cypher_walker, pstate);
}