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);
}