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)