From 48c5c9068211e0a04fd9553c8714b2821ed3ad17 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 27 Jul 2021 12:03:16 -0400 Subject: [PATCH] Use the "pg_temp" schema alias in EXPLAIN and related output. This patch causes EXPLAIN output to refer to objects that are in the current session's temp schema with the "pg_temp" schema alias rather than that schema's actual name. This is useful for our own testing purposes since it will stabilize EXPLAIN VERBOSE output for such cases, allowing us to use that in regression tests. It should be less confusing for end users too. Since ruleutils.c needs to change behavior for this, the change also leaks into a few other users of ruleutils.c, for example pg_get_viewdef(). AFAICS that won't cause any problems. We did find that aggressively trying to change this behavior across-the-board would cause issues, but as long as "pg_temp" only appears within generated SQL text, I think it'll be fine. Along the way, make get_namespace_name_or_temp conform to the same API as get_namespace_name, ie that it returns a palloc'd string or NULL. The current behavior hasn't caused any bugs since no callers attempt to pfree the result, but if it gets more widespread usage that could become a problem. Amul Sul, reviewed and extended by me Discussion: https://postgr.es/m/CAAJ_b97W=QaGmag9AhWNbmx3uEYsNkXWL+OVW1_E1D3BtgWvtw@mail.gmail.com --- contrib/postgres_fdw/postgres_fdw.c | 2 +- src/backend/commands/explain.c | 5 ++--- src/backend/utils/adt/ruleutils.c | 20 ++++++++++---------- src/backend/utils/cache/lsyscache.c | 2 +- src/test/regress/expected/explain.out | 13 +++++++++++++ src/test/regress/sql/explain.sql | 9 +++++++++ 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index f15c97ad7a4..51fac77f3d6 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -2854,7 +2854,7 @@ postgresExplainForeignScan(ForeignScanState *node, ExplainState *es) { char *namespace; - namespace = get_namespace_name(get_rel_namespace(rte->relid)); + namespace = get_namespace_name_or_temp(get_rel_namespace(rte->relid)); appendStringInfo(relations, "%s.%s", quote_identifier(namespace), quote_identifier(relname)); diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 340db2bac4d..36fbe129cf4 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -3747,7 +3747,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) Assert(rte->rtekind == RTE_RELATION); objectname = get_rel_name(rte->relid); if (es->verbose) - namespace = get_namespace_name(get_rel_namespace(rte->relid)); + namespace = get_namespace_name_or_temp(get_rel_namespace(rte->relid)); objecttag = "Relation Name"; break; case T_FunctionScan: @@ -3774,8 +3774,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) objectname = get_func_name(funcid); if (es->verbose) - namespace = - get_namespace_name(get_func_namespace(funcid)); + namespace = get_namespace_name_or_temp(get_func_namespace(funcid)); } } objecttag = "Function Name"; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 5e7108f9031..4df8cc5abf6 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -1617,7 +1617,7 @@ pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok) if (!columns_only) { - nsp = get_namespace_name(statextrec->stxnamespace); + nsp = get_namespace_name_or_temp(statextrec->stxnamespace); appendStringInfo(&buf, "CREATE STATISTICS %s", quote_qualified_identifier(nsp, NameStr(statextrec->stxname))); @@ -2811,7 +2811,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS) * We always qualify the function name, to ensure the right function gets * replaced. */ - nsp = get_namespace_name(proc->pronamespace); + nsp = get_namespace_name_or_temp(proc->pronamespace); appendStringInfo(&buf, "CREATE OR REPLACE %s %s(", isfunction ? "FUNCTION" : "PROCEDURE", quote_qualified_identifier(nsp, name)); @@ -11183,7 +11183,7 @@ get_opclass_name(Oid opclass, Oid actual_datatype, appendStringInfo(buf, " %s", quote_identifier(opcname)); else { - nspname = get_namespace_name(opcrec->opcnamespace); + nspname = get_namespace_name_or_temp(opcrec->opcnamespace); appendStringInfo(buf, " %s.%s", quote_identifier(nspname), quote_identifier(opcname)); @@ -11495,7 +11495,7 @@ generate_relation_name(Oid relid, List *namespaces) need_qual = !RelationIsVisible(relid); if (need_qual) - nspname = get_namespace_name(reltup->relnamespace); + nspname = get_namespace_name_or_temp(reltup->relnamespace); else nspname = NULL; @@ -11527,7 +11527,7 @@ generate_qualified_relation_name(Oid relid) reltup = (Form_pg_class) GETSTRUCT(tp); relname = NameStr(reltup->relname); - nspname = get_namespace_name(reltup->relnamespace); + nspname = get_namespace_name_or_temp(reltup->relnamespace); if (!nspname) elog(ERROR, "cache lookup failed for namespace %u", reltup->relnamespace); @@ -11639,7 +11639,7 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, p_funcid == funcid) nspname = NULL; else - nspname = get_namespace_name(procform->pronamespace); + nspname = get_namespace_name_or_temp(procform->pronamespace); result = quote_qualified_identifier(nspname, proname); @@ -11702,7 +11702,7 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2) nspname = NULL; else { - nspname = get_namespace_name(operform->oprnamespace); + nspname = get_namespace_name_or_temp(operform->oprnamespace); appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname)); } @@ -11790,7 +11790,7 @@ add_cast_to(StringInfo buf, Oid typid) typform = (Form_pg_type) GETSTRUCT(typetup); typname = NameStr(typform->typname); - nspname = get_namespace_name(typform->typnamespace); + nspname = get_namespace_name_or_temp(typform->typnamespace); appendStringInfo(buf, "::%s.%s", quote_identifier(nspname), quote_identifier(typname)); @@ -11822,7 +11822,7 @@ generate_qualified_type_name(Oid typid) typtup = (Form_pg_type) GETSTRUCT(tp); typname = NameStr(typtup->typname); - nspname = get_namespace_name(typtup->typnamespace); + nspname = get_namespace_name_or_temp(typtup->typnamespace); if (!nspname) elog(ERROR, "cache lookup failed for namespace %u", typtup->typnamespace); @@ -11856,7 +11856,7 @@ generate_collation_name(Oid collid) collname = NameStr(colltup->collname); if (!CollationIsVisible(collid)) - nspname = get_namespace_name(colltup->collnamespace); + nspname = get_namespace_name_or_temp(colltup->collnamespace); else nspname = NULL; diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 6bba5f8ec4e..4ebaa552a27 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -3340,7 +3340,7 @@ char * get_namespace_name_or_temp(Oid nspid) { if (isTempNamespace(nspid)) - return "pg_temp"; + return pstrdup("pg_temp"); else return get_namespace_name(nspid); } diff --git a/src/test/regress/expected/explain.out b/src/test/regress/expected/explain.out index cda28098baa..16e196a7bde 100644 --- a/src/test/regress/expected/explain.out +++ b/src/test/regress/expected/explain.out @@ -477,6 +477,19 @@ select jsonb_pretty( (1 row) rollback; +-- Test display of temporary objects +create temp table t1(f1 float8); +create function pg_temp.mysin(float8) returns float8 language plpgsql +as 'begin return sin($1); end'; +select explain_filter('explain (verbose) select * from t1 where pg_temp.mysin(f1) < 0.5'); + explain_filter +------------------------------------------------------------ + Seq Scan on pg_temp.t1 (cost=N.N..N.N rows=N width=N) + Output: f1 + Filter: (pg_temp.mysin(t1.f1) < 'N.N'::double precision) +(3 rows) + +-- Test compute_query_id set compute_query_id = on; select explain_filter('explain (verbose) select * from int8_tbl i8'); explain_filter diff --git a/src/test/regress/sql/explain.sql b/src/test/regress/sql/explain.sql index 3f9ae9843a2..f401d994092 100644 --- a/src/test/regress/sql/explain.sql +++ b/src/test/regress/sql/explain.sql @@ -104,5 +104,14 @@ select jsonb_pretty( rollback; +-- Test display of temporary objects +create temp table t1(f1 float8); + +create function pg_temp.mysin(float8) returns float8 language plpgsql +as 'begin return sin($1); end'; + +select explain_filter('explain (verbose) select * from t1 where pg_temp.mysin(f1) < 0.5'); + +-- Test compute_query_id set compute_query_id = on; select explain_filter('explain (verbose) select * from int8_tbl i8'); -- 2.39.5