On Sat, Apr 11, 2026 at 9:28 AM SATYANARAYANA NARLAPURAM <[email protected]> wrote: > > Hi Hackers, > > Two recursive functions, generate_setop_from_pathqueries() and > generate_queries_for_path_pattern_recurse() in GRAPH_TABLE rewriter are > missing check_stack_depth() calls. Consider a property graph with 400 edge > tables with a 2-hop pattern produce 160,000 path queries and therefore > 160,000 recursion frames in > generate_setop_from_pathqueries(). This can easily exceed the OS stack limit > for some systems and crashes the backend. > > I am proposing a stop gap fix of checking stack depth by calling > check_stack_depth for now but in future we may want to reduce the recursion > depth (for example use a balanced tree to reduce depth from O(N) to O(log N). > > Attached a patch for adding the check_stack_depth() check. > > Repro: > > CREATE TABLE sv (id int PRIMARY KEY); > INSERT INTO sv VALUES (1); > > DO $$ > BEGIN > FOR i IN 1..400 LOOP > EXECUTE format( > 'CREATE TABLE se_%s (id int PRIMARY KEY, src int, dst int)', i); > END LOOP; > END$$; > > DO $$ > DECLARE > sql text; > edges text := ''; > BEGIN > FOR i IN 1..400 LOOP > IF i > 1 THEN edges := edges || ', '; END IF; > edges := edges || format( > 'se_%s KEY (id) SOURCE KEY (src) REFERENCES sv (id) ' > 'DESTINATION KEY (dst) REFERENCES sv (id)', i); > END LOOP; > EXECUTE 'CREATE PROPERTY GRAPH g VERTEX TABLES (sv KEY (id)) ' > || 'EDGE TABLES (' || edges || ')'; > END$$; > > SELECT * FROM GRAPH_TABLE(g > MATCH (a)-[e1]->(b)-[e2]->(c) > COLUMNS(a.id AS a_id)) > LIMIT 1; >
Thanks for the report. I could reproduce the segfault on my laptop. The attached patch fixes it and gives ERROR: stack depth limit exceeded. generate_queries_for_path_pattern_recurse() - has to work in a linear fashion since the elements need to be processed in an order. Each permutation of elements produces one query. These queries can be arranged in a balanced tree as you suggest OR when constructing the setop tree we could generate it in divide-and-conquer manner. However, the tree will be flattened in the planner anyway (See flatten_simple_union_all() and pull_up_simple_union_all()). Thus the final planning will require a deeper stack anyway. The code complexity doesn't seem to be worth it. I also looked at a few commits that add check_stack_depth() to see if we add tests for these scenarios. But I didn't find any. So no tests added with this commit. -- Best Wishes, Ashutosh Bapat
From 71a851e9d74e1c3d74428700eca1f11437600bcd Mon Sep 17 00:00:00 2001 From: Ashutosh Bapat <[email protected]> Date: Wed, 15 Apr 2026 17:38:25 +0530 Subject: [PATCH v20260415 2/3] Check for stack overflow when rewriting graph queries. generate_queries_for_path_pattern_recurse() and generate_setop_from_pathqueries() are recursive functions. For a property graph with hundreds of tables, a graph pattern with a handful element patterns can cause stack overflow. Fix it by calling check_stack_depth() at the beginning of these functions. Reported-by: Satyanarayana Narlapuram <[email protected]> Author: Satyanarayana Narlapuram <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://www.postgresql.org/message-id/cahg+qdfgk0xddh8f3eab+uvn7sbdonv8rvm6okp4hthat6a...@mail.gmail.com --- src/backend/rewrite/rewriteGraphTable.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/backend/rewrite/rewriteGraphTable.c b/src/backend/rewrite/rewriteGraphTable.c index 2c3199d3230..429ef1cf1f4 100644 --- a/src/backend/rewrite/rewriteGraphTable.c +++ b/src/backend/rewrite/rewriteGraphTable.c @@ -17,6 +17,7 @@ #include "access/sysattr.h" #include "access/table.h" #include "access/htup_details.h" +#include "miscadmin.h" #include "catalog/pg_operator.h" #include "catalog/pg_propgraph_element.h" #include "catalog/pg_propgraph_element_label.h" @@ -361,6 +362,9 @@ generate_queries_for_path_pattern_recurse(RangeTblEntry *rte, List *pathqueries, { List *path_elems = list_nth_node(List, path_elem_lists, elempos); + /* Guard against stack overflow due to complex path patterns. */ + check_stack_depth(); + foreach_ptr(struct path_element, pe, path_elems) { /* Update current path being built with current element. */ @@ -698,6 +702,9 @@ generate_setop_from_pathqueries(List *pathqueries, List **rtable, List **targetl List *rtargetlist; ParseNamespaceItem *pni; + /* Guard against stack overflow due to many path queries. */ + check_stack_depth(); + /* Recursion termination condition. */ if (list_length(pathqueries) == 0) { -- 2.34.1
