]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Use heap_inplace_update() to unset pg_database.dathasloginevt
authorAlexander Korotkov <akorotkov@postgresql.org>
Sun, 11 Feb 2024 22:33:44 +0000 (00:33 +0200)
committerAlexander Korotkov <akorotkov@postgresql.org>
Sun, 11 Feb 2024 22:52:25 +0000 (00:52 +0200)
Doing this instead of regular updates serves two purposes. First, that avoids
possible waiting on the row-level lock.  Second, that avoids dealing with
TOAST.

It's known that changes made by heap_inplace_update() may be lost due to
concurrent normal updates.  However, we are OK with that.  The subsequent
connections will still have a chance to set "dathasloginevt" to false.

Reported-by: Alexander Lakhin
Discussion: https://postgr.es/m/e2a0248e-5f32-af0c-9832-a90d303c2c61%40gmail.com

src/backend/commands/event_trigger.c

index f193c7ddf60ea7b6988bd6e16b5e2823f2fd9054..c8b662131c3a82f0257fcfbc7ea5e450775271ae 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include "postgres.h"
 
+#include "access/heapam.h"
 #include "access/htup_details.h"
 #include "access/table.h"
 #include "access/xact.h"
@@ -943,18 +944,45 @@ EventTriggerOnLogin(void)
                        Relation        pg_db = table_open(DatabaseRelationId, RowExclusiveLock);
                        HeapTuple       tuple;
                        Form_pg_database db;
+                       ScanKeyData key[1];
+                       SysScanDesc scan;
 
-                       tuple = SearchSysCacheCopy1(DATABASEOID,
-                                                                               ObjectIdGetDatum(MyDatabaseId));
+                       /*
+                        * Get the pg_database tuple to scribble on.  Note that this does
+                        * not directly rely on the syscache to avoid issues with
+                        * flattened toast values for the in-place update.
+                        */
+                       ScanKeyInit(&key[0],
+                                               Anum_pg_database_oid,
+                                               BTEqualStrategyNumber, F_OIDEQ,
+                                               ObjectIdGetDatum(MyDatabaseId));
+
+                       scan = systable_beginscan(pg_db, DatabaseOidIndexId, true,
+                                                                         NULL, 1, key);
+                       tuple = systable_getnext(scan);
+                       tuple = heap_copytuple(tuple);
+                       systable_endscan(scan);
 
                        if (!HeapTupleIsValid(tuple))
-                               elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
+                               elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
 
                        db = (Form_pg_database) GETSTRUCT(tuple);
                        if (db->dathasloginevt)
                        {
                                db->dathasloginevt = false;
-                               CatalogTupleUpdate(pg_db, &tuple->t_self, tuple);
+
+                               /*
+                                * Do an "in place" update of the pg_database tuple.  Doing
+                                * this instead of regular updates serves two purposes. First,
+                                * that avoids possible waiting on the row-level lock. Second,
+                                * that avoids dealing with TOAST.
+                                *
+                                * It's known that changes made by heap_inplace_update() may
+                                * be lost due to concurrent normal updates.  However, we are
+                                * OK with that.  The subsequent connections will still have a
+                                * chance to set "dathasloginevt" to false.
+                                */
+                               heap_inplace_update(pg_db, tuple);
                        }
                        table_close(pg_db, RowExclusiveLock);
                        heap_freetuple(tuple);