/* * get_domain_constraint_oid * Find a constraint on the specified domain with the specified name. * Returns constraint's OID. */ Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok) { Relation pg_constraint; HeapTuple tuple; SysScanDesc scan; ScanKeyData skey[1]; Oid conOid = InvalidOid; /* * Fetch the constraint tuple from pg_constraint. There may be more than * one match, because constraints are not required to have unique names; * if so, error out. */ pg_constraint = heap_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&skey[0], Anum_pg_constraint_contypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(typid)); scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true, NULL, 1, skey); while (HeapTupleIsValid(tuple = systable_getnext(scan))) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); if (strcmp(NameStr(con->conname), conname) == 0) { if (OidIsValid(conOid)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("domain \"%s\" has multiple constraints named \"%s\"", format_type_be(typid), conname))); conOid = HeapTupleGetOid(tuple); } } systable_endscan(scan); /* If no such constraint exists, complain */ if (!OidIsValid(conOid) && !missing_ok) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("constraint \"%s\" for domain \"%s\" does not exist", conname, format_type_be(typid)))); heap_close(pg_constraint, AccessShareLock); return conOid; }
/* * get_constraint_index * Given the OID of a unique or primary-key constraint, return the * OID of the underlying unique index. * * Return InvalidOid if the index couldn't be found; this suggests the * given OID is bogus, but we leave it to caller to decide what to do. */ Oid get_constraint_index(Oid constraintId) { Oid indexId = InvalidOid; Relation depRel; ScanKeyData key[3]; SysScanDesc scan; HeapTuple tup; /* Search the dependency table for the dependent index */ depRel = heap_open(DependRelationId, AccessShareLock); ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ConstraintRelationId)); ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(constraintId)); ScanKeyInit(&key[2], Anum_pg_depend_refobjsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(0)); scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, 3, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); /* * We assume any internal dependency of an index on the constraint * must be what we are looking for. (The relkind test is just * paranoia; there shouldn't be any such dependencies otherwise.) */ if (deprec->classid == RelationRelationId && deprec->objsubid == 0 && deprec->deptype == DEPENDENCY_INTERNAL && get_rel_relkind(deprec->objid) == RELKIND_INDEX) { indexId = deprec->objid; break; } } systable_endscan(scan); heap_close(depRel, AccessShareLock); return indexId; }
/* * TableReferencing function checks whether given table is referencing by another table * via foreign constraints. If it is referencing, this function returns true. To check * that, this function searches given relation at pg_constraints system catalog. However * since there is no index for the column we searched, this function performs sequential * search, therefore call this function with caution. */ bool TableReferencing(Oid relationId) { Relation pgConstraint = NULL; HeapTuple heapTuple = NULL; SysScanDesc scanDescriptor = NULL; ScanKeyData scanKey[1]; int scanKeyCount = 1; Oid scanIndexId = InvalidOid; bool useIndex = false; pgConstraint = heap_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&scanKey[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, relationId); scanDescriptor = systable_beginscan(pgConstraint, scanIndexId, useIndex, NULL, scanKeyCount, scanKey); heapTuple = systable_getnext(scanDescriptor); while (HeapTupleIsValid(heapTuple)) { Form_pg_constraint constraintForm = (Form_pg_constraint) GETSTRUCT(heapTuple); if (constraintForm->contype == CONSTRAINT_FOREIGN) { systable_endscan(scanDescriptor); heap_close(pgConstraint, NoLock); return true; } heapTuple = systable_getnext(scanDescriptor); } systable_endscan(scanDescriptor); heap_close(pgConstraint, NoLock); return false; }
/* * GetComment -- get the comment for an object, or null if not found. */ char * GetComment(Oid oid, Oid classoid, int32 subid) { Relation description; ScanKeyData skey[3]; SysScanDesc sd; TupleDesc tupdesc; HeapTuple tuple; char *comment; /* Use the index to search for a matching old tuple */ ScanKeyInit(&skey[0], Anum_pg_description_objoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(oid)); ScanKeyInit(&skey[1], Anum_pg_description_classoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classoid)); ScanKeyInit(&skey[2], Anum_pg_description_objsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(subid)); description = heap_open(DescriptionRelationId, AccessShareLock); tupdesc = RelationGetDescr(description); sd = systable_beginscan(description, DescriptionObjIndexId, true, SnapshotNow, 3, skey); comment = NULL; while ((tuple = systable_getnext(sd)) != NULL) { Datum value; bool isnull; /* Found the tuple, get description field */ value = heap_getattr(tuple, Anum_pg_description_description, tupdesc, &isnull); if (!isnull) comment = TextDatumGetCString(value); break; /* Assume there can be only one match */ } systable_endscan(sd); /* Done */ heap_close(description, AccessShareLock); return comment; }
/* * ConstraintIsAForeignKeyToReferenceTable function scans the pgConstraint to * fetch all of the constraints on the given relationId and see if at least one * of them is a foreign key referencing to a reference table. */ bool ConstraintIsAForeignKeyToReferenceTable(char *constraintName, Oid relationId) { Relation pgConstraint = NULL; SysScanDesc scanDescriptor = NULL; ScanKeyData scanKey[1]; int scanKeyCount = 1; HeapTuple heapTuple = NULL; bool foreignKeyToReferenceTable = false; pgConstraint = heap_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&scanKey[0], Anum_pg_constraint_contype, BTEqualStrategyNumber, F_CHAREQ, CharGetDatum(CONSTRAINT_FOREIGN)); scanDescriptor = systable_beginscan(pgConstraint, InvalidOid, false, NULL, scanKeyCount, scanKey); heapTuple = systable_getnext(scanDescriptor); while (HeapTupleIsValid(heapTuple)) { Oid referencedTableId = InvalidOid; Form_pg_constraint constraintForm = (Form_pg_constraint) GETSTRUCT(heapTuple); char *constraintName = (constraintForm->conname).data; if (strncmp(constraintName, constraintName, NAMEDATALEN) != 0 || constraintForm->conrelid != relationId) { heapTuple = systable_getnext(scanDescriptor); continue; } referencedTableId = constraintForm->confrelid; Assert(IsDistributedTable(referencedTableId)); if (PartitionMethod(referencedTableId) == DISTRIBUTE_BY_NONE) { foreignKeyToReferenceTable = true; break; } heapTuple = systable_getnext(scanDescriptor); } /* clean up scan and close system catalog */ systable_endscan(scanDescriptor); heap_close(pgConstraint, AccessShareLock); return foreignKeyToReferenceTable; }
/* * GetSegFilesTotals * * Get the total bytes and tuples for a specific parquet table * from the pg_aoseg table on this local segdb. */ ParquetFileSegTotals *GetParquetSegFilesTotals(Relation parentrel, Snapshot parquetMetaDataSnapshot) { Relation pg_paqseg_rel; TupleDesc pg_paqseg_dsc; HeapTuple tuple; SysScanDesc paqscan; ParquetFileSegTotals *result; Datum eof, eof_uncompressed, tupcount; bool isNull; AppendOnlyEntry *aoEntry = NULL; Assert(RelationIsParquet(parentrel)); aoEntry = GetAppendOnlyEntry(RelationGetRelid(parentrel), parquetMetaDataSnapshot); result = (ParquetFileSegTotals *) palloc0(sizeof(ParquetFileSegTotals)); pg_paqseg_rel = heap_open(aoEntry->segrelid, AccessShareLock); pg_paqseg_dsc = RelationGetDescr(pg_paqseg_rel); paqscan = systable_beginscan(pg_paqseg_rel, InvalidOid, FALSE, parquetMetaDataSnapshot, 0, NULL); while (HeapTupleIsValid(tuple = systable_getnext(paqscan))) { eof = fastgetattr(tuple, Anum_pg_parquetseg_eof, pg_paqseg_dsc, &isNull); tupcount = fastgetattr(tuple, Anum_pg_parquetseg_tupcount, pg_paqseg_dsc, &isNull); eof_uncompressed = fastgetattr(tuple, Anum_pg_parquetseg_eofuncompressed, pg_paqseg_dsc, &isNull); if(isNull) result->totalbytesuncompressed = InvalidUncompressedEof; else result->totalbytesuncompressed += (int64)DatumGetFloat8(eof_uncompressed); result->totalbytes += (int64)DatumGetFloat8(eof); result->totaltuples += (int64)DatumGetFloat8(tupcount); result->totalfilesegs++; CHECK_FOR_INTERRUPTS(); } systable_endscan(paqscan); heap_close(pg_paqseg_rel, AccessShareLock); pfree(aoEntry); return result; }
/* * get_index_constraint * Given the OID of an index, return the OID of the owning unique or * primary-key constraint, or InvalidOid if no such constraint. */ Oid get_index_constraint(Oid indexId) { Oid constraintId = InvalidOid; Relation depRel; ScanKeyData key[3]; SysScanDesc scan; HeapTuple tup; /* Search the dependency table for the index */ depRel = heap_open(DependRelationId, AccessShareLock); ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationRelationId)); ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(indexId)); ScanKeyInit(&key[2], Anum_pg_depend_objsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(0)); scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 3, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); /* * We assume any internal dependency on a constraint must be what we * are looking for. */ if (deprec->refclassid == ConstraintRelationId && deprec->refobjsubid == 0 && deprec->deptype == DEPENDENCY_INTERNAL) { constraintId = deprec->refobjid; break; } } systable_endscan(scan); heap_close(depRel, AccessShareLock); return constraintId; }
/* * InsertFastSequenceEntry * * Insert a new fast sequence entry for a given object. If the given * object already exists in the table, this function replaces the old * entry with a fresh initial value. */ void InsertFastSequenceEntry(Oid objid, int64 objmod, int64 lastSequence) { Relation gp_fastsequence_rel; ScanKeyData scankey[2]; SysScanDesc scan; TupleDesc tupleDesc; HeapTuple tuple = NULL; /* * Open and lock the gp_fastsequence catalog table. */ gp_fastsequence_rel = heap_open(FastSequenceRelationId, RowExclusiveLock); tupleDesc = RelationGetDescr(gp_fastsequence_rel); /* SELECT * FROM gp_fastsequence WHERE objid = :1 AND objmod = :2 FOR UPDATE */ ScanKeyInit(&scankey[0], Anum_gp_fastsequence_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objid)); ScanKeyInit(&scankey[1], Anum_gp_fastsequence_objmod, BTEqualStrategyNumber, F_INT8EQ, Int64GetDatum(objmod)); scan = systable_beginscan(gp_fastsequence_rel, FastSequenceObjidObjmodIndexId, true, SnapshotNow, 2, scankey); tuple = systable_getnext(scan); insert_or_update_fastsequence(gp_fastsequence_rel, tuple, tupleDesc, objid, objmod, lastSequence); systable_endscan(scan); /* * gp_fastsequence table locking for AO inserts uses bottom up approach * meaning the locks are first acquired on the segments and later on the * master. * Hence, it is essential that we release the lock here to avoid * any form of master-segment resource deadlock. E.g. A transaction * trying to reindex gp_fastsequence has acquired a lock on it on the * master but is blocked on the segment as another transaction which * is an insert operation has acquired a lock first on segment and is * trying to acquire a lock on the Master. Deadlock! */ heap_close(gp_fastsequence_rel, RowExclusiveLock); }
/* * HasForeignKeyToReferenceTable function scans the pgConstraint table to * fetch all of the constraints on the given relationId and see if at least one * of them is a foreign key referencing to a reference table. */ bool HasForeignKeyToReferenceTable(Oid relationId) { Relation pgConstraint = NULL; SysScanDesc scanDescriptor = NULL; ScanKeyData scanKey[1]; int scanKeyCount = 1; HeapTuple heapTuple = NULL; bool hasForeignKeyToReferenceTable = false; pgConstraint = heap_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&scanKey[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, relationId); scanDescriptor = systable_beginscan(pgConstraint, ConstraintRelidIndexId, true, NULL, scanKeyCount, scanKey); heapTuple = systable_getnext(scanDescriptor); while (HeapTupleIsValid(heapTuple)) { Oid referencedTableId = InvalidOid; Form_pg_constraint constraintForm = (Form_pg_constraint) GETSTRUCT(heapTuple); if (constraintForm->contype != CONSTRAINT_FOREIGN) { heapTuple = systable_getnext(scanDescriptor); continue; } referencedTableId = constraintForm->confrelid; if (!IsDistributedTable(referencedTableId)) { continue; } if (PartitionMethod(referencedTableId) == DISTRIBUTE_BY_NONE) { hasForeignKeyToReferenceTable = true; break; } heapTuple = systable_getnext(scanDescriptor); } /* clean up scan and close system catalog */ systable_endscan(scanDescriptor); heap_close(pgConstraint, NoLock); return hasForeignKeyToReferenceTable; }
/* * Collect a list of OIDs of all sequences owned by the specified relation. */ List * getOwnedSequences(Oid relid) { List *result = NIL; Relation depRel; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; depRel = heap_open(DependRelationId, AccessShareLock); ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationRelationId)); ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, 2, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); /* * We assume any auto dependency of a sequence on a column must be * what we are looking for. (We need the relkind test because indexes * can also have auto dependencies on columns.) */ if (deprec->classid == RelationRelationId && deprec->objsubid == 0 && deprec->refobjsubid != 0 && deprec->deptype == DEPENDENCY_AUTO && get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE) { result = lappend_oid(result, deprec->objid); } } systable_endscan(scan); heap_close(depRel, AccessShareLock); return result; }
/* * Test whether given name is currently used as a constraint name * for the given object (relation or domain). * * This is used to decide whether to accept a user-specified constraint name. * It is deliberately not the same test as ChooseConstraintName uses to decide * whether an auto-generated name is OK: here, we will allow it unless there * is an identical constraint name in use *on the same object*. * * NB: Caller should hold exclusive lock on the given object, else * this test can be fooled by concurrent additions. */ bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, Oid objNamespace, const char *conname) { bool found; Relation conDesc; SysScanDesc conscan; ScanKeyData skey[2]; HeapTuple tup; conDesc = heap_open(ConstraintRelationId, AccessShareLock); found = false; ScanKeyInit(&skey[0], Anum_pg_constraint_conname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(conname)); ScanKeyInit(&skey[1], Anum_pg_constraint_connamespace, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objNamespace)); conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true, NULL, 2, skey); while (HeapTupleIsValid(tup = systable_getnext(conscan))) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup); if (conCat == CONSTRAINT_RELATION && con->conrelid == objId) { found = true; break; } else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId) { found = true; break; } } systable_endscan(conscan); heap_close(conDesc, AccessShareLock); return found; }
/* * pg_get_sequencedef_string returns the definition of a given sequence. This * definition includes explicit values for all CREATE SEQUENCE options. */ char * pg_get_sequencedef_string(Oid sequenceRelationId) { char *qualifiedSequenceName = NULL; char *sequenceDef = NULL; Form_pg_sequence pgSequenceForm = NULL; Relation sequenceRel = NULL; AclResult permissionCheck = ACLCHECK_NO_PRIV; SysScanDesc scanDescriptor = NULL; HeapTuple heapTuple = NULL; /* open and lock sequence */ sequenceRel = heap_open(sequenceRelationId, AccessShareLock); /* check permissions to read sequence attributes */ permissionCheck = pg_class_aclcheck(sequenceRelationId, GetUserId(), ACL_SELECT | ACL_USAGE); if (permissionCheck != ACLCHECK_OK) { ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", RelationGetRelationName(sequenceRel)))); } /* retrieve attributes from first tuple */ scanDescriptor = systable_beginscan(sequenceRel, InvalidOid, false, NULL, 0, NULL); heapTuple = systable_getnext(scanDescriptor); if (!HeapTupleIsValid(heapTuple)) { ereport(ERROR, (errmsg("could not find specified sequence"))); } pgSequenceForm = (Form_pg_sequence) GETSTRUCT(heapTuple); /* build our DDL command */ qualifiedSequenceName = generate_relation_name(sequenceRelationId, NIL); sequenceDef = psprintf(CREATE_SEQUENCE_COMMAND, qualifiedSequenceName, pgSequenceForm->increment_by, pgSequenceForm->min_value, pgSequenceForm->max_value, pgSequenceForm->cache_value, pgSequenceForm->is_cycled ? "" : "NO "); systable_endscan(scanDescriptor); heap_close(sequenceRel, AccessShareLock); return sequenceDef; }
/* --------------------- * lookupProcCallback() - Find a specified callback for a specified function * * Parameters: * profnoid - oid of the function that has a callback * promethod - which callback to find * --------------------- */ Oid lookupProcCallback(Oid profnoid, char promethod) { Relation rel; ScanKeyData skey[2]; SysScanDesc scan; HeapTuple tup; Oid result; Insist(OidIsValid(profnoid)); /* open pg_proc_callback */ rel = heap_open(ProcCallbackRelationId, AccessShareLock); /* Lookup (profnoid, promethod) from index */ /* (profnoid, promethod) is guaranteed unique by the index */ ScanKeyInit(&skey[0], Anum_pg_proc_callback_profnoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(profnoid)); ScanKeyInit(&skey[1], Anum_pg_proc_callback_promethod, BTEqualStrategyNumber, F_CHAREQ, CharGetDatum(promethod)); scan = systable_beginscan(rel, ProcCallbackProfnoidPromethodIndexId, true, SnapshotNow, 2, skey); tup = systable_getnext(scan); if (HeapTupleIsValid(tup)) { Datum d; bool isnull; d = heap_getattr(tup, Anum_pg_proc_callback_procallback, RelationGetDescr(rel), &isnull); Assert(!isnull); result = DatumGetObjectId(d); } else result = InvalidOid; systable_endscan(scan); heap_close(rel, AccessShareLock); return result; }
/* * Get all relations for subscription that are not in a ready state. * * Returned list is palloc'ed in current memory context. */ List * GetSubscriptionNotReadyRelations(Oid subid) { List *res = NIL; Relation rel; HeapTuple tup; int nkeys = 0; ScanKeyData skey[2]; SysScanDesc scan; rel = table_open(SubscriptionRelRelationId, AccessShareLock); ScanKeyInit(&skey[nkeys++], Anum_pg_subscription_rel_srsubid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(subid)); ScanKeyInit(&skey[nkeys++], Anum_pg_subscription_rel_srsubstate, BTEqualStrategyNumber, F_CHARNE, CharGetDatum(SUBREL_STATE_READY)); scan = systable_beginscan(rel, InvalidOid, false, NULL, nkeys, skey); while (HeapTupleIsValid(tup = systable_getnext(scan))) { Form_pg_subscription_rel subrel; SubscriptionRelState *relstate; subrel = (Form_pg_subscription_rel) GETSTRUCT(tup); relstate = (SubscriptionRelState *) palloc(sizeof(SubscriptionRelState)); relstate->relid = subrel->srrelid; relstate->state = subrel->srsubstate; relstate->lsn = subrel->srsublsn; res = lappend(res, relstate); } /* Cleanup */ systable_endscan(scan); table_close(rel, AccessShareLock); return res; }
/* * DeleteComments -- remove comments for an object * * If subid is nonzero then only comments matching it will be removed. * If subid is zero, all comments matching the oid/classoid will be removed * (this corresponds to deleting a whole object). */ void DeleteComments(Oid oid, Oid classoid, int32 subid) { Relation description; ScanKeyData skey[3]; int nkeys; SysScanDesc sd; HeapTuple oldtuple; /* Use the index to search for all matching old tuples */ ScanKeyInit(&skey[0], Anum_pg_description_objoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(oid)); ScanKeyInit(&skey[1], Anum_pg_description_classoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classoid)); if (subid != 0) { ScanKeyInit(&skey[2], Anum_pg_description_objsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(subid)); nkeys = 3; } else nkeys = 2; description = heap_open(DescriptionRelationId, RowExclusiveLock); sd = systable_beginscan(description, DescriptionObjIndexId, true, SnapshotNow, nkeys, skey); while ((oldtuple = systable_getnext(sd)) != NULL) simple_heap_delete(description, &oldtuple->t_self); /* Done */ systable_endscan(sd); heap_close(description, RowExclusiveLock); }
/* * Detect whether a sequence is marked as "owned" by a column * * An ownership marker is an AUTO dependency from the sequence to the * column. If we find one, store the identity of the owning column * into *tableId and *colId and return TRUE; else return FALSE. * * Note: if there's more than one such pg_depend entry then you get * a random one of them returned into the out parameters. This should * not happen, though. */ bool sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId) { bool ret = false; Relation depRel; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; depRel = heap_open(DependRelationId, AccessShareLock); ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationRelationId)); ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(seqId)); scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key); while (HeapTupleIsValid((tup = systable_getnext(scan)))) { Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); if (depform->refclassid == RelationRelationId && depform->deptype == DEPENDENCY_AUTO) { *tableId = depform->refobjid; *colId = depform->refobjsubid; ret = true; break; /* no need to keep scanning */ } } systable_endscan(scan); heap_close(depRel, AccessShareLock); return ret; }
/* * Scan pg_db_role_setting looking for applicable settings, and load them on * the current process. * * relsetting is pg_db_role_setting, already opened and locked. * * Note: we only consider setting for the exact databaseid/roleid combination. * This probably needs to be called more than once, with InvalidOid passed as * databaseid/roleid. */ void ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid, Relation relsetting, GucSource source) { SysScanDesc scan; ScanKeyData keys[2]; HeapTuple tup; ScanKeyInit(&keys[0], Anum_pg_db_role_setting_setdatabase, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(databaseid)); ScanKeyInit(&keys[1], Anum_pg_db_role_setting_setrole, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(roleid)); scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true, snapshot, 2, keys); while (HeapTupleIsValid(tup = systable_getnext(scan))) { bool isnull; Datum datum; datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig, RelationGetDescr(relsetting), &isnull); if (!isnull) { ArrayType *a = DatumGetArrayTypeP(datum); /* * We process all the options at SUSET level. We assume that the * right to insert an option into pg_db_role_setting was checked * when it was inserted. */ ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET); } } systable_endscan(scan); }
/* * GetDatabaseTuple -- fetch the pg_database row for a database * * This is used during backend startup when we don't yet have any access to * system catalogs in general. In the worst case, we can seqscan pg_database * using nothing but the hard-wired descriptor that relcache.c creates for * pg_database. In more typical cases, relcache.c was able to load * descriptors for both pg_database and its indexes from the shared relcache * cache file, and so we can do an indexscan. criticalSharedRelcachesBuilt * tells whether we got the cached descriptors. */ static struct heap_tuple* GetDatabaseTuple(const char *dbname) { struct heap_tuple *tuple; struct relation *relation; struct sys_scan *scan; struct scankey key[1]; /* * form a scan key */ scankey_init(&key[0], Anum_pg_database_datname, BT_EQ_STRAT_NR, F_NAMEEQ, CSTRING_TO_D(dbname)); /* * Open pg_database and fetch a tuple. Force heap scan if we haven't yet * built the critical shared relcache entries (i.e., we're starting up * without a shared relcache cache file). */ relation = heap_open(DatabaseRelationId, ACCESS_SHR_LOCK); scan = systable_beginscan( relation, DatabaseNameIndexId, criticalSharedRelcachesBuilt, snap_now, 1, key); tuple = systable_getnext(scan); /* Must copy tuple before releasing buffer */ if (HT_VALID(tuple)) tuple = heap_dup_tuple(tuple); /* all done */ systable_endscan(scan); heap_close(relation, ACCESS_SHR_LOCK); return tuple; }
/* * GetParquetTotalBytes * * Get the total bytes for a specific parquet table from the pg_aoseg table on master. * * In hawq, master keep all segfile info in pg_aoseg table, * therefore it get the whole table size. */ int64 GetParquetTotalBytes(Relation parentrel, Snapshot parquetMetaDataSnapshot) { Relation pg_paqseg_rel; TupleDesc pg_paqseg_dsc; HeapTuple tuple; SysScanDesc parquetscan; int64 result; Datum eof; bool isNull; AppendOnlyEntry *aoEntry = NULL; aoEntry = GetAppendOnlyEntry(RelationGetRelid(parentrel), parquetMetaDataSnapshot); result = 0; pg_paqseg_rel = heap_open(aoEntry->segrelid, AccessShareLock); pg_paqseg_dsc = RelationGetDescr(pg_paqseg_rel); Assert (Gp_role != GP_ROLE_EXECUTE); parquetscan = systable_beginscan(pg_paqseg_rel, InvalidOid, FALSE, parquetMetaDataSnapshot, 0, NULL); while (HeapTupleIsValid(tuple = systable_getnext(parquetscan))) { eof = fastgetattr(tuple, Anum_pg_parquetseg_eof, pg_paqseg_dsc, &isNull); Assert(!isNull); result += (int64)DatumGetFloat8(eof); CHECK_FOR_INTERRUPTS(); } systable_endscan(parquetscan); heap_close(pg_paqseg_rel, AccessShareLock); pfree(aoEntry); return result; }
/* * deleteDependencyRecordsForClass -- delete all records with given depender * classId/objectId, dependee classId, and deptype. * Returns the number of records deleted. * * This is a variant of deleteDependencyRecordsFor, useful when revoking * an object property that is expressed by a dependency record (such as * extension membership). */ long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype) { long count = 0; Relation depRel; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; depRel = heap_open(DependRelationId, RowExclusiveLock); ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId)); ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId)); scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); if (depform->refclassid == refclassId && depform->deptype == deptype) { simple_heap_delete(depRel, &tup->t_self); count++; } } systable_endscan(scan); heap_close(depRel, RowExclusiveLock); return count; }
/* * Find the extension containing the specified object, if any * * Returns the OID of the extension, or InvalidOid if the object does not * belong to any extension. * * Extension membership is marked by an EXTENSION dependency from the object * to the extension. Note that the result will be indeterminate if pg_depend * contains links from this object to more than one extension ... but that * should never happen. */ Oid getExtensionOfObject(Oid classId, Oid objectId) { Oid result = InvalidOid; Relation depRel; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; depRel = heap_open(DependRelationId, AccessShareLock); ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId)); ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId)); scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key); while (HeapTupleIsValid((tup = systable_getnext(scan)))) { Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); if (depform->refclassid == ExtensionRelationId && depform->deptype == DEPENDENCY_EXTENSION) { result = depform->refobjid; break; /* no need to keep scanning */ } } systable_endscan(scan); heap_close(depRel, AccessShareLock); return result; }
/* * Same as pg_largeobject.c's large_obj_exists(), except snapshot to * read with can be specified. */ static bool mylo_exists(oid_t loid, struct snap* snapshot) { struct relation* pg_lo_meta; struct scankey skey[1]; struct sys_scan* sd; struct heap_tuple* tuple; bool retval = false; scankey_init(&skey[0], OID_ATTR_NR, BT_EQ_STRAT_NR, F_OIDEQ, OID_TO_D(loid)); pg_lo_meta = heap_open(LargeObjectMetadataRelationId, ACCESS_SHR_LOCK); sd = systable_beginscan(pg_lo_meta, LO_METADATA_OID_INDEX_ID, true, snapshot, 1, skey); tuple = systable_getnext(sd); if (HT_VALID(tuple)) retval = true; systable_endscan(sd); heap_close(pg_lo_meta, ACCESS_SHR_LOCK); return retval; }
/* * deleteDependencyRecordsFor -- delete all records with given depender * classId/objectId. Returns the number of records deleted. * * This is used when redefining an existing object. Links leading to the * object do not change, and links leading from it will be recreated * (possibly with some differences from before). * * If skipExtensionDeps is true, we do not delete any dependencies that * show that the given object is a member of an extension. This avoids * needing a lot of extra logic to fetch and recreate that dependency. */ long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps) { long count = 0; Relation depRel; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; depRel = heap_open(DependRelationId, RowExclusiveLock); ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId)); ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId)); scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { if (skipExtensionDeps && ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION) continue; simple_heap_delete(depRel, &tup->t_self); count++; } systable_endscan(scan); heap_close(depRel, RowExclusiveLock); return count; }
/* * isObjectPinned() * * Test if an object is required for basic database functionality. * Caller must already have opened pg_depend. * * The passed subId, if any, is ignored; we assume that only whole objects * are pinned (and that this implies pinning their components). */ static bool isObjectPinned(const ObjectAddress *object, Relation rel) { bool ret = false; SysScanDesc scan; HeapTuple tup; ScanKeyData key[2]; ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->classId)); ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId)); scan = systable_beginscan(rel, DependReferenceIndexId, true, NULL, 2, key); /* * Since we won't generate additional pg_depend entries for pinned * objects, there can be at most one entry referencing a pinned object. * Hence, it's sufficient to look at the first returned tuple; we don't * need to loop. */ tup = systable_getnext(scan); if (HeapTupleIsValid(tup)) { Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup); if (foundDep->deptype == DEPENDENCY_PIN) ret = true; } systable_endscan(scan); return ret; }
/* * IsChildTable returns true if the table is inherited. Note that * partition tables inherites by default. However, this function * returns false if the given table is a partition. */ bool IsChildTable(Oid relationId) { Relation pgInherits = NULL; SysScanDesc scan = NULL; ScanKeyData key[1]; HeapTuple inheritsTuple = NULL; bool tableInherits = false; pgInherits = heap_open(InheritsRelationId, AccessShareLock); ScanKeyInit(&key[0], Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relationId)); scan = systable_beginscan(pgInherits, InvalidOid, false, NULL, 1, key); while ((inheritsTuple = systable_getnext(scan)) != NULL) { Oid inheritedRelationId = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid; if (relationId == inheritedRelationId) { tableInherits = true; break; } } systable_endscan(scan); heap_close(pgInherits, AccessShareLock); if (tableInherits && PartitionTable(relationId)) { tableInherits = false; } return tableInherits; }
/* * GetRoleTupleByOid -- as above, but search by role OID */ static HeapTuple GetRoleTupleByName(const char * rolename) { HeapTuple tuple; Relation relation; SysScanDesc scan; ScanKeyData key[1]; /* * form a scan key */ ScanKeyInit(&key[0], Anum_pg_authid_rolname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(rolename)); /* * Open pg_authid and fetch a tuple. Force heap scan if we haven't yet * built the critical shared relcache entries (i.e., we're starting up * without a shared relcache cache file). */ relation = heap_open(AuthIdRelationId, AccessShareLock); scan = systable_beginscan(relation, AuthIdRolnameIndexId, criticalSharedRelcachesBuilt, SNAPSHOT, 1, key); tuple = systable_getnext(scan); /* Must copy tuple before releasing buffer */ if (HeapTupleIsValid(tuple)) tuple = heap_copytuple(tuple); /* all done */ systable_endscan(scan); heap_close(relation, AccessShareLock); return tuple; }
/* * GetDatabaseTupleByOid -- as above, but search by database OID */ static HeapTuple GetDatabaseTupleByOid(Oid dboid) { HeapTuple tuple; Relation relation; SysScanDesc scan; ScanKeyData key[1]; /* * form a scan key */ ScanKeyInit(&key[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(dboid)); /* * Open pg_database and fetch a tuple. Force heap scan if we haven't yet * built the critical shared relcache entries (i.e., we're starting up * without a shared relcache cache file). */ relation = heap_open(DatabaseRelationId, AccessShareLock); scan = systable_beginscan(relation, DatabaseOidIndexId, criticalSharedRelcachesBuilt, NULL, 1, key); tuple = systable_getnext(scan); /* Must copy tuple before releasing buffer */ if (HeapTupleIsValid(tuple)) tuple = heap_copytuple(tuple); /* all done */ systable_endscan(scan); heap_close(relation, AccessShareLock); return tuple; }
/* * GetNewOidWithIndex * Guts of GetNewOid: use the supplied index * * This is exported separately because there are cases where we want to use * an index that will not be recognized by RelationGetOidIndex: TOAST tables * have indexes that are usable, but have multiple columns and are on * ordinary columns rather than a true OID column. This code will work * anyway, so long as the OID is the index's first column. The caller must * pass in the actual heap attnum of the OID column, however. * * Caller must have a suitable lock on the relation. */ Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn) { Oid newOid; SysScanDesc scan; ScanKeyData key; bool collides; /* * We should never be asked to generate a new pg_type OID during * pg_upgrade; doing so would risk collisions with the OIDs it wants to * assign. Hitting this assert means there's some path where we failed to * ensure that a type OID is determined by commands in the dump script. */ Assert(!IsBinaryUpgrade || RelationGetRelid(relation) != TypeRelationId); /* Generate new OIDs until we find one not in the table */ do { CHECK_FOR_INTERRUPTS(); newOid = GetNewObjectId(); ScanKeyInit(&key, oidcolumn, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(newOid)); /* see notes above about using SnapshotAny */ scan = systable_beginscan(relation, indexId, true, SnapshotAny, 1, &key); collides = HeapTupleIsValid(systable_getnext(scan)); systable_endscan(scan); } while (collides); return newOid; }
/* * RemoveExtTableEntry * * Remove an external table entry from pg_exttable. Caller's * responsibility to ensure that the relation has such an entry. */ void RemoveExtTableEntry(Oid relid) { Relation pg_exttable_rel; ScanKeyData skey; SysScanDesc scan; HeapTuple tuple; /* * now remove the pg_exttable entry */ pg_exttable_rel = heap_open(ExtTableRelationId, RowExclusiveLock); ScanKeyInit(&skey, Anum_pg_exttable_reloid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); scan = systable_beginscan(pg_exttable_rel, ExtTableReloidIndexId, true, SnapshotNow, 1, &skey); tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("external table object id \"%d\" does not exist", relid))); /* * Delete the external table entry from the catalog (pg_exttable). */ while (HeapTupleIsValid(tuple = systable_getnext(scan))) simple_heap_delete(pg_exttable_rel, &tuple->t_self); /* Finish up scan and close exttable catalog. */ systable_endscan(scan); heap_close(pg_exttable_rel, NoLock); }
/* MPP-6923: * GetResourceTypeByName: find the named resource in pg_resourcetype * * Input: name of resource * Output: resourcetypid (int2), oid of entry * * updates output and returns true if named resource found * */ static bool GetResourceTypeByName(char *pNameIn, int *pTypeOut, Oid *pOidOut) { Relation pg_resourcetype; ScanKeyData scankey; SysScanDesc sscan; HeapTuple tuple; bool bStat = false; /* * SELECT * FROM pg_resourcetype WHERE resname = :1 FOR UPDATE * * XXX XXX: maybe should be share lock, ie remove FOR UPDATE ? * XXX XXX: only one */ pg_resourcetype = heap_open(ResourceTypeRelationId, RowExclusiveLock); ScanKeyInit(&scankey, Anum_pg_resourcetype_resname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(pNameIn)); sscan = systable_beginscan(pg_resourcetype, ResourceTypeResnameIndexId, true, SnapshotNow, 1, &scankey); tuple = systable_getnext(sscan); if (HeapTupleIsValid(tuple)) { *pOidOut = HeapTupleGetOid(tuple); *pTypeOut = ((Form_pg_resourcetype) GETSTRUCT(tuple))->restypid; bStat = true; } systable_endscan(sscan); heap_close(pg_resourcetype, RowExclusiveLock); return (bStat); } /* end GetResourceTypeByName */