mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Distinguish publication exclusions in object addresses.
A pg_publication_rel entry can represent either an explicitly published
relation or a table excluded from a FOR ALL TABLES publication, but the
object address code treated every entry as a published relation without
checking prexcept. EXCEPT entries thus appeared as ordinary
published-table mappings in dependency messages, pg_identify_object(),
and pg_identify_object_as_address().
Report such entries as "publication excluded relation" instead, with
object identities indicating that the table is excluded from the
publication. pg_get_object_address() also accepts this new object type,
so that the output of pg_identify_object_as_address() can still be
passed back to it to look up the same object. "publication relation"
now resolves only non-EXCEPT entries, and "publication excluded
relation" only EXCEPT entries.
Oversight in commit fd366065e0.
Author: Fujii Masao <masao.fujii@gmail.com>
Author: Vignesh C <vignesh21@gmail.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Peter Smith <smithpb2250@gmail.com>
Reviewed-by: Zhijie Hou <houzj.fnst@fujitsu.com>
Reviewed-by: Nisha Moond <nisha.moond412@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Manuel Reyes Bravo <manuelreyesbravo@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwHfESBexa7fq99EvFCf31av=O9h9udnw22ymxmm6LMZzw@mail.gmail.com
Backpatch-through: 19, where it was introduced
This commit is contained in:
@@ -2765,6 +2765,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
|
||||
case OBJECT_DEFAULT:
|
||||
case OBJECT_DEFACL:
|
||||
case OBJECT_DOMCONSTRAINT:
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_ROLE:
|
||||
@@ -2906,6 +2907,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
|
||||
case OBJECT_DEFACL:
|
||||
case OBJECT_DOMCONSTRAINT:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_ROLE:
|
||||
|
||||
@@ -823,6 +823,9 @@ static const struct object_type_map
|
||||
{
|
||||
"publication relation", OBJECT_PUBLICATION_REL
|
||||
},
|
||||
{
|
||||
"publication excluded relation", OBJECT_PUBLICATION_EXCLUDED_REL
|
||||
},
|
||||
{
|
||||
"subscription", OBJECT_SUBSCRIPTION
|
||||
},
|
||||
@@ -863,7 +866,8 @@ 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);
|
||||
static ObjectAddress get_object_address_publication_schema(List *object,
|
||||
@@ -880,6 +884,9 @@ static void getRelationTypeDescription(StringInfo buffer, Oid relid,
|
||||
int32 objectSubId, bool missing_ok);
|
||||
static void getProcedureTypeDescription(StringInfo buffer, Oid procid,
|
||||
bool missing_ok);
|
||||
static void getPublicationRelationTypeDescription(StringInfo buffer,
|
||||
Oid pubreloid,
|
||||
bool missing_ok);
|
||||
static void getConstraintTypeDescription(StringInfo buffer, Oid constroid,
|
||||
bool missing_ok);
|
||||
static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
|
||||
@@ -1112,8 +1119,10 @@ get_object_address(ObjectType objtype, Node *object,
|
||||
address = get_object_address_publication_schema(castNode(List, object),
|
||||
missing_ok);
|
||||
break;
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
address = get_object_address_publication_rel(castNode(List, object),
|
||||
address = get_object_address_publication_rel(objtype,
|
||||
castNode(List, object),
|
||||
&relation,
|
||||
missing_ok);
|
||||
break;
|
||||
@@ -1860,12 +1869,12 @@ get_object_address_usermapping(List *object, bool missing_ok)
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the ObjectAddress for a publication relation. 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,
|
||||
get_object_address_publication_rel(ObjectType objtype, List *object,
|
||||
Relation *relp, bool missing_ok)
|
||||
{
|
||||
ObjectAddress address;
|
||||
@@ -1873,6 +1882,12 @@ get_object_address_publication_rel(List *object,
|
||||
List *relname;
|
||||
char *pubname;
|
||||
Publication *pub;
|
||||
Form_pg_publication_rel prform;
|
||||
HeapTuple tup;
|
||||
bool isexcept;
|
||||
|
||||
Assert(objtype == OBJECT_PUBLICATION_REL ||
|
||||
objtype == OBJECT_PUBLICATION_EXCLUDED_REL);
|
||||
|
||||
ObjectAddressSet(address, PublicationRelRelationId, InvalidOid);
|
||||
|
||||
@@ -1893,22 +1908,54 @@ get_object_address_publication_rel(List *object,
|
||||
return address;
|
||||
}
|
||||
|
||||
/* Find the publication relation mapping in syscache. */
|
||||
address.objectId =
|
||||
GetSysCacheOid2(PUBLICATIONRELMAP, Anum_pg_publication_rel_oid,
|
||||
ObjectIdGetDatum(RelationGetRelid(relation)),
|
||||
ObjectIdGetDatum(pub->oid));
|
||||
if (!OidIsValid(address.objectId))
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
tup = SearchSysCache2(PUBLICATIONRELMAP,
|
||||
ObjectIdGetDatum(RelationGetRelid(relation)),
|
||||
ObjectIdGetDatum(pub->oid));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
if (!missing_ok)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("publication relation \"%s\" in publication \"%s\" does not exist",
|
||||
RelationGetRelationName(relation), pubname)));
|
||||
{
|
||||
if (objtype == OBJECT_PUBLICATION_EXCLUDED_REL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("publication excluded relation \"%s\" in publication \"%s\" does not exist",
|
||||
RelationGetRelationName(relation), pubname)));
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
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 (objtype == OBJECT_PUBLICATION_EXCLUDED_REL && !isexcept)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not an excluded relation of publication \"%s\"",
|
||||
RelationGetRelationName(relation), pubname)));
|
||||
else if (objtype == OBJECT_PUBLICATION_REL && isexcept)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a published relation of publication \"%s\"",
|
||||
RelationGetRelationName(relation), pubname)));
|
||||
|
||||
*relp = relation;
|
||||
return address;
|
||||
}
|
||||
@@ -2235,6 +2282,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
|
||||
pg_fallthrough;
|
||||
case OBJECT_DOMCONSTRAINT:
|
||||
case OBJECT_CAST:
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_DEFACL:
|
||||
case OBJECT_TRANSFORM:
|
||||
@@ -2326,6 +2374,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
|
||||
case OBJECT_TRANSFORM:
|
||||
objnode = (Node *) list_make2(typename, linitial(args));
|
||||
break;
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
objnode = (Node *) list_make2(name, linitial(args));
|
||||
break;
|
||||
@@ -2554,6 +2603,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
|
||||
case OBJECT_AMPROC:
|
||||
case OBJECT_DEFAULT:
|
||||
case OBJECT_DEFACL:
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_USER_MAPPING:
|
||||
@@ -4025,9 +4075,18 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
|
||||
initStringInfo(&rel);
|
||||
getRelationDescription(&rel, prform->prrelid, false);
|
||||
|
||||
/* translator: first %s is, e.g., "table %s" */
|
||||
appendStringInfo(&buffer, _("publication of %s in publication %s"),
|
||||
rel.data, pubname);
|
||||
if (prform->prexcept)
|
||||
{
|
||||
/* translator: first %s is, e.g., "table %s" */
|
||||
appendStringInfo(&buffer, _("exclusion of %s from publication %s"),
|
||||
rel.data, pubname);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* translator: first %s is, e.g., "table %s" */
|
||||
appendStringInfo(&buffer, _("publication of %s in publication %s"),
|
||||
rel.data, pubname);
|
||||
}
|
||||
pfree(rel.data);
|
||||
ReleaseSysCache(tup);
|
||||
break;
|
||||
@@ -4659,7 +4718,8 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
|
||||
break;
|
||||
|
||||
case PublicationRelRelationId:
|
||||
appendStringInfoString(&buffer, "publication relation");
|
||||
getPublicationRelationTypeDescription(&buffer, object->objectId,
|
||||
missing_ok);
|
||||
break;
|
||||
|
||||
case SubscriptionRelationId:
|
||||
@@ -4813,6 +4873,41 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid,
|
||||
ReleaseSysCache(procTup);
|
||||
}
|
||||
|
||||
/*
|
||||
* subroutine for getObjectTypeDescription: describe a publication relation
|
||||
*
|
||||
* Appends "publication excluded relation" for EXCEPT entries, or
|
||||
* "publication relation" for published relations, to buffer.
|
||||
*/
|
||||
static void
|
||||
getPublicationRelationTypeDescription(StringInfo buffer, Oid pubreloid,
|
||||
bool missing_ok)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Form_pg_publication_rel prform;
|
||||
|
||||
tup = SearchSysCache1(PUBLICATIONREL, ObjectIdGetDatum(pubreloid));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "cache lookup failed for publication table %u",
|
||||
pubreloid);
|
||||
|
||||
/* fallback to "publication relation" for an undefined object */
|
||||
appendStringInfoString(buffer, "publication relation");
|
||||
return;
|
||||
}
|
||||
|
||||
prform = (Form_pg_publication_rel) GETSTRUCT(tup);
|
||||
|
||||
if (prform->prexcept)
|
||||
appendStringInfoString(buffer, "publication excluded relation");
|
||||
else
|
||||
appendStringInfoString(buffer, "publication relation");
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain a given object's identity, as a palloc'ed string.
|
||||
*
|
||||
@@ -5954,7 +6049,11 @@ getObjectIdentityParts(const ObjectAddress *object,
|
||||
pubname = get_publication_name(prform->prpubid, false);
|
||||
|
||||
getRelationIdentity(&buffer, prform->prrelid, objname, false);
|
||||
appendStringInfo(&buffer, " in publication %s", pubname);
|
||||
if (prform->prexcept)
|
||||
appendStringInfo(&buffer, " excluded from publication %s",
|
||||
pubname);
|
||||
else
|
||||
appendStringInfo(&buffer, " in publication %s", pubname);
|
||||
|
||||
if (objargs)
|
||||
*objargs = list_make1(pubname);
|
||||
|
||||
@@ -504,6 +504,7 @@ does_not_exist_skipping(ObjectType objtype, Node *object)
|
||||
case OBJECT_DOMCONSTRAINT:
|
||||
case OBJECT_LARGEOBJECT:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_TABCONSTRAINT:
|
||||
|
||||
@@ -2316,6 +2316,7 @@ stringify_grant_objtype(ObjectType objtype)
|
||||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_POLICY:
|
||||
case OBJECT_PUBLICATION:
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_ROLE:
|
||||
@@ -2400,6 +2401,7 @@ stringify_adefprivs_objtype(ObjectType objtype)
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_POLICY:
|
||||
case OBJECT_PUBLICATION:
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_ROLE:
|
||||
|
||||
@@ -80,6 +80,7 @@ SecLabelSupportsObjectType(ObjectType objtype)
|
||||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_POLICY:
|
||||
case OBJECT_PUBLICATION_EXCLUDED_REL:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_RULE:
|
||||
|
||||
@@ -2351,6 +2351,7 @@ typedef enum ObjectType
|
||||
OBJECT_POLICY,
|
||||
OBJECT_PROCEDURE,
|
||||
OBJECT_PUBLICATION,
|
||||
OBJECT_PUBLICATION_EXCLUDED_REL,
|
||||
OBJECT_PUBLICATION_NAMESPACE,
|
||||
OBJECT_PUBLICATION_REL,
|
||||
OBJECT_ROLE,
|
||||
|
||||
@@ -111,7 +111,8 @@ BEGIN
|
||||
('text search template'), ('text search configuration'),
|
||||
('policy'), ('user mapping'), ('default acl'), ('transform'),
|
||||
('operator of access method'), ('function of access method'),
|
||||
('publication namespace'), ('publication relation')
|
||||
('publication namespace'), ('publication relation'),
|
||||
('publication excluded relation')
|
||||
LOOP
|
||||
FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}')
|
||||
LOOP
|
||||
@@ -331,6 +332,12 @@ WARNING: error for publication relation,{addr_nsp,zwei},{}: argument list lengt
|
||||
WARNING: error for publication relation,{addr_nsp,zwei},{integer}: relation "addr_nsp.zwei" does not exist
|
||||
WARNING: error for publication relation,{eins,zwei,drei},{}: argument list length must be exactly 1
|
||||
WARNING: error for publication relation,{eins,zwei,drei},{integer}: cross-database references are not implemented: "eins.zwei.drei"
|
||||
WARNING: error for publication excluded relation,{eins},{}: argument list length must be exactly 1
|
||||
WARNING: error for publication excluded relation,{eins},{integer}: relation "eins" does not exist
|
||||
WARNING: error for publication excluded relation,{addr_nsp,zwei},{}: argument list length must be exactly 1
|
||||
WARNING: error for publication excluded relation,{addr_nsp,zwei},{integer}: relation "addr_nsp.zwei" does not exist
|
||||
WARNING: error for publication excluded relation,{eins,zwei,drei},{}: argument list length must be exactly 1
|
||||
WARNING: error for publication excluded relation,{eins,zwei,drei},{integer}: cross-database references are not implemented: "eins.zwei.drei"
|
||||
-- these object types cannot be qualified names
|
||||
SELECT pg_get_object_address('language', '{one}', '{}');
|
||||
ERROR: language "one" does not exist
|
||||
@@ -509,6 +516,23 @@ subscription|NULL|regress_addr_sub|regress_addr_sub|t
|
||||
publication|NULL|addr_pub|addr_pub|t
|
||||
publication relation|NULL|NULL|addr_nsp.gentable in publication addr_pub|t
|
||||
publication namespace|NULL|NULL|addr_nsp in publication addr_pub_schema|t
|
||||
-- A FOR ALL TABLES publication is listed by \d for every table in the
|
||||
-- database, which would disturb the other tests running concurrently in this
|
||||
-- parallel group. Create it in a transaction that is rolled back, so that it
|
||||
-- is never visible to another session.
|
||||
BEGIN;
|
||||
SET LOCAL client_min_messages = 'ERROR';
|
||||
CREATE PUBLICATION addr_pub_except FOR ALL TABLES EXCEPT (TABLE addr_nsp.gentable);
|
||||
SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.objsubid)).*,
|
||||
ROW(pg_identify_object(addr1.classid, addr1.objid, addr1.objsubid)) =
|
||||
ROW(pg_identify_object(addr2.classid, addr2.objid, addr2.objsubid)) AS roundtrip
|
||||
FROM pg_get_object_address('publication excluded relation',
|
||||
'{addr_nsp, gentable}',
|
||||
'{addr_pub_except}') AS addr1,
|
||||
pg_identify_object_as_address(classid, objid, objsubid) AS ioa (typ, nms, args),
|
||||
pg_get_object_address(typ, nms, ioa.args) AS addr2;
|
||||
publication excluded relation|NULL|NULL|addr_nsp.gentable excluded from publication addr_pub_except|t
|
||||
ROLLBACK;
|
||||
---
|
||||
--- Cleanup resources
|
||||
---
|
||||
|
||||
@@ -265,6 +265,41 @@ Excluded from publications:
|
||||
"testpub_foralltables_excepttable"
|
||||
"testpub_foralltables_excepttable1"
|
||||
|
||||
-- Check object address handling for an EXCEPT entry.
|
||||
\a\t
|
||||
SELECT (pg_identify_object('pg_publication_rel'::regclass, pr.oid, 0)).*
|
||||
FROM pg_publication_rel pr
|
||||
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';
|
||||
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_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: "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 excluded relation "testpub_tbl1" in publication "testpub_default" does not exist
|
||||
-- Check pg_describe_object output for both included and excluded entries
|
||||
SELECT p.pubname,
|
||||
pg_describe_object('pg_publication_rel'::regclass, pr.oid, 0) AS description,
|
||||
pr.prexcept
|
||||
FROM pg_publication_rel pr
|
||||
JOIN pg_publication p ON p.oid = pr.prpubid
|
||||
WHERE p.pubname IN ('testpub_describe', 'testpub_foralltables_excepttable1')
|
||||
ORDER BY p.pubname;
|
||||
testpub_describe|publication of table testpub_tbl1 in publication testpub_describe|f
|
||||
testpub_foralltables_excepttable1|exclusion of table testpub_tbl1 from publication testpub_foralltables_excepttable1|t
|
||||
DROP PUBLICATION testpub_describe;
|
||||
\a\t
|
||||
-- fail - first table in the EXCEPT list should use TABLE keyword
|
||||
CREATE PUBLICATION testpub_foralltables_excepttable2 FOR ALL TABLES EXCEPT (testpub_tbl1, testpub_tbl2);
|
||||
ERROR: syntax error at or near "testpub_tbl1"
|
||||
|
||||
@@ -103,7 +103,8 @@ BEGIN
|
||||
('text search template'), ('text search configuration'),
|
||||
('policy'), ('user mapping'), ('default acl'), ('transform'),
|
||||
('operator of access method'), ('function of access method'),
|
||||
('publication namespace'), ('publication relation')
|
||||
('publication namespace'), ('publication relation'),
|
||||
('publication excluded relation')
|
||||
LOOP
|
||||
FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}')
|
||||
LOOP
|
||||
@@ -225,6 +226,23 @@ FROM objects,
|
||||
pg_get_object_address(typ, nms, ioa.args) AS addr2
|
||||
ORDER BY addr1.classid, addr1.objid, addr1.objsubid;
|
||||
|
||||
-- A FOR ALL TABLES publication is listed by \d for every table in the
|
||||
-- database, which would disturb the other tests running concurrently in this
|
||||
-- parallel group. Create it in a transaction that is rolled back, so that it
|
||||
-- is never visible to another session.
|
||||
BEGIN;
|
||||
SET LOCAL client_min_messages = 'ERROR';
|
||||
CREATE PUBLICATION addr_pub_except FOR ALL TABLES EXCEPT (TABLE addr_nsp.gentable);
|
||||
SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.objsubid)).*,
|
||||
ROW(pg_identify_object(addr1.classid, addr1.objid, addr1.objsubid)) =
|
||||
ROW(pg_identify_object(addr2.classid, addr2.objid, addr2.objsubid)) AS roundtrip
|
||||
FROM pg_get_object_address('publication excluded relation',
|
||||
'{addr_nsp, gentable}',
|
||||
'{addr_pub_except}') AS addr1,
|
||||
pg_identify_object_as_address(classid, objid, objsubid) AS ioa (typ, nms, args),
|
||||
pg_get_object_address(typ, nms, ioa.args) AS addr2;
|
||||
ROLLBACK;
|
||||
|
||||
---
|
||||
--- Cleanup resources
|
||||
---
|
||||
|
||||
@@ -121,6 +121,35 @@ CREATE PUBLICATION testpub_foralltables_excepttable1 FOR ALL TABLES EXCEPT (TABL
|
||||
-- Check that the table description shows the publications where it is listed
|
||||
-- in the EXCEPT clause
|
||||
\d testpub_tbl1
|
||||
-- Check object address handling for an EXCEPT entry.
|
||||
\a\t
|
||||
SELECT (pg_identify_object('pg_publication_rel'::regclass, pr.oid, 0)).*
|
||||
FROM pg_publication_rel pr
|
||||
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_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
|
||||
SELECT p.pubname,
|
||||
pg_describe_object('pg_publication_rel'::regclass, pr.oid, 0) AS description,
|
||||
pr.prexcept
|
||||
FROM pg_publication_rel pr
|
||||
JOIN pg_publication p ON p.oid = pr.prpubid
|
||||
WHERE p.pubname IN ('testpub_describe', 'testpub_foralltables_excepttable1')
|
||||
ORDER BY p.pubname;
|
||||
DROP PUBLICATION testpub_describe;
|
||||
\a\t
|
||||
-- fail - first table in the EXCEPT list should use TABLE keyword
|
||||
CREATE PUBLICATION testpub_foralltables_excepttable2 FOR ALL TABLES EXCEPT (testpub_tbl1, testpub_tbl2);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user