* ScanPgRelation * * This is used by RelationBuildDesc to find a pg_class * tuple matching targetRelId. The caller must hold at least * AccessShareLock on the target relid to prevent concurrent-update * scenarios; it isn't guaranteed that all scans used to build the * relcache entry will use the same snapshot. If, for example, * an attribute were to be added after scanning pg_class
| 350 | * and must eventually be freed with heap_freetuple. |
| 351 | */ |
| 352 | static HeapTuple |
| 353 | ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic) |
| 354 | { |
| 355 | HeapTuple pg_class_tuple; |
| 356 | Relation pg_class_desc; |
| 357 | SysScanDesc pg_class_scan; |
| 358 | ScanKeyData key[1]; |
| 359 | Snapshot snapshot = NULL; |
| 360 | |
| 361 | /* |
| 362 | * If something goes wrong during backend startup, we might find ourselves |
| 363 | * trying to read pg_class before we've selected a database. That ain't |
| 364 | * gonna work, so bail out with a useful error message. If this happens, |
| 365 | * it probably means a relcache entry that needs to be nailed isn't. |
| 366 | */ |
| 367 | if (!OidIsValid(MyDatabaseId)) |
| 368 | elog(FATAL, "cannot read pg_class without having selected a database"); |
| 369 | |
| 370 | /* |
| 371 | * form a scan key |
| 372 | */ |
| 373 | ScanKeyInit(&key[0], |
| 374 | Anum_pg_class_oid, |
| 375 | BTEqualStrategyNumber, F_OIDEQ, |
| 376 | ObjectIdGetDatum(targetRelId)); |
| 377 | |
| 378 | /* |
| 379 | * Open pg_class and fetch a tuple. Force heap scan if we haven't yet |
| 380 | * built the critical relcache entries (this includes initdb and startup |
| 381 | * without a pg_internal.init file). The caller can also force a heap |
| 382 | * scan by setting indexOK == false. |
| 383 | */ |
| 384 | pg_class_desc = table_open(RelationRelationId, AccessShareLock); |
| 385 | |
| 386 | /* |
| 387 | * The caller might need a tuple that's newer than the one the historic |
| 388 | * snapshot; currently the only case requiring to do so is looking up the |
| 389 | * relfilenode of non mapped system relations during decoding. That |
| 390 | * snapshot can't change in the midst of a relcache build, so there's no |
| 391 | * need to register the snapshot. |
| 392 | */ |
| 393 | if (force_non_historic) |
| 394 | snapshot = GetNonHistoricCatalogSnapshot( |
| 395 | RelationRelationId, |
| 396 | DistributedTransactionContext); |
| 397 | |
| 398 | pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId, |
| 399 | indexOK && criticalRelcachesBuilt, |
| 400 | snapshot, |
| 401 | 1, key); |
| 402 | |
| 403 | pg_class_tuple = systable_getnext(pg_class_scan); |
| 404 | |
| 405 | /* |
| 406 | * Must copy tuple before releasing buffer. |
| 407 | */ |
| 408 | if (HeapTupleIsValid(pg_class_tuple)) |
| 409 | pg_class_tuple = heap_copytuple(pg_class_tuple); |
no test coverage detected