public inbox for [email protected]  
help / color / mirror / Atom feed
From: SATYANARAYANA NARLAPURAM <[email protected]>
To: PostgreSQL Hackers <[email protected]>
To: Ashutosh Bapat <[email protected]>
Subject: Bug: pg_get_viewdef() fails on GRAPH_TABLE views with lateral column references
Date: Sat, 18 Apr 2026 00:56:19 -0700
Message-ID: <CAHg+QDcLVa2iBnggkHxY4itZbXtDMfsYHEjnCUYe9hNbnxDi-w@mail.gmail.com> (raw)

Hi hackers,

pg_get_viewdef() fails with ERROR: bogus varlevelsup: 0 offset 0 for any
view containing a GRAPH_TABLE whose COLUMNS clause references an outer
(lateral)
table. This also breaks pg_dump and \d+ for any database containing such a
view.

Repro:

CREATE TABLE vtab (id int PRIMARY KEY, name text);
CREATE TABLE etab (eid int PRIMARY KEY,
    src int REFERENCES vtab(id), dst int REFERENCES vtab(id));
CREATE PROPERTY GRAPH g1
    VERTEX TABLES (vtab)
    EDGE TABLES (etab KEY (eid)
        SOURCE KEY (src) REFERENCES vtab(id)
        DESTINATION KEY (dst) REFERENCES vtab(id));
CREATE TABLE outer_t (val int);

CREATE VIEW v AS
  SELECT * FROM outer_t,
    GRAPH_TABLE (g1 MATCH (a IS vtab)
      COLUMNS (a.name AS src_name, outer_t.val AS oval));

pg_dump -d foo -p 5433
pg_dump: error: query failed: ERROR:  bogus varlevelsup: 0 offset 0
pg_dump: detail: Query was: SELECT
pg_catalog.pg_get_viewdef('173849'::pg_catalog.oid) AS viewdef

Problem:
deparse_context context variable declared in the case RTE_GRAPH_TABLE
shadows the function's
deparse_context *context parameter. The zeroed struct has namespaces = NIL,
so when get_rule_expr()
reaches a Var node, get_variable() sees list_length(context->namespaces) ==
0 and raises the error. Property
references are fine because GraphPropertyRef deparsing never touches
namespaces.

Fix:
Remove the shadowing local variable and pass the outer context pointer to
get_rule_expr(). Attached a patch
with a fix, additionally added a test.

Thanks,
Satya


Attachments:

  [application/octet-stream] 0001-Fix-pg_get_viewdef-crash-for-GRAPH_TABLE-views-with-.patch (4.9K, 3-0001-Fix-pg_get_viewdef-crash-for-GRAPH_TABLE-views-with-.patch)
  download | inline diff:
From f9667899154e6a42e6e73d9f21393384a9ff1dc2 Mon Sep 17 00:00:00 2001
From: Ubuntu
 <azureuser@pgclient.5sdvw5dac2hu3o3frfdg3sxydd.zx.internal.cloudapp.net>
Date: Sat, 18 Apr 2026 07:34:58 +0000
Subject: [PATCH] Fix pg_get_viewdef() crash for GRAPH_TABLE views with lateral
 column refs

get_from_clause_item() in ruleutils.c declares a local 'deparse_context
context = {0}' inside the RTE_GRAPH_TABLE COLUMNS loop, which shadows the
function's 'deparse_context *context' parameter. The zeroed struct has
namespaces = NIL, so when get_rule_expr() encounters a Var node (from a
lateral column reference in COLUMNS), get_variable() finds list_length(0)
and errors with 'bogus varlevelsup: 0 offset 0'.

Fix by removing the shadowing local variable and passing the outer context
pointer through to get_rule_expr(), which is what every other RTE case in
this function already does.

This crash affects pg_get_viewdef(), pg_dump, and psql's \d+ for any view
containing a GRAPH_TABLE with lateral column references in its COLUMNS
clause.
---
 src/backend/utils/adt/ruleutils.c         |  5 +----
 src/test/regress/expected/graph_table.out | 19 +++++++++++++++++++
 src/test/regress/sql/graph_table.sql      | 11 +++++++++++
 3 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 090e8cc2..148eb5bb 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -13097,16 +13097,13 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 					foreach(lc, rte->graph_table_columns)
 					{
 						TargetEntry *te = lfirst_node(TargetEntry, lc);
-						deparse_context context = {0};
 
 						if (!first)
 							appendStringInfoString(buf, ", ");
 						else
 							first = false;
 
-						context.buf = buf;
-
-						get_rule_expr((Node *) te->expr, &context, false);
+						get_rule_expr((Node *) te->expr, context, false);
 						appendStringInfoString(buf, " AS ");
 						appendStringInfoString(buf, quote_identifier(te->resname));
 					}
diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out
index b579e3df..d7b767be 100644
--- a/src/test/regress/expected/graph_table.out
+++ b/src/test/regress/expected/graph_table.out
@@ -932,6 +932,25 @@ SELECT pg_get_viewdef('customers_us'::regclass);
    ORDER BY customer_name, product_name;
 (1 row)
 
+-- ruleutils reverse parsing with lateral column reference in COLUMNS
+CREATE TABLE lateral_t (val int);
+INSERT INTO lateral_t VALUES (1);
+CREATE VIEW gt_lateral_view AS
+  SELECT * FROM lateral_t,
+    GRAPH_TABLE (myshop MATCH (c IS customers)
+      COLUMNS (c.name AS cname, lateral_t.val AS lval));
+SELECT pg_get_viewdef('gt_lateral_view'::regclass);
+                                          pg_get_viewdef                                           
+---------------------------------------------------------------------------------------------------
+  SELECT lateral_t.val,                                                                           +
+     "graph_table".cname,                                                                         +
+     "graph_table".lval                                                                           +
+    FROM lateral_t,                                                                               +
+     GRAPH_TABLE (myshop MATCH (c IS customers) COLUMNS (c.name AS cname, lateral_t.val AS lval));
+(1 row)
+
+DROP VIEW gt_lateral_view;
+DROP TABLE lateral_t;
 -- test view/graph nesting
 CREATE VIEW customers_view AS SELECT customer_id, 'redacted' || customer_id AS name_redacted, address FROM customers;
 SELECT * FROM customers;
diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql
index 4ff98817..90e5ea2e 100644
--- a/src/test/regress/sql/graph_table.sql
+++ b/src/test/regress/sql/graph_table.sql
@@ -528,6 +528,17 @@ SELECT * FROM GRAPH_TABLE (g4 MATCH (s WHERE s.id = 3)-[e]-(d) COLUMNS (s.val, e
 CREATE VIEW customers_us AS SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US')-[IS customer_orders | customer_wishlists ]->(l IS orders | wishlists)-[ IS list_items]->(p IS products) COLUMNS (c.name AS customer_name, p.name AS product_name)) ORDER BY customer_name, product_name;
 SELECT pg_get_viewdef('customers_us'::regclass);
 
+-- ruleutils reverse parsing with lateral column reference in COLUMNS
+CREATE TABLE lateral_t (val int);
+INSERT INTO lateral_t VALUES (1);
+CREATE VIEW gt_lateral_view AS
+  SELECT * FROM lateral_t,
+    GRAPH_TABLE (myshop MATCH (c IS customers)
+      COLUMNS (c.name AS cname, lateral_t.val AS lval));
+SELECT pg_get_viewdef('gt_lateral_view'::regclass);
+DROP VIEW gt_lateral_view;
+DROP TABLE lateral_t;
+
 -- test view/graph nesting
 
 CREATE VIEW customers_view AS SELECT customer_id, 'redacted' || customer_id AS name_redacted, address FROM customers;
-- 
2.43.0



view thread (4+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected]
  Subject: Re: Bug: pg_get_viewdef() fails on GRAPH_TABLE views with lateral column references
  In-Reply-To: <CAHg+QDcLVa2iBnggkHxY4itZbXtDMfsYHEjnCUYe9hNbnxDi-w@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox