Hello everyone!

I have found out the problem when try to sequentially call the function that casts constant to composite type of temporary table that is deleted ateach transaction termination (i.e. at each function call completion).


For example, we have the following function 'test':

CREATE OR REPLACE FUNCTION test()
 RETURNS void
 LANGUAGE plpgsql
AS $function$
begin
    create temp table tbl (id int) on commit drop;
    perform json_populate_record(null::tbl, '{ "id": 11 }'::json) as tt;
end;
$function$


Оn the second and subsequent calls we'll observe the following error:

ERROR: cache lookup failed for type 16392


I investigated the problem and realized that result type of function *json_populate_record* (/funcresulttype/ field of /FuncExpr/ struct) as well as type of the first null argument (/consttype/ field of /Const/ struct) refer to the invalid composite type related with temporary table'tbl'. Namely they take a value of oid gotten from the first 'tbl' initialization. The plan of query *'perform json_populate_record(null::tbl, '{ "id": 11 }'::json) as tt'*is cached and is not invalidated at each function call. This is because** the statement of this query doesn't have any dependency from the 'tbl' relation (/relationOids/ list of /CachedPlanSource/ struct).


Attached patch resolves this problem by adding dependency from relation upon detection Const expression of composite type of that relation.

--
Regards,
Maksim Milyutin

diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index b0c9e94..bf5e4f4 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -78,6 +78,12 @@ typedef struct
 	(((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
 	 !(con)->constisnull)
 
+/*
+ * Check if a Const node has composite type
+ */
+#define ISTABLETYPECONST(con) \
+	(OidIsValid(get_typ_typrelid((con)->consttype)))
+
 #define fix_scan_list(root, lst, rtoffset) \
 	((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))
 
@@ -1410,6 +1416,12 @@ fix_expr_common(PlannerInfo *root, Node *node)
 			root->glob->relationOids =
 				lappend_oid(root->glob->relationOids,
 							DatumGetObjectId(con->constvalue));
+
+		/* Check whether const has composite type */
+		if (ISTABLETYPECONST(con))
+			root->glob->relationOids =
+				lappend_oid(root->glob->relationOids,
+							get_typ_typrelid(con->consttype));
 	}
 	else if (IsA(node, GroupingFunc))
 	{
diff --git a/src/test/regress/sql/plancache.sql b/src/test/regress/sql/plancache.sql
index cb2a551..41be0d6 100644
--- a/src/test/regress/sql/plancache.sql
+++ b/src/test/regress/sql/plancache.sql
@@ -140,6 +140,21 @@ create temp sequence seq;
 
 execute p2;
 
+-- Check that invalidation deals with casting const value to temporary
+-- composite type reinitialized on each new transaction
+
+create function cache_query_with_composite_const() returns void as $$
+begin
+    create temp table tbl(id int) on commit drop;
+
+    -- Plan of the next query has to be rebuilt on each new call of function
+    -- due to casting first argument 'null' to recreated temprary table 'tbl'
+    perform json_populate_record(null::tbl, '{"id": 0}'::json);
+end$$ language plpgsql;
+
+select cache_query_with_composite_const();
+select cache_query_with_composite_const();
+
 -- Check DDL via SPI, immediately followed by SPI plan re-use
 -- (bug in original coding)
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to