Skip to content

Commit fa61313

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 d8b0c64 commit fa61313

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
@@ -2779,14 +2779,35 @@ get_object_property_data(Oid class_id)
27792779
*/
27802780
HeapTuple
27812781
get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
2782+
{
2783+
return
2784+
get_catalog_object_by_oid_extended(catalog, oidcol, objectId, false);
2785+
}
2786+
2787+
/*
2788+
* Same as get_catalog_object_by_oid(), but with an additional "locktup"
2789+
* argument controlling whether to acquire a LOCKTAG_TUPLE at mode
2790+
* InplaceUpdateTupleLock. See README.tuplock section "Locking to write
2791+
* inplace-updated tables".
2792+
*/
2793+
HeapTuple
2794+
get_catalog_object_by_oid_extended(Relation catalog,
2795+
AttrNumber oidcol,
2796+
Oid objectId,
2797+
bool locktup)
27822798
{
27832799
HeapTuple tuple;
27842800
Oid classId = RelationGetRelid(catalog);
27852801
int oidCacheId = get_object_catcache_oid(classId);
27862802

27872803
if (oidCacheId > 0)
27882804
{
2789-
tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
2805+
if (locktup)
2806+
tuple = SearchSysCacheLockedCopy1(oidCacheId,
2807+
ObjectIdGetDatum(objectId));
2808+
else
2809+
tuple = SearchSysCacheCopy1(oidCacheId,
2810+
ObjectIdGetDatum(objectId));
27902811
if (!HeapTupleIsValid(tuple)) /* should not happen */
27912812
return NULL;
27922813
}
@@ -2811,6 +2832,10 @@ get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
28112832
systable_endscan(scan);
28122833
return NULL;
28132834
}
2835+
2836+
if (locktup)
2837+
LockTuple(catalog, &tuple->t_self, InplaceUpdateTupleLock);
2838+
28142839
tuple = heap_copytuple(tuple);
28152840

28162841
systable_endscan(scan);

src/backend/commands/alter.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "miscadmin.h"
6060
#include "replication/logicalworker.h"
6161
#include "rewrite/rewriteDefine.h"
62+
#include "storage/lmgr.h"
6263
#include "utils/acl.h"
6364
#include "utils/builtins.h"
6465
#include "utils/lsyscache.h"
@@ -931,7 +932,9 @@ AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId)
931932

932933
rel = table_open(catalogId, RowExclusiveLock);
933934

934-
oldtup = get_catalog_object_by_oid(rel, Anum_oid, objectId);
935+
/* Search tuple and lock it. */
936+
oldtup =
937+
get_catalog_object_by_oid_extended(rel, Anum_oid, objectId, true);
935938
if (oldtup == NULL)
936939
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
937940
objectId, RelationGetRelationName(rel));
@@ -1031,6 +1034,8 @@ AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId)
10311034
/* Perform actual update */
10321035
CatalogTupleUpdate(rel, &newtup->t_self, newtup);
10331036

1037+
UnlockTuple(rel, &oldtup->t_self, InplaceUpdateTupleLock);
1038+
10341039
/* Update owner dependency reference */
10351040
changeDependencyOnOwner(classId, objectId, new_ownerId);
10361041

@@ -1039,6 +1044,8 @@ AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId)
10391044
pfree(nulls);
10401045
pfree(replaces);
10411046
}
1047+
else
1048+
UnlockTuple(rel, &oldtup->t_self, InplaceUpdateTupleLock);
10421049

10431050
/* Note the post-alter hook gets classId not catalogId */
10441051
InvokeObjectPostAlterHook(classId, objectId, 0);

src/include/catalog/objectaddress.h

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

7070
extern HeapTuple get_catalog_object_by_oid(Relation catalog,
7171
AttrNumber oidcol, Oid objectId);
72+
extern HeapTuple get_catalog_object_by_oid_extended(Relation catalog,
73+
AttrNumber oidcol,
74+
Oid objectId,
75+
bool locktup);
7276

7377
extern char *getObjectDescription(const ObjectAddress *object,
7478
bool missing_ok);

src/test/regress/expected/database.out

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

src/test/regress/sql/database.sql

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

17+
CREATE ROLE regress_datdba_before;
18+
CREATE ROLE regress_datdba_after;
19+
ALTER DATABASE regression_utf8 OWNER TO regress_datdba_before;
20+
REASSIGN OWNED BY regress_datdba_before TO regress_datdba_after;
21+
1722
DROP DATABASE regression_utf8;
23+
DROP ROLE regress_datdba_before;
24+
DROP ROLE regress_datdba_after;

0 commit comments

Comments
 (0)