diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 5b3aadf81f9..eebb10f2352 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -866,10 +866,10 @@ static ObjectAddress get_object_address_opf_member(ObjectType objtype, static ObjectAddress get_object_address_usermapping(List *object, bool missing_ok); -static ObjectAddress get_object_address_publication_rel(List *object, +static ObjectAddress get_object_address_publication_rel(ObjectType objtype, + List *object, Relation *relp, - bool missing_ok, - bool pubrel_is_exclusion); + bool missing_ok); static ObjectAddress get_object_address_publication_schema(List *object, bool missing_ok); static ObjectAddress get_object_address_defacl(List *object, @@ -1121,10 +1121,10 @@ get_object_address(ObjectType objtype, Node *object, break; case OBJECT_PUBLICATION_REL: case OBJECT_PUBLICATION_EXCLUDED_REL: - address = get_object_address_publication_rel(castNode(List, object), + address = get_object_address_publication_rel(objtype, + castNode(List, object), &relation, - missing_ok, - objtype == OBJECT_PUBLICATION_EXCLUDED_REL); + missing_ok); break; case OBJECT_DEFACL: address = get_object_address_defacl(castNode(List, object), @@ -1869,21 +1869,22 @@ get_object_address_usermapping(List *object, bool missing_ok) } /* - * Find the ObjectAddress for a publication relation or exclusion. The first - * element of the object parameter is the relation name, the second is the - * publication name. + * Find the ObjectAddress for a published or excluded publication relation. + * The first element of the object parameter is the relation name, the second + * is the publication name. */ static ObjectAddress -get_object_address_publication_rel(List *object, - Relation *relp, bool missing_ok, - bool pubrel_is_exclusion) +get_object_address_publication_rel(ObjectType objtype, List *object, + Relation *relp, bool missing_ok) { ObjectAddress address; Relation relation; List *relname; char *pubname; Publication *pub; + Form_pg_publication_rel prform; HeapTuple tup; + bool isexcept; ObjectAddressSet(address, PublicationRelRelationId, InvalidOid); @@ -1907,46 +1908,47 @@ get_object_address_publication_rel(List *object, /* * Find the publication relation mapping in syscache. Fetch the tuple * rather than just its OID, so that prexcept can be checked without a - * second lookup. A missing entry, or one of the other kind, falls - * through to the not-found handling below. + * second lookup. */ tup = SearchSysCache2(PUBLICATIONRELMAP, ObjectIdGetDatum(RelationGetRelid(relation)), ObjectIdGetDatum(pub->oid)); - if (HeapTupleIsValid(tup)) + if (!HeapTupleIsValid(tup)) { - /* Found row in pg_publication_rel */ - Form_pg_publication_rel prform = - (Form_pg_publication_rel) GETSTRUCT(tup); - Oid pubreloid = prform->oid; - bool isexcept = prform->prexcept; - - ReleaseSysCache(tup); - - /* Treat a prexcept mismatch as not found. */ - if (isexcept == pubrel_is_exclusion) - { - address.objectId = pubreloid; - *relp = relation; - return address; - } + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication relation \"%s\" in publication \"%s\" does not exist", + RelationGetRelationName(relation), pubname))); + relation_close(relation, AccessShareLock); + return address; } - if (!missing_ok) + prform = (Form_pg_publication_rel) GETSTRUCT(tup); + address.objectId = prform->oid; + isexcept = prform->prexcept; + ReleaseSysCache(tup); + + /* + * The same relation and publication pair identifies either a published or + * an excluded relation, so reject an entry of the kind that was not asked + * for. + */ + if (isexcept != (objtype == OBJECT_PUBLICATION_EXCLUDED_REL)) { - if (pubrel_is_exclusion) + if (isexcept) ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("publication excluded relation \"%s\" from publication \"%s\" does not exist", + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a published relation of publication \"%s\"", RelationGetRelationName(relation), pubname))); else ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("publication relation \"%s\" in publication \"%s\" does not exist", + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not an excluded relation of publication \"%s\"", RelationGetRelationName(relation), pubname))); } - relation_close(relation, AccessShareLock); + *relp = relation; return address; } diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index 534b0f3f8af..7ccfb5810a6 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -283,15 +283,21 @@ JOIN pg_class c ON c.oid = pr.prrelid WHERE p.pubname = 'testpub_foralltables_excepttable1' AND c.relname = 'testpub_tbl1'; publication excluded relation|||public.testpub_tbl1 excluded from publication testpub_foralltables_excepttable1 +-- testpub_describe publishes testpub_tbl1, testpub_foralltables_excepttable1 +-- excludes it; an entry of one kind must not be resolved as the other. +CREATE PUBLICATION testpub_describe FOR TABLE testpub_tbl1; SELECT pg_get_object_address('publication excluded relation', - '{public, testpub_tbl1}', '{testpub_fortable}'); -ERROR: publication excluded relation "testpub_tbl1" from publication "testpub_fortable" does not exist + '{public, testpub_tbl1}', '{testpub_describe}'); +ERROR: "testpub_tbl1" is not an excluded relation of publication "testpub_describe" SELECT pg_get_object_address('publication relation', '{public, testpub_tbl1}', '{testpub_foralltables_excepttable1}'); -ERROR: publication relation "testpub_tbl1" in publication "testpub_foralltables_excepttable1" does not exist +ERROR: "testpub_tbl1" is not a published relation of publication "testpub_foralltables_excepttable1" +-- No entry of either kind. testpub_default publishes nothing. +SELECT pg_get_object_address('publication excluded relation', + '{public, testpub_tbl1}', '{testpub_default}'); +ERROR: publication relation "testpub_tbl1" in publication "testpub_default" does not exist -- Check pg_describe_object output for both included and excluded entries -CREATE PUBLICATION testpub_describe FOR TABLE testpub_tbl1; SELECT p.pubname, pg_describe_object('pg_publication_rel'::regclass, pr.oid, 0) AS description, pr.prexcept diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index 2e4bf749149..074482605d9 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -131,13 +131,18 @@ JOIN pg_publication p ON p.oid = pr.prpubid JOIN pg_class c ON c.oid = pr.prrelid WHERE p.pubname = 'testpub_foralltables_excepttable1' AND c.relname = 'testpub_tbl1'; +-- testpub_describe publishes testpub_tbl1, testpub_foralltables_excepttable1 +-- excludes it; an entry of one kind must not be resolved as the other. +CREATE PUBLICATION testpub_describe FOR TABLE testpub_tbl1; SELECT pg_get_object_address('publication excluded relation', - '{public, testpub_tbl1}', '{testpub_fortable}'); + '{public, testpub_tbl1}', '{testpub_describe}'); SELECT pg_get_object_address('publication relation', '{public, testpub_tbl1}', '{testpub_foralltables_excepttable1}'); +-- No entry of either kind. testpub_default publishes nothing. +SELECT pg_get_object_address('publication excluded relation', + '{public, testpub_tbl1}', '{testpub_default}'); -- Check pg_describe_object output for both included and excluded entries -CREATE PUBLICATION testpub_describe FOR TABLE testpub_tbl1; SELECT p.pubname, pg_describe_object('pg_publication_rel'::regclass, pr.oid, 0) AS description, pr.prexcept