You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by jg...@apache.org on 2022/10/06 00:59:52 UTC
[age] branch master updated: Fix EXPLAIN to allow for nested cypher commands
This is an automated email from the ASF dual-hosted git repository.
jgemignani pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/master by this push:
new c9c07f7 Fix EXPLAIN to allow for nested cypher commands
c9c07f7 is described below
commit c9c07f71123d2f11d6209188633dff1ad341d23a
Author: John Gemignani <jr...@gmail.com>
AuthorDate: Tue Oct 4 12:28:35 2022 -0700
Fix EXPLAIN to allow for nested cypher commands
Fixed the EXPLAIN command to allow for nested cypher commands within
more complex SQL queries.
---
src/backend/parser/cypher_analyze.c | 117 ++++++++++++++++++++++++------------
1 file changed, 77 insertions(+), 40 deletions(-)
diff --git a/src/backend/parser/cypher_analyze.c b/src/backend/parser/cypher_analyze.c
index 15222ff..1a8ea23 100644
--- a/src/backend/parser/cypher_analyze.c
+++ b/src/backend/parser/cypher_analyze.c
@@ -44,7 +44,17 @@
#include "utils/ag_func.h"
#include "utils/agtype.h"
+/*
+ * extra_node is a global variable to this source to store, at the moment, the
+ * explain stmt node passed up by the parser. The return value from the parser
+ * contains an 'extra' value, hence the name.
+ */
static Node *extra_node = NULL;
+/*
+ * Takes a query node and builds an explain stmt query node. It then replaces
+ * the passed query node with the new explain stmt query node.
+ */
+static void build_explain_query(Query *query, Node *explain_node);
static post_parse_analyze_hook_type prev_post_parse_analyze_hook;
@@ -79,9 +89,34 @@ void post_parse_analyze_fini(void)
static void post_parse_analyze(ParseState *pstate, Query *query)
{
if (prev_post_parse_analyze_hook)
+ {
prev_post_parse_analyze_hook(pstate, query);
+ }
+
+ /*
+ * extra_node is set in the parsing stage to keep track of EXPLAIN.
+ * So it needs to be set to NULL prior to any cypher parsing.
+ */
+ extra_node = NULL;
convert_cypher_walker((Node *)query, pstate);
+
+ /*
+ * If there is an extra_node returned, we need to check to see if
+ * it is an EXPLAIN.
+ */
+ if (extra_node != NULL)
+ {
+ /* process the EXPLAIN node */
+ if (nodeTag(extra_node) == T_ExplainStmt)
+ {
+ build_explain_query(query, extra_node);
+ }
+
+ /* reset extra_node */
+ pfree(extra_node);
+ extra_node = NULL;
+ }
}
// find cypher() calls in FROM clauses and convert them to SELECT subqueries
@@ -178,57 +213,55 @@ static bool convert_cypher_walker(Node *node, ParseState *pstate)
flags = QTW_EXAMINE_RTES | QTW_IGNORE_RT_SUBQUERIES |
QTW_IGNORE_JOINALIASES;
- /* clear the global variable extra_node */
- extra_node = NULL;
-
/* recurse on query */
result = query_tree_walker(query, convert_cypher_walker, pstate, flags);
- /* check for EXPLAIN */
- if (extra_node != NULL && nodeTag(extra_node) == T_ExplainStmt)
- {
- ExplainStmt *estmt = NULL;
- Query *query_copy = NULL;
- Query *query_node = NULL;
+ return result;
+ }
- /*
- * Create a copy of the query node. This is purposely a shallow copy
- * because we are only moving the contents to another pointer.
- */
- query_copy = (Query *) palloc(sizeof(Query));
- memcpy(query_copy, query, sizeof(Query));
+ return expression_tree_walker(node, convert_cypher_walker, pstate);
+}
- /* build our Explain node and store the query node copy in it */
- estmt = makeNode(ExplainStmt);
- estmt->query = (Node *)query_copy;
- estmt->options = ((ExplainStmt *)extra_node)->options;
+/*
+ * Takes a query node and builds an explain stmt query node. It then replaces
+ * the passed query node with the new explain stmt query node.
+ */
+static void build_explain_query(Query *query, Node *explain_node)
+{
+ ExplainStmt *estmt = NULL;
+ Query *query_copy = NULL;
+ Query *query_node = NULL;
- /* build our replacement query node */
- query_node = makeNode(Query);
- query_node->commandType = CMD_UTILITY;
- query_node->utilityStmt = (Node *)estmt;
- query_node->canSetTag = true;
+ /*
+ * Create a copy of the query node. This is purposely a shallow copy
+ * because we are only moving the contents to another pointer.
+ */
+ query_copy = (Query *) palloc(sizeof(Query));
+ memcpy(query_copy, query, sizeof(Query));
- /* now replace the top query node with our replacement query node */
- memcpy(query, query_node, sizeof(Query));
+ /* build our Explain node and store the query node copy in it */
+ estmt = makeNode(ExplainStmt);
+ estmt->query = (Node *)query_copy;
+ estmt->options = ((ExplainStmt *)explain_node)->options;
- /*
- * We need to free and clear the global variable when done. But, not
- * the ExplainStmt options. Those will get freed by PG when the
- * query is deleted.
- */
- ((ExplainStmt *)extra_node)->options = NULL;
- pfree(extra_node);
- extra_node = NULL;
+ /* build our replacement query node */
+ query_node = makeNode(Query);
+ query_node->commandType = CMD_UTILITY;
+ query_node->utilityStmt = (Node *)estmt;
+ query_node->canSetTag = true;
- /* we need to free query_node as it is no longer needed */
- pfree(query_node);
- }
+ /* now replace the top query node with our replacement query node */
+ memcpy(query, query_node, sizeof(Query));
- return result;
- }
+ /*
+ * We need to free and clear the global variable when done. But, not
+ * the ExplainStmt options. Those will get freed by PG when the
+ * query is deleted.
+ */
+ ((ExplainStmt *)explain_node)->options = NULL;
- return expression_tree_walker(node, convert_cypher_walker, pstate);
+ /* we need to free query_node as it is no longer needed */
+ pfree(query_node);
}
static bool is_rte_cypher(RangeTblEntry *rte)
@@ -386,6 +419,10 @@ static void convert_cypher_to_subquery(RangeTblEntry *rte, ParseState *pstate)
{
Node *temp = llast(stmt);
+ ereport(WARNING,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("too many extra_nodes passed from parser")));
+
list_delete_ptr(stmt, temp);
}