Skip to content

Commit

Permalink
Fix a failure in DROP EXTENSION (#96)
Browse files Browse the repository at this point in the history
When pg_ivm is dropped, the error "could not open relation with OID ..." occurred
at the hook function that enables DROP TABLE on an IMMV to remove the entry in
pg_ivm_immv. It was because that the primary key was already dropped at the time
pg_ivm_immv's toast is been dropped. Also, DROP TABLE command issued concurrently
with DROP EXTENSION pg_Ivm also could cause the same error because pg_ivm_immv
could be already dropped.

This race condition is fixed by using always RangeVarGetRelidExtended to get OID of
pg_ivm_immv instead of using a cache of get_relname_relid results. This makes sure
that pg_ivm_immv exists when this is scanned.
  • Loading branch information
ibhaskar2 authored Oct 21, 2024
1 parent 36d4a47 commit edde972
Showing 1 changed file with 16 additions and 19 deletions.
35 changes: 16 additions & 19 deletions pg_ivm.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include "parser/parser.h"
#include "parser/scansup.h"
#include "tcop/tcopprot.h"
#include "nodes/makefuncs.h"
#include "utils/syscache.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
Expand All @@ -36,8 +38,6 @@

PG_MODULE_MAGIC;

static Oid pg_ivm_immv_id = InvalidOid;
static Oid pg_ivm_immv_pkey_id = InvalidOid;

static object_access_hook_type PrevObjectAccessHook = NULL;

Expand Down Expand Up @@ -326,10 +326,9 @@ CreateChangePreventTrigger(Oid matviewOid)
Oid
PgIvmImmvRelationId(void)
{
if (!OidIsValid(pg_ivm_immv_id))
pg_ivm_immv_id = get_relname_relid("pg_ivm_immv", PG_CATALOG_NAMESPACE);

return pg_ivm_immv_id;
return RangeVarGetRelidExtended(
makeRangeVar("pg_catalog", "pg_ivm_immv", -1),
AccessShareLock, RVR_MISSING_OK, NULL, NULL);
}

/*
Expand All @@ -338,10 +337,9 @@ PgIvmImmvRelationId(void)
Oid
PgIvmImmvPrimaryKeyIndexId(void)
{
if (!OidIsValid(pg_ivm_immv_pkey_id))
pg_ivm_immv_pkey_id = get_relname_relid("pg_ivm_immv_pkey", PG_CATALOG_NAMESPACE);

return pg_ivm_immv_pkey_id;
return RangeVarGetRelidExtended(
makeRangeVar("pg_catalog", "pg_ivm_immv_pkey", -1),
AccessShareLock, RVR_MISSING_OK, NULL, NULL);
}

/*
Expand Down Expand Up @@ -391,24 +389,23 @@ PgIvmObjectAccessHook(ObjectAccessType access, Oid classId,
HeapTuple tup;
Oid pgIvmImmvOid = PgIvmImmvRelationId();

/* pg_ivm_immv is not created yet, so there are no IMMVs, either. */
if (pgIvmImmvOid == InvalidOid)
return;
Oid pgIvmImmvPkOid = PgIvmImmvPrimaryKeyIndexId();

/*
* When the dropped table is pg_ivm_immv, we don't need to continue
* any more. Also, in this case, the index on it is already dropped,
* so the index scan below will fail and raise an error.
* Index or table not yet created (so no IMMVs yet), already dropped
* (expect IMMVs also gone soon), or renamed. It's not great that a
* rename of either object will silently break IMMVs, but that's
* better than ERROR below.
*/
if (objectId == pgIvmImmvOid)
return;
if (pgIvmImmvPkOid == InvalidOid || pgIvmImmvOid == InvalidOid)
return;

pgIvmImmv = table_open(pgIvmImmvOid, AccessShareLock);
ScanKeyInit(&key,
Anum_pg_ivm_immv_immvrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(objectId));
scan = systable_beginscan(pgIvmImmv, PgIvmImmvPrimaryKeyIndexId(),
scan = systable_beginscan(pgIvmImmv, pgIvmImmvPkOid,
true, NULL, 1, &key);

tup = systable_getnext(scan);
Expand Down

0 comments on commit edde972

Please sign in to comment.