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
This commit is contained in:
Tom Lane 2021-07-27 12:03:16 -04:00
parent 91d76613b7
commit 48c5c90682
6 changed files with 36 additions and 15 deletions

View File

@ -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));

View File

@ -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";

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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');