/* * 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; }
/* * 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; }
/* * 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); }
/* * 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); }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * ConstraintIsAForeignKey returns true if the given constraint name * is a foreign key to defined on the relation. */ bool ConstraintIsAForeignKey(char *constraintNameInput, Oid relationId) { Relation pgConstraint = NULL; SysScanDesc scanDescriptor = NULL; ScanKeyData scanKey[1]; int scanKeyCount = 1; HeapTuple heapTuple = NULL; 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)) { Form_pg_constraint constraintForm = (Form_pg_constraint) GETSTRUCT(heapTuple); char *constraintName = (constraintForm->conname).data; if (strncmp(constraintName, constraintNameInput, NAMEDATALEN) == 0 && constraintForm->conrelid == relationId) { systable_endscan(scanDescriptor); heap_close(pgConstraint, AccessShareLock); return true; } heapTuple = systable_getnext(scanDescriptor); } /* clean up scan and close system catalog */ systable_endscan(scanDescriptor); heap_close(pgConstraint, AccessShareLock); return false; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
void ParquetFetchSegFileInfo(AppendOnlyEntry *aoEntry, List *segfileinfos, Snapshot parquetMetaDataSnapshot) { Relation pg_parquetseg_rel; TupleDesc pg_parquetseg_dsc; HeapTuple tuple; SysScanDesc parquetscan; /* * Since this function is called for insert operation, * here we use RowExclusiveLock. */ pg_parquetseg_rel = heap_open(aoEntry->segrelid, RowExclusiveLock); pg_parquetseg_dsc = RelationGetDescr(pg_parquetseg_rel); parquetscan = systable_beginscan(pg_parquetseg_rel, InvalidOid, FALSE, parquetMetaDataSnapshot, 0, NULL); while (HeapTupleIsValid(tuple = systable_getnext(parquetscan))) { ListCell *lc; int segno = DatumGetInt32(fastgetattr(tuple, Anum_pg_parquetseg_segno, pg_parquetseg_dsc, NULL)); foreach (lc, segfileinfos) { ResultRelSegFileInfo *segfileinfo = (ResultRelSegFileInfo *)lfirst(lc); Assert(segfileinfo != NULL); if (segfileinfo->segno == segno) { segfileinfo->numfiles = 1; segfileinfo->tupcount = (int64)DatumGetFloat8(fastgetattr(tuple, Anum_pg_parquetseg_tupcount, pg_parquetseg_dsc, NULL)); segfileinfo->varblock = 0; segfileinfo->eof = (int64 *)palloc(sizeof(int64)); segfileinfo->eof[0] = (int64)DatumGetFloat8(fastgetattr(tuple, Anum_pg_parquetseg_eof, pg_parquetseg_dsc, NULL)); segfileinfo->uncompressed_eof = (int64 *)palloc(sizeof(int64)); segfileinfo->uncompressed_eof[0] = (int64)DatumGetFloat8(fastgetattr(tuple, Anum_pg_parquetseg_eofuncompressed, pg_parquetseg_dsc, NULL)); break; } } }
/* * 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 */
/* * Remove any existing "owned" markers for the specified sequence. * * Note: we don't provide a special function to install an "owned" * marker; just use recordDependencyOn(). */ void markSequenceUnowned(Oid seqId) { 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(RelationRelationId)); ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(seqId)); scan = systable_beginscan(depRel, DependDependerIndexId, true, SnapshotNow, 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) { simple_heap_delete(depRel, &tup->t_self); } } systable_endscan(scan); heap_close(depRel, RowExclusiveLock); }
/* * Same as LookupExtProtocolFunction but returns the actual * protocol Oid. */ Oid LookupExtProtocolOid(const char *prot_name, bool missing_ok) { Oid protOid = InvalidOid; Relation rel; ScanKeyData skey; SysScanDesc scan; HeapTuple tup; rel = heap_open(ExtprotocolRelationId, AccessShareLock); /* * Check the pg_extprotocol relation to be certain the protocol * is there. */ ScanKeyInit(&skey, Anum_pg_extprotocol_ptcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(prot_name)); scan = systable_beginscan(rel, ExtprotocolPtcnameIndexId, true, SnapshotNow, 1, &skey); tup = systable_getnext(scan); if (HeapTupleIsValid(tup)) protOid = HeapTupleGetOid(tup); else if (!missing_ok) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("protocol \"%s\" does not exist", prot_name))); systable_endscan(scan); heap_close(rel, AccessShareLock); return protOid; }
/* * regtypein - converts "typename" to type OID * * We also accept a numeric OID, for symmetry with the output routine. * * '-' signifies unknown (OID 0). In all other cases, the input must * match an existing pg_type entry. * * In bootstrap mode the name must just equal some existing name in pg_type. * In normal mode the type name can be specified using the full type syntax * recognized by the parser; for example, DOUBLE PRECISION and INTEGER[] will * work and be translated to the correct type names. (We ignore any typmod * info generated by the parser, however.) */ Datum regtypein(PG_FUNCTION_ARGS) { char *typ_name_or_oid = PG_GETARG_CSTRING(0); Oid result = InvalidOid; int32 typmod; /* '-' ? */ if (strcmp(typ_name_or_oid, "-") == 0) PG_RETURN_OID(InvalidOid); /* Numeric OID? */ if (typ_name_or_oid[0] >= '0' && typ_name_or_oid[0] <= '9' && strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid)) { result = DatumGetObjectId(DirectFunctionCall1(oidin, CStringGetDatum(typ_name_or_oid))); PG_RETURN_OID(result); } /* Else it's a type name, possibly schema-qualified or decorated */ /* * In bootstrap mode we assume the given name is not schema-qualified, and * just search pg_type for a match. This is needed for initializing other * system catalogs (pg_namespace may not exist yet, and certainly there * are no schemas other than pg_catalog). */ if (IsBootstrapProcessingMode()) { Relation hdesc; ScanKeyData skey[1]; SysScanDesc sysscan; HeapTuple tuple; ScanKeyInit(&skey[0], Anum_pg_type_typname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(typ_name_or_oid)); hdesc = heap_open(TypeRelationId, AccessShareLock); sysscan = systable_beginscan(hdesc, TypeNameNspIndexId, true, NULL, 1, skey); if (HeapTupleIsValid(tuple = systable_getnext(sysscan))) result = HeapTupleGetOid(tuple); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", typ_name_or_oid))); /* We assume there can be only one match */ systable_endscan(sysscan); heap_close(hdesc, AccessShareLock); PG_RETURN_OID(result); } /* * Normal case: invoke the full parser to deal with special cases such as * array syntax. */ parseTypeString(typ_name_or_oid, &result, &typmod); PG_RETURN_OID(result); }
/* * regprocin - converts "proname" to proc OID * * We also accept a numeric OID, for symmetry with the output routine. * * '-' signifies unknown (OID 0). In all other cases, the input must * match an existing pg_proc entry. */ Datum regprocin(PG_FUNCTION_ARGS) { char *pro_name_or_oid = PG_GETARG_CSTRING(0); RegProcedure result = InvalidOid; List *names; FuncCandidateList clist; /* '-' ? */ if (strcmp(pro_name_or_oid, "-") == 0) PG_RETURN_OID(InvalidOid); /* Numeric OID? */ if (pro_name_or_oid[0] >= '0' && pro_name_or_oid[0] <= '9' && strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid)) { result = DatumGetObjectId(DirectFunctionCall1(oidin, CStringGetDatum(pro_name_or_oid))); PG_RETURN_OID(result); } /* Else it's a name, possibly schema-qualified */ /* * In bootstrap mode we assume the given name is not schema-qualified, and * just search pg_proc for a unique match. This is needed for * initializing other system catalogs (pg_namespace may not exist yet, and * certainly there are no schemas other than pg_catalog). */ if (IsBootstrapProcessingMode()) { int matches = 0; Relation hdesc; ScanKeyData skey[1]; SysScanDesc sysscan; HeapTuple tuple; ScanKeyInit(&skey[0], Anum_pg_proc_proname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(pro_name_or_oid)); hdesc = heap_open(ProcedureRelationId, AccessShareLock); sysscan = systable_beginscan(hdesc, ProcedureNameArgsNspIndexId, true, NULL, 1, skey); while (HeapTupleIsValid(tuple = systable_getnext(sysscan))) { result = (RegProcedure) HeapTupleGetOid(tuple); if (++matches > 1) break; } systable_endscan(sysscan); heap_close(hdesc, AccessShareLock); if (matches == 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function \"%s\" does not exist", pro_name_or_oid))); else if (matches > 1) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("more than one function named \"%s\"", pro_name_or_oid))); PG_RETURN_OID(result); } /* * Normal case: parse the name into components and see if it matches any * pg_proc entries in the current search path. */ names = stringToQualifiedNameList(pro_name_or_oid); clist = FuncnameGetCandidates(names, -1, NIL, false, false, false); if (clist == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function \"%s\" does not exist", pro_name_or_oid))); else if (clist->next != NULL) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("more than one function named \"%s\"", pro_name_or_oid))); result = clist->oid; PG_RETURN_OID(result); }
/* * regclassin - converts "classname" to class OID * * We also accept a numeric OID, for symmetry with the output routine. * * '-' signifies unknown (OID 0). In all other cases, the input must * match an existing pg_class entry. */ Datum regclassin(PG_FUNCTION_ARGS) { char *class_name_or_oid = PG_GETARG_CSTRING(0); Oid result = InvalidOid; List *names; /* '-' ? */ if (strcmp(class_name_or_oid, "-") == 0) PG_RETURN_OID(InvalidOid); /* Numeric OID? */ if (class_name_or_oid[0] >= '0' && class_name_or_oid[0] <= '9' && strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid)) { result = DatumGetObjectId(DirectFunctionCall1(oidin, CStringGetDatum(class_name_or_oid))); PG_RETURN_OID(result); } /* Else it's a name, possibly schema-qualified */ /* * In bootstrap mode we assume the given name is not schema-qualified, and * just search pg_class for a match. This is needed for initializing * other system catalogs (pg_namespace may not exist yet, and certainly * there are no schemas other than pg_catalog). */ if (IsBootstrapProcessingMode()) { Relation hdesc; ScanKeyData skey[1]; SysScanDesc sysscan; HeapTuple tuple; ScanKeyInit(&skey[0], Anum_pg_class_relname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(class_name_or_oid)); hdesc = heap_open(RelationRelationId, AccessShareLock); sysscan = systable_beginscan(hdesc, ClassNameNspIndexId, true, NULL, 1, skey); if (HeapTupleIsValid(tuple = systable_getnext(sysscan))) result = HeapTupleGetOid(tuple); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", class_name_or_oid))); /* We assume there can be only one match */ systable_endscan(sysscan); heap_close(hdesc, AccessShareLock); PG_RETURN_OID(result); } /* * Normal case: parse the name into components and see if it matches any * pg_class entries in the current search path. */ names = stringToQualifiedNameList(class_name_or_oid); /* We might not even have permissions on this relation; don't lock it. */ result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false); PG_RETURN_OID(result); }
Datum gp_inject_fault(PG_FUNCTION_ARGS) { char *faultName = TextDatumGetCString(PG_GETARG_DATUM(0)); char *type = TextDatumGetCString(PG_GETARG_DATUM(1)); char *ddlStatement = TextDatumGetCString(PG_GETARG_DATUM(2)); char *databaseName = TextDatumGetCString(PG_GETARG_DATUM(3)); char *tableName = TextDatumGetCString(PG_GETARG_DATUM(4)); int numOccurrences = PG_GETARG_INT32(5); int sleepTimeSeconds = PG_GETARG_INT32(6); int dbid = PG_GETARG_INT32(7); StringInfo faultmsg = makeStringInfo(); /* Fast path if injecting fault in our postmaster. */ if (GpIdentity.dbid == dbid) { appendStringInfo(faultmsg, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n", faultName, type, ddlStatement, databaseName, tableName, numOccurrences, sleepTimeSeconds); int offset = 0; char *response = processTransitionRequest_faultInject( faultmsg->data, &offset, faultmsg->len); if (!response) elog(ERROR, "failed to inject fault locally (dbid %d)", dbid); if (strncmp(response, "Success:", strlen("Success:")) != 0) elog(ERROR, "%s", response); elog(NOTICE, "%s", response); PG_RETURN_DATUM(true); } /* Obtain host and port of the requested dbid */ HeapTuple tuple; Relation rel = heap_open(GpSegmentConfigRelationId, AccessShareLock); ScanKeyData scankey; SysScanDesc sscan; ScanKeyInit(&scankey, Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum((int16) dbid)); sscan = systable_beginscan(rel, GpSegmentConfigDbidIndexId, true, GetTransactionSnapshot(), 1, &scankey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cannot find dbid %d", dbid); bool isnull; Datum datum = heap_getattr(tuple, Anum_gp_segment_configuration_hostname, RelationGetDescr(rel), &isnull); char *hostname; if (!isnull) hostname = DatumGetCString(DirectFunctionCall1(textout, datum)); else elog(ERROR, "hostname is null for dbid %d", dbid); int port = DatumGetInt32(heap_getattr(tuple, Anum_gp_segment_configuration_port, RelationGetDescr(rel), &isnull)); systable_endscan(sscan); heap_close(rel, NoLock); struct addrinfo *addrList = NULL; struct addrinfo hint; int ret; /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_STREAM; hint.ai_family = AF_UNSPEC; char portStr[100]; if (snprintf(portStr, sizeof(portStr), "%d", port) >= sizeof(portStr)) elog(ERROR, "port number too long for dbid %d", dbid); /* Use pg_getaddrinfo_all() to resolve the address */ ret = pg_getaddrinfo_all(hostname, portStr, &hint, &addrList); if (ret || !addrList) { if (addrList) pg_freeaddrinfo_all(hint.ai_family, addrList); elog(ERROR, "could not translate host name \"%s\" to address: %s\n", hostname, gai_strerror(ret)); } PrimaryMirrorTransitionClientInfo client; client.receivedDataCallbackFn = transitionReceivedDataFn; client.errorLogFn = transitionErrorLogFn; client.checkForNeedToExitFn = checkForNeedToExitFn; transitionMsgErrors = makeStringInfo(); appendStringInfo(faultmsg, "%s\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n", "faultInject", faultName, type, ddlStatement, databaseName, tableName, numOccurrences, sleepTimeSeconds); if (sendTransitionMessage(&client, addrList, faultmsg->data, faultmsg->len, 1 /* retries */, 60 /* timeout */) != TRANS_ERRCODE_SUCCESS) { pg_freeaddrinfo_all(hint.ai_family, addrList); ereport(ERROR, (errmsg("failed to inject %s fault in dbid %d", faultName, dbid), errdetail("%s", transitionMsgErrors->data))); } pg_freeaddrinfo_all(hint.ai_family, addrList); PG_RETURN_DATUM(BoolGetDatum(true)); }