Use the "pg_temp" schema alias in EXPLAIN and related output.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 27 Jul 2021 16:03:16 +0000 (12:03 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 27 Jul 2021 16:03:16 +0000 (12:03 -0400)
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
src/backend/commands/explain.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/lsyscache.c
src/test/regress/expected/explain.out
src/test/regress/sql/explain.sql

index f15c97ad7a482908ba6441419a624354f00e855a..51fac77f3d6592fec5dd7c4e470db4621055383a 100644 (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));
index 340db2bac4d06be150623d2bf411d3de2edeaeca..36fbe129cf47b8bbed4d13e95f93560421bdd183 100644 (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";
index 5e7108f903121c6e5dd8991711e7d74464be6cb6..4df8cc5abf6c240b3343e8eae8ac458938d759b4 100644 (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;
 
index 6bba5f8ec4e899968cc6adeb7e3941f29ccb621e..4ebaa552a2766a3643a4340e5e253793ceff001b 100644 (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);
 }
index cda28098baabae1339bb318ef9f194d477564fc8..16e196a7bde4fc40bec29a3fea0dcb404b87445b 100644 (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                         
index 3f9ae9843a2663acf68d3ba1a5885b00fe7ff226..f401d9940922960d677cc4992329294d239670b0 100644 (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');