On Thu, Aug 6, 2026 at 8:19 PM Fujii Masao <[email protected]> wrote:
>
> Hi,
>
> I'd like to propose the attached patch, which makes object address output
> distinguish publication EXCEPT entries from ordinary publication table
> mappings.
>
> pg_publication_rel can now represent either an explicitly published table
> or a table excluded from a FOR ALL TABLES publication. However,
> the object address code currently treats every pg_publication_rel entry
> as a publication relation.
>
> For example,
>
>     =# CREATE TABLE t (a int);
>     =# CREATE PUBLICATION p FOR ALL TABLES EXCEPT (TABLE t);
>     =# SELECT pi.* FROM pg_publication_rel pp CROSS JOIN LATERAL
>         pg_identify_object('pg_publication_rel'::regclass, pp.oid, 0) AS pi;
>              type         | schema |  name  |         identity
>     ----------------------+--------+--------+---------------------------
>      publication relation | (null) | (null) | public.t in publication p
>
>     =# SELECT pd.* FROM pg_publication_rel pp CROSS JOIN LATERAL
>         pg_describe_object('pg_publication_rel'::regclass, pp.oid, 0) AS pd;
>                        pd
>     -----------------------------------------
>      publication of table t in publication p
>
> Although the pg_publication_rel entry for t represents an exclusion,
> the object address output makes it appear to be an ordinary published-table
> mapping. This affects pg_identify_object(), pg_describe_object(),
> and pg_identify_object_as_address(), and can also be confusing for tools
> that use object addresses, such as audit or DDL deparsing tools.

I agree.

> The root cause is that objectaddress.c does not check
> pg_publication_rel.prexcept when describing or identifying
> pg_publication_rel objects.
>
> The patch fixes this by distinguishing EXCEPT entries. They are now
> reported as publication exclusion, with identities such as:
>
>     =# SELECT pi.* FROM pg_publication_rel pp CROSS JOIN LATERAL
>         pg_identify_object('pg_publication_rel'::regclass, pp.oid, 0) AS pi;
>              type          | schema |  name  |               identity
>     
> -----------------------+--------+--------+--------------------------------------
>      publication exclusion | (null) | (null) | public.t excluded from
> publication p
>
>     =# SELECT pd.* FROM pg_publication_rel pp CROSS JOIN LATERAL
>         pg_describe_object('pg_publication_rel'::regclass, pp.oid, 0) AS pd;
>                        pd
>     -----------------------------------------
>      exclusion of table t from publication p
>
> Thoughts?
>

Agree with the problem statement and the approach. Please find a few
initial comments, will review in detail next week.

1)
getObjectTypeDescription:

+ if (isPublicationRelationExcept(object->objectId, missing_ok))
+ appendStringInfoString(&buffer, "publication exclusion");
+ else
+ appendStringInfoString(&buffer, "publication relation");

It seems strange initially that when missing_okay is true and say
cache-tuple is missing, we ccnsider it as 'publication relation'. But
then I checked other calls accepting 'missing_ok' in the same function
such as: getProcedureTypeDescription, getConstraintTypeDescription.
They have a fallback option for undefined object. The comment there
makes it clear. Perhaps we should add similar comment here.

2)
It seems that get_object_address_publication_rel() currently performs
two cache lookups to obtain the complete details of the relation.
Ideally, a single lookup would suffice, although that would likely
require restructuring the implementation instead of going through
isPublicationRelationExcept(). That said, I understand that
isPublicationRelationExcept() is still needed in other code paths, so
even though I would prefer a single cache lookup, keeping the current
approach is fine as well.

thanks
Shveta


Reply via email to