Skip to content

Commit 1025463

Browse files
committed
In REASSIGN OWNED of a database, lock the tuple as mandated.
Commit aac2c9b mandated such locking and attempted to fulfill that mandate, but it missed REASSIGN OWNED. Hence, it remained possible to lose VACUUM's inplace update of datfrozenxid if a REASSIGN OWNED processed that database at the same time. This didn't affect the other inplace-updated catalog, pg_class. For pg_class, REASSIGN OWNED calls ATExecChangeOwner() instead of the generic AlterObjectOwner_internal(), and ATExecChangeOwner() fulfills the locking mandate. Like in GRANT, implement this by following the locking protocol for any catalog subject to the generic AlterObjectOwner_internal(). It would suffice to do this for IsInplaceUpdateOid() catalogs only. Back-patch to v13 (all supported versions). Kirill Reshke. Reported by Alexander Kukushkin. Discussion: https://postgr.es/m/CAFh8B=mpKjAy4Cuun-HP-f_vRzh2HSvYFG3rhVfYbfEBUhBAGg@mail.gmail.com
1 parent ba230ce commit 1025463

File tree

5 files changed

+51
-2
lines changed

5 files changed

+51
-2
lines changed

src/backend/catalog/objectaddress.c

+26-1
Original file line numberDiff line numberDiff line change
@@ -2705,14 +2705,35 @@ get_object_property_data(Oid class_id)
27052705
*/
27062706
HeapTuple
27072707
get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
2708+
{
2709+
return
2710+
get_catalog_object_by_oid_extended(catalog, oidcol, objectId, false);
2711+
}
2712+
2713+
/*
2714+
* Same as get_catalog_object_by_oid(), but with an additional "locktup"
2715+
* argument controlling whether to acquire a LOCKTAG_TUPLE at mode
2716+
* InplaceUpdateTupleLock. See README.tuplock section "Locking to write
2717+
* inplace-updated tables".
2718+
*/
2719+
HeapTuple
2720+
get_catalog_object_by_oid_extended(Relation catalog,
2721+
AttrNumber oidcol,
2722+
Oid objectId,
2723+
bool locktup)
27082724
{
27092725
HeapTuple tuple;
27102726
Oid classId = RelationGetRelid(catalog);
27112727
int oidCacheId = get_object_catcache_oid(classId);
27122728

27132729
if (oidCacheId > 0)
27142730
{
2715-
tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
2731+
if (locktup)
2732+
tuple = SearchSysCacheLockedCopy1(oidCacheId,
2733+
ObjectIdGetDatum(objectId));
2734+
else
2735+
tuple = SearchSysCacheCopy1(oidCacheId,
2736+
ObjectIdGetDatum(objectId));
27162737
if (!HeapTupleIsValid(tuple)) /* should not happen */
27172738
return NULL;
27182739
}
@@ -2737,6 +2758,10 @@ get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
27372758
systable_endscan(scan);
27382759
return NULL;
27392760
}
2761+
2762+
if (locktup)
2763+
LockTuple(catalog, &tuple->t_self, InplaceUpdateTupleLock);
2764+
27402765
tuple = heap_copytuple(tuple);
27412766

27422767
systable_endscan(scan);

src/backend/commands/alter.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#include "miscadmin.h"
6161
#include "parser/parse_func.h"
6262
#include "rewrite/rewriteDefine.h"
63+
#include "storage/lmgr.h"
6364
#include "tcop/utility.h"
6465
#include "utils/builtins.h"
6566
#include "utils/fmgroids.h"
@@ -945,7 +946,9 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
945946
Oid old_ownerId;
946947
Oid namespaceId = InvalidOid;
947948

948-
oldtup = get_catalog_object_by_oid(rel, Anum_oid, objectId);
949+
/* Search tuple and lock it. */
950+
oldtup =
951+
get_catalog_object_by_oid_extended(rel, Anum_oid, objectId, true);
949952
if (oldtup == NULL)
950953
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
951954
objectId, RelationGetRelationName(rel));
@@ -1044,6 +1047,8 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
10441047
/* Perform actual update */
10451048
CatalogTupleUpdate(rel, &newtup->t_self, newtup);
10461049

1050+
UnlockTuple(rel, &oldtup->t_self, InplaceUpdateTupleLock);
1051+
10471052
/*
10481053
* Update owner dependency reference. When working on a large object,
10491054
* we have to translate back to the OID conventionally used for LOs'
@@ -1061,6 +1066,8 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
10611066
}
10621067
else
10631068
{
1069+
UnlockTuple(rel, &oldtup->t_self, InplaceUpdateTupleLock);
1070+
10641071
/*
10651072
* No need to change anything. But when working on a large object, we
10661073
* have to translate back to the OID conventionally used for LOs'

src/include/catalog/objectaddress.h

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ extern bool get_object_namensp_unique(Oid class_id);
6868

6969
extern HeapTuple get_catalog_object_by_oid(Relation catalog,
7070
AttrNumber oidcol, Oid objectId);
71+
extern HeapTuple get_catalog_object_by_oid_extended(Relation catalog,
72+
AttrNumber oidcol,
73+
Oid objectId,
74+
bool locktup);
7175

7276
extern char *getObjectDescription(const ObjectAddress *object);
7377
extern char *getObjectDescriptionOids(Oid classid, Oid objid);

src/test/regress/expected/database.out

+6
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,10 @@ WHERE datname = 'regression_utf8';
1111
-- load catcache entry, if nothing else does
1212
ALTER DATABASE regression_utf8 RESET TABLESPACE;
1313
ROLLBACK;
14+
CREATE ROLE regress_datdba_before;
15+
CREATE ROLE regress_datdba_after;
16+
ALTER DATABASE regression_utf8 OWNER TO regress_datdba_before;
17+
REASSIGN OWNED BY regress_datdba_before TO regress_datdba_after;
1418
DROP DATABASE regression_utf8;
19+
DROP ROLE regress_datdba_before;
20+
DROP ROLE regress_datdba_after;

src/test/regress/sql/database.sql

+7
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,11 @@ WHERE datname = 'regression_utf8';
1313
ALTER DATABASE regression_utf8 RESET TABLESPACE;
1414
ROLLBACK;
1515

16+
CREATE ROLE regress_datdba_before;
17+
CREATE ROLE regress_datdba_after;
18+
ALTER DATABASE regression_utf8 OWNER TO regress_datdba_before;
19+
REASSIGN OWNED BY regress_datdba_before TO regress_datdba_after;
20+
1621
DROP DATABASE regression_utf8;
22+
DROP ROLE regress_datdba_before;
23+
DROP ROLE regress_datdba_after;

0 commit comments

Comments
 (0)