From d8c05994945221d38deb2f25fe2c753613ddb406 Mon Sep 17 00:00:00 2001 From: Henri Gasc Date: Mon, 14 Sep 2026 16:30:58 +0200 Subject: [PATCH 8/8] Remove dead code and simplify GraphScan --- src/backend/executor/nodeGraphScan.c | 220 +++++++++++------------- src/backend/optimizer/path/allpaths.c | 26 +-- src/backend/parser/parse_graphtable.c | 36 +--- src/backend/rewrite/rewriteGraphTable.c | 85 +++++---- src/include/nodes/execnodes.h | 3 - src/include/nodes/pathnodes.h | 3 - src/include/parser/parse_graphtable.h | 19 +- src/include/rewrite/rewriteGraphTable.h | 8 + 8 files changed, 165 insertions(+), 235 deletions(-) diff --git a/src/backend/executor/nodeGraphScan.c b/src/backend/executor/nodeGraphScan.c index 79da8915e91..2a25f382f52 100644 --- a/src/backend/executor/nodeGraphScan.c +++ b/src/backend/executor/nodeGraphScan.c @@ -37,7 +37,6 @@ */ #include "postgres.h" -#include "access/htup_details.h" #include "catalog/pg_propgraph_element.h" #include "executor/executor.h" #include "executor/nodeGraphScan.h" @@ -47,26 +46,27 @@ #include "utils/array.h" #include "utils/lsyscache.h" #include "utils/memutils.h" -#include "utils/syscache.h" static TupleTableSlot *ExecGraphScan(PlanState *pstate); -static void build_arms(GraphScanState * node, GraphScan * plan); +static void build_arms(GraphScanState * node); static void build_arm_keys(List *keys, int *nkeys, FmgrInfo **eq, Oid **colls); -static bool graph_fetch_seed(GraphScanState * node, GraphScan * plan); +static bool graph_fetch_seed(GraphScanState * node); static void graph_bind_side(GraphScanState * node, GraphDepthFrameData * fr, bool active, int first_slot, int nslots); static void graph_bind_vertex_params(GraphScanState * node, GraphDepthFrameData * fr); -static bool graph_next(GraphScanState * node, GraphScan * plan); -static bool graph_step(GraphScanState * node, GraphScan * plan, - GraphDepthFrameData * fr); -static int graph_try_edge(GraphScanState * node, GraphScan * plan, +static bool graph_next(GraphScanState * node); +static bool graph_step(GraphScanState * node, GraphDepthFrameData * fr); +static bool try_traverse(GraphDepthFrameData * fr, TupleTableSlot *eslot, + GraphScanArmData * arm, bool match_src, + Oid *newelem, int *newnkeys, Datum *newvid, + bool *newnull); +static bool graph_try_edge(GraphScanState * node, GraphDepthFrameData * fr, TupleTableSlot *eslot, Oid *newelem, int *newnkeys, Datum *newvid, bool *newnull, Datum *eprops, bool *epropsnull); -static bool edge_key_matches(GraphScanState * node, GraphDepthFrameData * fr, - TupleTableSlot *eslot, GraphScanArmData * arm, - bool issrc); +static bool edge_key_matches(GraphDepthFrameData * fr, TupleTableSlot *eslot, + GraphScanArmData * arm, bool issrc); static int graph_find_arm(GraphScanState * node, Oid relid); static void graph_push(GraphScanState * node, Oid newelem, int newnkeys, Datum *newvid, bool *newnull, Datum *eprops, @@ -78,19 +78,15 @@ static TupleTableSlot *graph_emit_row(GraphScanState * node, TupleTableSlot *slo static Datum graph_build_edge_array(GraphScanState * node, TupleTableSlot *slot, int pi); -/* Result values of graph_try_edge */ -#define GRAPH_EDGE_NONE 0 /* not traversable */ -#define GRAPH_EDGE_FORWARD 1 /* traversable in the forward direction */ -#define GRAPH_EDGE_FORWARD 1 /* forward traversal */ - /* * Compile, per edge element arm, the metadata needed to match edges against * the current vertex: element ids, source/destination key column positions * within the arm's output row, and default equality functions. */ static void -build_arms(GraphScanState * node, GraphScan * plan) +build_arms(GraphScanState * node) { + GraphScan *plan = castNode(GraphScan, node->ss.ps.plan); int nprops = node->nprops; node->arms = palloc0(sizeof(GraphScanArmData) * node->narms); @@ -98,18 +94,10 @@ build_arms(GraphScanState * node, GraphScan * plan) for (int a = 0; a < node->narms; a++) { Oid elemoid = list_nth_oid(plan->edge_element_oids, a); - HeapTuple etup; - Form_pg_propgraph_element pge; GraphScanArmData *arm = &node->arms[a]; - etup = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(elemoid)); - if (!HeapTupleIsValid(etup)) - elog(ERROR, "cache lookup failed for property graph element %u", elemoid); - pge = (Form_pg_propgraph_element) GETSTRUCT(etup); - - arm->arm_relid = pge->pgerelid; - arm->arm_srcvertex = pge->pgesrcvertexid; - arm->arm_dstvertex = pge->pgedestvertexid; + get_graph_element_identity(elemoid, &arm->arm_relid, + &arm->arm_srcvertex, &arm->arm_dstvertex); arm->arm_src_first = nprops + 2; arm->arm_dst_first = nprops + 2 + node->max_nsrc; @@ -119,8 +107,6 @@ build_arms(GraphScanState * node, GraphScan * plan) build_arm_keys(get_graph_element_key_columns(elemoid, Anum_pg_propgraph_element_pgedestkey), &arm->arm_ndst, &arm->arm_dsteq, &arm->arm_dstcoll); - - ReleaseSysCache(etup); } } @@ -154,7 +140,7 @@ build_arm_keys(List *keys, int *nkeys, FmgrInfo **eq, Oid **colls) * is no (usable) seed; the scan is then exhausted. */ static bool -graph_fetch_seed(GraphScanState * node, GraphScan * plan) +graph_fetch_seed(GraphScanState * node) { EState *estate = node->ss.ps.state; GraphDepthFrameData *fr = &node->frames[0]; @@ -272,13 +258,13 @@ graph_bind_vertex_params(GraphScanState * node, GraphDepthFrameData * fr) * seed is exhausted (caller must fetch a new seed). */ static bool -graph_next(GraphScanState * node, GraphScan * plan) +graph_next(GraphScanState * node) { for (;;) { GraphDepthFrameData *fr = &node->frames[node->cur_depth]; - if (graph_step(node, plan, fr)) + if (graph_step(node, fr)) { /* descended one edge; emit whenever the new depth is deep enough */ if (node->cur_depth >= node->min_depth) @@ -301,9 +287,9 @@ graph_next(GraphScanState * node, GraphScan * plan) * true if a new depth was pushed onto the stack. */ static bool -graph_step(GraphScanState * node, GraphScan * plan, - GraphDepthFrameData * fr) +graph_step(GraphScanState * node, GraphDepthFrameData * fr) { + GraphScan *plan = castNode(GraphScan, node->ss.ps.plan); TupleTableSlot *eslot; Oid newelem; int newnkeys; @@ -330,32 +316,24 @@ graph_step(GraphScanState * node, GraphScan * plan, * (the frame's vertex) before pulling any rows. Parameterized index * scans only re-evaluate their scan keys when (re)started, so a frame * whose vertex was (re)set (a fresh push or a new seed) must have its - * inner scan (re)initialized or rescanned now, first and only time it is - * stepped for that vertex. + * inner scan rescanned now, first and only time it is stepped for that + * vertex. */ graph_bind_vertex_params(node, fr); if (fr->need_init) { - if (fr->inner_state == NULL) - fr->inner_state = - ExecInitNode(copyObject(plan->inner_plan), - node->ss.ps.state, node->eflags); - else - ExecReScan(fr->inner_state); + ExecReScan(fr->inner_state); fr->need_init = false; } for (;;) { - int res; - eslot = ExecProcNode(fr->inner_state); if (TupIsNull(eslot)) return false; - res = graph_try_edge(node, plan, fr, eslot, &newelem, &newnkeys, newvid, - newnull, newprops, newpropsnull); - if (res != GRAPH_EDGE_NONE) + if (graph_try_edge(node, fr, eslot, &newelem, &newnkeys, newvid, + newnull, newprops, newpropsnull)) { graph_push(node, newelem, newnkeys, newvid, newnull, newprops, newpropsnull); @@ -364,25 +342,63 @@ graph_step(GraphScanState * node, GraphScan * plan, } } +/* + * Try to adopt a candidate edge (one row of the inner plan) as the next + * traversal step: the current vertex must match the given side (source or + * destination) of the edge, in which case the next vertex is the element on + * the opposite side. The direction of the hop decides which side is tried. + */ +static bool +try_traverse(GraphDepthFrameData * fr, TupleTableSlot *eslot, + GraphScanArmData * arm, bool match_src, + Oid *newelem, int *newnkeys, Datum *newvid, + bool *newnull) +{ + Oid next_elem; + int next_nkeys; + int next_first; + + if (match_src) + { + next_elem = arm->arm_dstvertex; + next_nkeys = arm->arm_ndst; + next_first = arm->arm_dst_first; + } + else + { + next_elem = arm->arm_srcvertex; + next_nkeys = arm->arm_nsrc; + next_first = arm->arm_src_first; + } + + if (!edge_key_matches(fr, eslot, arm, match_src)) + return false; + + *newelem = next_elem; + *newnkeys = next_nkeys; + for (int i = 0; i < next_nkeys; i++) + newvid[i] = slot_getattr(eslot, next_first + i + 1, &newnull[i]); + return true; +} + /* * Check whether a candidate edge (one row of the inner plan) is traversable * from the current vertex, according to the hop's direction, and if so fill * the next vertex plus the edge's VLE property values. - * - * Returns GRAPH_EDGE_NONE / _FORWARD / _BOTH (the latter for an undirected - * non-loop edge, whose reverse traversal is also valid and is deferred). */ -static int -graph_try_edge(GraphScanState * node, GraphScan * plan, - GraphDepthFrameData * fr, TupleTableSlot *eslot, - Oid *newelem, int *newnkeys, Datum *newvid, - bool *newnull, Datum *eprops, bool *epropsnull) +static bool +graph_try_edge(GraphScanState * node, GraphDepthFrameData * fr, + TupleTableSlot *eslot, Oid *newelem, int *newnkeys, + Datum *newvid, bool *newnull, Datum *eprops, + bool *epropsnull) { + GraphScan *plan = castNode(GraphScan, node->ss.ps.plan); Oid tbl; bool isnull; int armno; GraphScanArmData *arm; int nprops = node->nprops; + bool matched; /* identify the edge element by its table OID */ tbl = DatumGetObjectId(slot_getattr(eslot, nprops + 2, &isnull)); @@ -391,69 +407,37 @@ graph_try_edge(GraphScanState * node, GraphScan * plan, elog(ERROR, "graph scan encountered unknown edge element table %u", tbl); arm = &node->arms[armno]; - /* VLE property values of the edge (may be filtered out below) */ - for (int i = 0; i < nprops; i++) - { - eprops[i] = slot_getattr(eslot, i + 1, &epropsnull[i]); - } - switch (plan->direction) { case GRAPH_DIR_INCOMING: - if (edge_key_matches(node, fr, eslot, arm, false)) - { - *newelem = arm->arm_srcvertex; - *newnkeys = arm->arm_nsrc; - for (int i = 0; i < arm->arm_nsrc; i++) - newvid[i] = - slot_getattr(eslot, arm->arm_src_first + i + 1, &newnull[i]); - return GRAPH_EDGE_FORWARD; - } + /* traverse the edge from its destination (the current vertex) */ + matched = try_traverse(fr, eslot, arm, false, + newelem, newnkeys, newvid, newnull); break; case GRAPH_DIR_UNDIRECTED: - - /* - * An undirected edge is traversable from the current vertex when - * it matches either endpoint: as the source it yields the - * destination as next vertex, as the destination it yields the - * source (the reverse traversal, generated here rather than with - * a deferred mechanism). - */ - if (edge_key_matches(node, fr, eslot, arm, true)) - { - *newelem = arm->arm_dstvertex; - *newnkeys = arm->arm_ndst; - for (int i = 0; i < arm->arm_ndst; i++) - newvid[i] = - slot_getattr(eslot, arm->arm_dst_first + i + 1, &newnull[i]); - return GRAPH_EDGE_FORWARD; - } - if (edge_key_matches(node, fr, eslot, arm, false)) - { - *newelem = arm->arm_srcvertex; - *newnkeys = arm->arm_nsrc; - for (int i = 0; i < arm->arm_nsrc; i++) - newvid[i] = - slot_getattr(eslot, arm->arm_src_first + i + 1, &newnull[i]); - return GRAPH_EDGE_FORWARD; - } + /* traverse from either endpoint; try the source side first */ + matched = try_traverse(fr, eslot, arm, true, + newelem, newnkeys, newvid, newnull); + if (!matched) + matched = try_traverse(fr, eslot, arm, false, + newelem, newnkeys, newvid, newnull); break; default: /* GRAPH_DIR_OUTGOING */ - if (edge_key_matches(node, fr, eslot, arm, true)) - { - *newelem = arm->arm_dstvertex; - *newnkeys = arm->arm_ndst; - for (int i = 0; i < arm->arm_ndst; i++) - newvid[i] = - slot_getattr(eslot, arm->arm_dst_first + i + 1, &newnull[i]); - return GRAPH_EDGE_FORWARD; - } + /* traverse the edge from its source (the current vertex) */ + matched = try_traverse(fr, eslot, arm, true, + newelem, newnkeys, newvid, newnull); break; } - return GRAPH_EDGE_NONE; + if (!matched) + return false; + + /* VLE property values of the edge */ + for (int i = 0; i < nprops; i++) + eprops[i] = slot_getattr(eslot, i + 1, &epropsnull[i]); + return true; } /* @@ -462,9 +446,8 @@ graph_try_edge(GraphScanState * node, GraphScan * plan, * destination) vertex element must equal the current vertex's element. */ static bool -edge_key_matches(GraphScanState * node, GraphDepthFrameData * fr, - TupleTableSlot *eslot, GraphScanArmData * arm, - bool issrc) +edge_key_matches(GraphDepthFrameData * fr, TupleTableSlot *eslot, + GraphScanArmData * arm, bool issrc) { int n; int first; @@ -551,11 +534,8 @@ graph_push(GraphScanState * node, Oid newelem, int newnkeys, nfr->vid_nkeys = newnkeys; memcpy(nfr->vid, newvid, sizeof(Datum) * newnkeys); memcpy(nfr->vidnull, newnull, sizeof(bool) * newnkeys); - if (eprops != NULL) - { - memcpy(nfr->edge_props, eprops, sizeof(Datum) * node->nprops); - memcpy(nfr->edge_propsnull, epropsnull, sizeof(bool) * node->nprops); - } + memcpy(nfr->edge_props, eprops, sizeof(Datum) * node->nprops); + memcpy(nfr->edge_propsnull, epropsnull, sizeof(bool) * node->nprops); /* the new vertex's inner scan must (re)start (see graph_step) */ nfr->need_init = true; node->cur_depth = d; @@ -574,10 +554,10 @@ graph_backtrack(GraphScanState * node) static void graph_reset(GraphScanState * node) { - for (; node->cur_depth > 0; node->cur_depth--) + while (node->cur_depth > 0) { node->ss.ps.state->es_graph_stack_depth--; - (void) 0; + node->cur_depth--; } Assert(node->ss.ps.state->es_graph_stack_depth >= 0); node->cur_depth = -1; @@ -588,7 +568,6 @@ static TupleTableSlot * ExecGraphScan(PlanState *pstate) { GraphScanState *node = castNode(GraphScanState, pstate); - GraphScan *plan = castNode(GraphScan, pstate->plan); TupleTableSlot *slot = node->ss.ss_ScanTupleSlot; for (;;) @@ -606,7 +585,7 @@ ExecGraphScan(PlanState *pstate) if (!node->need_seed) return NULL; node->need_seed = false; - if (!graph_fetch_seed(node, plan)) + if (!graph_fetch_seed(node)) return NULL; } @@ -623,7 +602,7 @@ ExecGraphScan(PlanState *pstate) } /* try to descend along another edge (or backtrack) */ - if (graph_next(node, plan)) + if (graph_next(node)) { TupleTableSlot *res = graph_emit_row(node, slot); @@ -774,7 +753,6 @@ ExecInitGraphScan(GraphScan * node, EState *estate, int eflags) scanstate->vertex_params = node->vertex_param_ids; scanstate->fwd_active = (node->direction != GRAPH_DIR_INCOMING); scanstate->rev_active = (node->direction != GRAPH_DIR_OUTGOING); - scanstate->eflags = eflags; /* * Effective maximum depth. Explicit bounds are honored; unbounded (or @@ -787,7 +765,7 @@ ExecInitGraphScan(GraphScan * node, EState *estate, int eflags) scanstate->frames = palloc0(sizeof(GraphDepthFrameData) * scanstate->ndepths); /* Compile the per-arm edge element metadata. */ - build_arms(scanstate, node); + build_arms(scanstate); /* * Initialize the scan slot. There is no heap relation to describe it, so diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index c81fee8da7b..ae3269ebffe 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -56,11 +56,8 @@ #include "rewrite/rewriteGraphTable.h" #include "rewrite/rewriteManip.h" #include "utils/lsyscache.h" -#include "utils/array.h" -#include "utils/builtins.h" #include "utils/selfuncs.h" #include "utils/syscache.h" -#include "utils/typcache.h" /* Bitmask flags for pushdown_safety_info.unsafeFlags */ @@ -4086,29 +4083,25 @@ static void graph_est_element_rows(Oid elemoid, Oid *relid, Oid *srcvertex, Oid *dstvertex, double *tuples) { - HeapTuple etup; - Form_pg_propgraph_element pge; + Oid rid; + Oid srcv; + Oid dstv; Relation rel; BlockNumber pages; double allvisfrac; - etup = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(elemoid)); - if (!HeapTupleIsValid(etup)) - elog(ERROR, "cache lookup failed for property graph element %u", - elemoid); - pge = (Form_pg_propgraph_element) GETSTRUCT(etup); + get_graph_element_identity(elemoid, &rid, &srcv, &dstv); - *relid = pge->pgerelid; + if (relid) + *relid = rid; if (srcvertex) - *srcvertex = pge->pgesrcvertexid; + *srcvertex = srcv; if (dstvertex) - *dstvertex = pge->pgedestvertexid; + *dstvertex = dstv; - rel = table_open(*relid, AccessShareLock); + rel = table_open(rid, AccessShareLock); estimate_rel_size(rel, NULL, &pages, tuples, &allvisfrac); table_close(rel, NoLock); - - ReleaseSysCache(etup); } static double @@ -4359,7 +4352,6 @@ set_graphscan_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, gpath->vertex_param_ids = lappend_int(gpath->vertex_param_ids, vprm->paramid); gpath->seed_elem_oid = rte->graph_seed_elem_oid; - gpath->seed_param_ids = NIL; gpath->max_nsrc = max_nsrc; gpath->max_ndst = max_ndst; diff --git a/src/backend/parser/parse_graphtable.c b/src/backend/parser/parse_graphtable.c index 5d6074ba542..9f37488c123 100644 --- a/src/backend/parser/parse_graphtable.c +++ b/src/backend/parser/parse_graphtable.c @@ -842,8 +842,7 @@ get_graph_all_label_oids(Oid propgraphid) * vertex, 'e' for edge) and the human-readable class name ("vertex"/"edge"). * Returns false for pattern kinds that do not denote a vertex or edge (e.g. * PAREN_EXPR), leaving the outputs untouched. kind_str may be NULL if the - * caller only needs the character. Shared by the parser validators, the - * native planner, and the native executor. + * caller only needs the character. Used by the label-kind validator. */ bool graph_element_kind_info(GraphElementPatternKind kind, @@ -867,36 +866,3 @@ graph_element_kind_info(GraphElementPatternKind kind, return false; } } - -/* - * Match a label expression against an element, using the supplied - * membership callback. A label expression is a single GraphLabelRef or a - * BoolExpr (OR) tree of GraphLabelRef nodes; the element matches if it - * carries any of the referenced labels (OR semantics). A NULL labelexpr - * matches everything. - * - * See graph_label_expr_matches() in parse_graphtable.h for the shared API. - */ -bool -graph_label_expr_matches(Node *labelexpr, GraphLabelHasFn has_label, - void *arg) -{ - if (labelexpr == NULL) - return true; - if (IsA(labelexpr, GraphLabelRef)) - return has_label(((GraphLabelRef *) labelexpr)->labelid, arg); - if (IsA(labelexpr, BoolExpr)) - { - BoolExpr *b = (BoolExpr *) labelexpr; - - foreach_ptr(Node, sub, b->args) - { - if (graph_label_expr_matches(sub, has_label, arg)) - return true; - } - return false; - } - elog(ERROR, "unsupported label expression node: %d", - (int) nodeTag(labelexpr)); - return false; /* keep compiler quiet */ -} diff --git a/src/backend/rewrite/rewriteGraphTable.c b/src/backend/rewrite/rewriteGraphTable.c index 9877604d170..1e4dd2f2098 100644 --- a/src/backend/rewrite/rewriteGraphTable.c +++ b/src/backend/rewrite/rewriteGraphTable.c @@ -1344,7 +1344,6 @@ get_element_property_expr(Oid elemoid, Oid propoid, int rtindex) */ typedef struct native_vle_factor { - int factorpos; /* pattern position of the edge */ GraphElementPattern *edge_gep; /* the edge element pattern */ List *edge_element_oids; /* edge element OIDs matching the label */ List *array_props; /* GraphPropertyRef* (VLE edge-list refs) */ @@ -1375,7 +1374,6 @@ typedef struct native_bind typedef struct native_decomp { RangeTblEntry *rte; /* the user's graph RTE */ - List *factors; /* one path_factor per element pattern */ List *elem_lists; /* per factor: List of struct path_element * (NIL for a VLE factor) */ List *vle_factors; /* per factor: native_vle_factor* or NULL */ @@ -1386,7 +1384,6 @@ typedef struct native_decomp /* Context for resolving property references within a branch. */ typedef struct native_prop_ctx { - Oid propgraphid; List *binds; /* List of native_bind */ List *vle_binds; /* List of native_vle_bind */ } native_prop_ctx; @@ -1430,6 +1427,30 @@ get_graph_element_key_columns(Oid elemoid, int key_attnum) return result; } +/* + * Look up the backing table and the vertex element references of a graph + * element (pgerelid / pgesrcvertexid / pgedestvertexid). Shared by the + * native planner and the native executor. + */ +void +get_graph_element_identity(Oid elemoid, Oid *relid, Oid *srcvertex, + Oid *dstvertex) +{ + HeapTuple eletup; + Form_pg_propgraph_element pgeform; + + eletup = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(elemoid)); + if (!HeapTupleIsValid(eletup)) + elog(ERROR, "cache lookup failed for property graph element %u", elemoid); + pgeform = (Form_pg_propgraph_element) GETSTRUCT(eletup); + + *relid = pgeform->pgerelid; + *srcvertex = pgeform->pgesrcvertexid; + *dstvertex = pgeform->pgedestvertexid; + + ReleaseSysCache(eletup); +} + /* * Return an equality operator suitable for the given datatype, using the * type's default (btree) equality operator. @@ -1674,10 +1695,8 @@ native_build_vle_rte(RangeTblEntry *rte, native_vle_factor * vf, List *src_keys; List *term_keys; int nseed; - int nterm; int seed_first = 1; int term_first; - int array_first; int eff_min; List *columns = NIL; List *colnames = NIL; @@ -1698,14 +1717,12 @@ native_build_vle_rte(RangeTblEntry *rte, native_vle_factor * vf, term_keys = get_graph_element_key_columns(termpe->elemoid, Anum_pg_propgraph_element_pgekey); nseed = list_length(src_keys); - nterm = list_length(term_keys); eff_min = vf->min_depth; if (eff_min == 0 && srcpe->elemoid != termpe->elemoid) eff_min = 1; term_first = seed_first + nseed; - array_first = term_first + nterm; /* The RT index of the new RTE: next in the branch's rtable. */ gs_rti = list_length(branch->rtable) + 1; @@ -1938,12 +1955,6 @@ native_replace_property_refs_mutator(Node *node, native_prop_ctx * ctx) ctx); } -static Node * -native_replace_property_refs(Node *node, native_prop_ctx * ctx) -{ - return native_replace_property_refs_mutator(node, ctx); -} - /* * Construct the Query for one fully-bound branch. Returns NULL if the * combination is inconsistent (fixed edge-vertex links don't line up). @@ -2047,7 +2058,6 @@ native_query_for_branch(native_decomp * dc, List *elems, List *vles) foreach(lc, elems) { struct path_element *pe = lfirst(lc); - native_vle_factor *vf = list_nth(vles, i); if (pe == NULL) { @@ -2114,22 +2124,21 @@ native_query_for_branch(native_decomp * dc, List *elems, List *vles) i++; } - ctx.propgraphid = rte->relid; ctx.binds = binds; ctx.vle_binds = vle_binds; if (rte->graph_pattern->whereClause) qual_exprs = lappend(qual_exprs, - native_replace_property_refs(copyObject((Node *) rte->graph_pattern->whereClause), - &ctx)); + native_replace_property_refs_mutator(copyObject((Node *) rte->graph_pattern->whereClause), + &ctx)); path_query->jointree = makeFromExpr(fromlist, qual_exprs ? (Node *) makeBoolExpr(AND_EXPR, qual_exprs, -1) : NULL); /* Construct the branch targetlist from the COLUMNS specification. */ path_query->targetList = castNode(List, - native_replace_property_refs(copyObject((Node *) rte->graph_table_columns), - &ctx)); + native_replace_property_refs_mutator(copyObject((Node *) rte->graph_table_columns), + &ctx)); /* * Mark the columns being accessed in the branch query as requiring SELECT @@ -2197,6 +2206,21 @@ native_queries_recurse(native_decomp * dc, int facpos, List *elems, List *vles) } } +/* + * Return the OIDs of the elements described by the given list of resolved + * path elements (shared by the edge/vertex element lookups below). + */ +static List * +path_element_oids(List *pes) +{ + List *result = NIL; + + foreach_ptr(struct path_element, pe, pes) + result = lappend_oid(result, pe->elemoid); + + return result; +} + /* * Return the OIDs of the edge elements matching the given edge element * pattern in the given property graph. Used by the native planner to build @@ -2208,9 +2232,6 @@ get_graph_edge_element_oids(Oid propgraphid, GraphElementPattern *gep) struct path_factor *src_pf; struct path_factor *edge_pf; struct path_factor *dest_pf; - List *pes; - List *result = NIL; - ListCell *lc; Assert(IS_EDGE_PATTERN(gep->kind)); @@ -2236,11 +2257,8 @@ get_graph_edge_element_oids(Oid propgraphid, GraphElementPattern *gep) edge_pf->src_pf = src_pf; edge_pf->dest_pf = dest_pf; - pes = get_path_elements_for_path_factor(propgraphid, edge_pf); - foreach_ptr(struct path_element, pe, pes) - result = lappend_oid(result, pe->elemoid); - - return result; + return path_element_oids(get_path_elements_for_path_factor(propgraphid, + edge_pf)); } /* @@ -2253,9 +2271,6 @@ List * get_graph_vertex_element_oids(Oid propgraphid, GraphElementPattern *gep) { struct path_factor *pf; - List *pes; - List *result = NIL; - ListCell *lc; Assert(gep->kind == VERTEX_PATTERN); @@ -2266,11 +2281,8 @@ get_graph_vertex_element_oids(Oid propgraphid, GraphElementPattern *gep) pf->variable = gep->variable; pf->whereClause = gep->whereClause; - pes = get_path_elements_for_path_factor(propgraphid, pf); - foreach_ptr(struct path_element, pe, pes) - result = lappend_oid(result, pe->elemoid); - - return result; + return path_element_oids(get_path_elements_for_path_factor(propgraphid, + pf)); } /* @@ -2293,7 +2305,6 @@ decomposeGraphNative(RangeTblEntry *rte) List *vle_factors = NIL; int factorpos = 0; Query *result; - ListCell *lc; Assert(list_length(gp->path_pattern_list) == 1); path_pattern = linitial(gp->path_pattern_list); @@ -2347,7 +2358,6 @@ decomposeGraphNative(RangeTblEntry *rte) native_vle_factor *vf = palloc0_object(native_vle_factor); List *edes; - vf->factorpos = pf->factorpos; vf->edge_gep = gep; vf->min_depth = linitial_int(gep->quantifier); vf->max_depth = lsecond_int(gep->quantifier); @@ -2371,7 +2381,6 @@ decomposeGraphNative(RangeTblEntry *rte) } dc.rte = rte; - dc.factors = factors; dc.elem_lists = elem_lists; dc.vle_factors = vle_factors; dc.nfactors = list_length(factors); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index d9dd23fb6b3..d6ed237974c 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1987,9 +1987,6 @@ typedef struct GraphScanState int narms; struct GraphScanArmData *arms; - /* Flags passed to ExecInitGraphScan (needed for lazy inner init). */ - int eflags; - /* * Seed key values of the current seed column (List of Param or Const, one * per seed key column, in key order); see GraphScan.seed_params. diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index 5baacce3aad..b997287639a 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -2241,9 +2241,6 @@ typedef struct GraphPath /* Vertex element the (ghost) seed belongs to. */ Oid seed_elem_oid; - /* PARAM_EXEC ids of the seed key columns (filled at create_plan time). */ - List *seed_param_ids; - /* * PARAM_EXEC ids of the current-vertex key values used to parameterize * the inner (1-hop) arm scans; see GraphScan.vertex_param_ids. diff --git a/src/include/parser/parse_graphtable.h b/src/include/parser/parse_graphtable.h index e5c42264b88..0119f09d3ac 100644 --- a/src/include/parser/parse_graphtable.h +++ b/src/include/parser/parse_graphtable.h @@ -42,8 +42,7 @@ extern List *get_graph_all_label_oids(Oid propgraphid); * vertex, 'e' for edge) and the human-readable class name ("vertex"/"edge"). * Returns false for pattern kinds that do not denote a vertex or edge (e.g. * PAREN_EXPR), leaving the outputs untouched. kind_str may be NULL if the - * caller only needs the character. Shared by the graph rewrite fallback, - * the native planner, and the native executor. + * caller only needs the character. Used by the label-kind validator. */ extern bool graph_element_kind_info(GraphElementPatternKind kind, char *element_kind, const char **kind_str); @@ -58,20 +57,4 @@ extern bool graph_element_kind_info(GraphElementPatternKind kind, extern void validate_graph_element_label_kinds(GraphPattern *pattern, Oid graph_oid); -/* - * Callback used by graph_label_expr_matches(): does the element described - * by arg carry the given label? - */ -typedef bool (*GraphLabelHasFn) (Oid labelid, void *arg); - -/* - * Match a label expression (a single GraphLabelRef, or a BoolExpr OR tree of - * GraphLabelRef nodes) against an element, invoking has_label for each label - * the expression references. A NULL labelexpr matches everything. Shared by - * the native planner (syscache-backed) and the native executor (cached - * element model) so the OR / GraphLabelRef traversal is single-sourced. - */ -extern bool graph_label_expr_matches(Node *labelexpr, - GraphLabelHasFn has_label, void *arg); - #endif /* PARSE_GRAPHTABLE_H */ diff --git a/src/include/rewrite/rewriteGraphTable.h b/src/include/rewrite/rewriteGraphTable.h index 3a6ffab37a6..b0085a26ae6 100644 --- a/src/include/rewrite/rewriteGraphTable.h +++ b/src/include/rewrite/rewriteGraphTable.h @@ -72,6 +72,14 @@ typedef struct GraphElementKeyCol */ extern List *get_graph_element_key_columns(Oid elemoid, int key_attnum); +/* + * Look up the backing table (relid) and the source/destination vertex + * element references of a graph element. Shared by the native planner and + * the native executor. + */ +extern void get_graph_element_identity(Oid elemoid, Oid *relid, + Oid *srcvertex, Oid *dstvertex); + /* * Return an equality operator suitable for a graph key datatype: the type's * default equality operator. Key values are compared with this operator, -- 2.39.2