On Wed, 20 Nov 2024 12:43:16 -0500
Tom Lane <t...@sss.pgh.pa.us> wrote:

> Yugo NAGATA <nag...@sraoss.co.jp> writes:
> >> You could even argue that case 2 isn't good enough either,
> >> and we should be delivering a specific error message saying
> >> that an ENR can't be used in a view/matview.  To do that,
> >> we'd likely need to pass down the QueryEnvironment in more
> >> places not fewer.
> 
> > We can raise a similar error for (not materialized) views by passing
> > QueryEnv to DefineView() (or in ealier stage) , but there are other
> > objects that can contain ENR in their definition, for examle, functions,
> > cursor, or RLS policies. Is it worth introducing this version of error
> > message for all these objects? 
> 
> If it's worth checking for here, why not in other cases?
> 
> I'm not sure I like using isQueryUsingTempRelation as a model,
> because its existing use in transformCreateTableAsStmt seems
> like mostly a hack.  (And I definitely don't love introducing
> yet another scan of the query.)  It seems to me that we should
> think about this, for MVs as well as those other object types,
> as fundamentally a dependency problem.  That is, the reason
> we can't allow a reference to an ENR in a long-lived object
> is that we have no catalog representation for the reference.
> So that leads to thinking that the issue ought to be handled
> in recordDependencyOnExpr and friends.  If we see an ENR while
> scanning a rangetable to extract dependencies, then complain.
> This might be a bit messy to produce good error messages for,
> though.
> 
> Speaking of error messages, I'm not sure that it's okay to
> use the phrase "ephemeral named relation" in a user-facing
> error message.  We don't use that term in our documentation
> AFAICS, except in some SPI documentation that most users
> will never have read.  In the context of triggers, "transition
> relation" seems to be what the docs use.

Thank you for your suggestion.

I've attached a updated patch. Use of ENRs are now checked in
find_expr_references_walker() called from recordDependencyOnExpr().

The message is changed to "transition tables cannot be used rule"
because the view definition is stored in the pg_rewrite catalog as
a rule. 

Regards,
Yugo Nagata


-- 
Yugo NAGATA <nag...@sraoss.co.jp>
>From 34d09775e92b0ac39cd8656d69164b13c92f6fa2 Mon Sep 17 00:00:00 2001
From: Yugo Nagata <nag...@sraoss.co.jp>
Date: Mon, 2 Dec 2024 09:39:34 +0900
Subject: [PATCH v2] Prohibit materialized views to use ephemeral named
 relations

---
 src/backend/catalog/dependency.c       | 24 ++++++++++++++++++++++++
 src/test/regress/expected/triggers.out | 13 +++++++++++++
 src/test/regress/sql/triggers.sql      | 13 +++++++++++++
 3 files changed, 50 insertions(+)

diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 2afc550540..f323e8c91e 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -138,6 +138,7 @@ typedef struct
 /* for find_expr_references_walker */
 typedef struct
 {
+	const ObjectAddress *depender;	/* depender object */
 	ObjectAddresses *addrs;		/* addresses being accumulated */
 	List	   *rtables;		/* list of rangetables to resolve Vars */
 } find_expr_references_context;
@@ -1556,6 +1557,7 @@ recordDependencyOnExpr(const ObjectAddress *depender,
 {
 	find_expr_references_context context;
 
+	context.depender = depender;
 	context.addrs = new_object_addresses();
 
 	/* Set up interpretation for Vars at varlevelsup = 0 */
@@ -1602,6 +1604,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
 	find_expr_references_context context;
 	RangeTblEntry rte = {0};
 
+	context.depender = depender;
 	context.addrs = new_object_addresses();
 
 	/* We gin up a rather bogus rangetable list to handle Vars */
@@ -1739,6 +1742,17 @@ find_expr_references_walker(Node *node,
 			/* (done out of line, because it's a bit bulky) */
 			process_function_rte_ref(rte, var->varattno, context);
 		}
+		else if (rte->rtekind == RTE_NAMEDTUPLESTORE)
+		{
+			/*
+			 * Catalog objects cannot depend on a transtion table which has
+			 * no catalog representation.
+			 */
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("transition table cannot be used in %s",
+							getObjectTypeDescription(context->depender, true))));
+		}
 
 		/*
 		 * Vars referencing other RTE types require no additional work.  In
@@ -2191,6 +2205,16 @@ find_expr_references_walker(Node *node,
 					}
 					context->rtables = list_delete_first(context->rtables);
 					break;
+				case RTE_NAMEDTUPLESTORE:
+					/*
+					 * Catalog objects cannot depend on a transtion table
+					 * which has no catalog representation.
+					 */
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("transition table cannot be used in %s",
+									getObjectTypeDescription(context->depender, true))));
+					break;
 				default:
 					break;
 			}
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index a044d6afe2..e3522cf3bb 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -3728,3 +3728,16 @@ Inherits: parent
 
 drop table parent, child;
 drop function f();
+-- Verify prohibition of materialized views defined using tansition table
+create table my_table (a int);
+create function make_matview() returns trigger as
+$$ begin create materialized view mv as select * from new_table; return new; end $$
+language plpgsql;
+create trigger make_matview after insert on my_table
+referencing new table as new_table
+for each statement execute function make_matview();
+insert into my_table values (42);
+ERROR:  transition tables cannot be used in rule
+CONTEXT:  SQL statement "create materialized view mv as select * from new_table"
+PL/pgSQL function make_matview() line 1 at SQL statement
+drop table my_table;
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 51610788b2..f83bd84e6c 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -2551,6 +2551,7 @@ merge into merge_target_table t
 using merge_source_table s
 on t.a = s.a
 when matched and s.a <= 2 then
+
 	update set b = t.b || ' updated by merge'
 when matched and s.a > 2 then
 	delete
@@ -2820,3 +2821,15 @@ alter trigger parenttrig on parent rename to anothertrig;
 
 drop table parent, child;
 drop function f();
+
+-- Verify prohibition of materialized views defined using tansition table
+
+create table my_table (a int);
+create function make_matview() returns trigger as
+$$ begin create materialized view mv as select * from new_table; return new; end $$
+language plpgsql;
+create trigger make_matview after insert on my_table
+referencing new table as new_table
+for each statement execute function make_matview();
+insert into my_table values (42);
+drop table my_table;
-- 
2.34.1

Reply via email to