Esempio n. 1
0
/**
 * @fn      Datum get_table_and_inheritors(PG_FUNCTION_ARGS)
 * @brief   Return array containing Oids of parent table and its children.
 *          Note that this function does not release relation locks.
 *
 * get_table_and_inheritors(table)
 *
 * @param	table	parent table.
 * @retval	regclass[]
 */
Datum
repack_get_table_and_inheritors(PG_FUNCTION_ARGS)
{
	Oid			parent = PG_GETARG_OID(0);
	List	   *relations;
	Datum	   *relations_array;
	int			relations_array_size;
	ArrayType  *result;
	ListCell   *lc;
	int			i;

	LockRelationOid(parent, AccessShareLock);

	/* Check that parent table exists */
	if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(parent)))
		PG_RETURN_ARRAYTYPE_P(construct_empty_array(OIDOID));

	/* Also check that children exist */
	relations = find_all_inheritors(parent, AccessShareLock, NULL);

	relations_array_size = list_length(relations);
	if (relations_array_size == 0)
		PG_RETURN_ARRAYTYPE_P(construct_empty_array(OIDOID));

	relations_array = palloc(relations_array_size * sizeof(Datum));

	i = 0;
	foreach (lc, relations)
		relations_array[i++] = ObjectIdGetDatum(lfirst_oid(lc));

	result = construct_array(relations_array,
							 relations_array_size,
							 OIDOID, sizeof(Oid),
							 true, 'i');

	pfree(relations_array);

	PG_RETURN_ARRAYTYPE_P(result);
}
void LockSegfilesOnMaster(Relation rel, int32 segno) {
  List *children = NIL;
  ListCell *lc;

  children = find_all_inheritors(rel->rd_id);

  foreach(lc, children)
  {
    Relation child_rel = rel;
    Oid oid = lfirst_oid(lc);

    if (rel_is_partitioned(oid))
      continue;

    /* open/close the child relation. */
    if (oid != rel->rd_id)
      child_rel = heap_open(oid, AccessShareLock);

    LockSegfilesOnMasterForSingleRel(child_rel, segno);

    if (oid != rel->rd_id)
      heap_close(child_rel, AccessShareLock);
  }
Esempio n. 3
0
/*
 * sepgsql_dml_privileges
 *
 * Entrypoint of the DML permission checks
 */
bool
sepgsql_dml_privileges(List *rangeTabls, bool abort_on_violation)
{
	ListCell   *lr;

	foreach(lr, rangeTabls)
	{
		RangeTblEntry *rte = lfirst(lr);
		uint32		required = 0;
		List	   *tableIds;
		ListCell   *li;

		/*
		 * Only regular relations shall be checked
		 */
		if (rte->rtekind != RTE_RELATION)
			continue;

		/*
		 * Find out required permissions
		 */
		if (rte->requiredPerms & ACL_SELECT)
			required |= SEPG_DB_TABLE__SELECT;
		if (rte->requiredPerms & ACL_INSERT)
			required |= SEPG_DB_TABLE__INSERT;
		if (rte->requiredPerms & ACL_UPDATE)
		{
			if (!bms_is_empty(rte->updatedCols))
				required |= SEPG_DB_TABLE__UPDATE;
			else
				required |= SEPG_DB_TABLE__LOCK;
		}
		if (rte->requiredPerms & ACL_DELETE)
			required |= SEPG_DB_TABLE__DELETE;

		/*
		 * Skip, if nothing to be checked
		 */
		if (required == 0)
			continue;

		/*
		 * If this RangeTblEntry is also supposed to reference inherited
		 * tables, we need to check security label of the child tables. So, we
		 * expand rte->relid into list of OIDs of inheritance hierarchy, then
		 * checker routine will be invoked for each relations.
		 */
		if (!rte->inh)
			tableIds = list_make1_oid(rte->relid);
		else
			tableIds = find_all_inheritors(rte->relid, NoLock, NULL);

		foreach(li, tableIds)
		{
			Oid			tableOid = lfirst_oid(li);
			Bitmapset  *selectedCols;
			Bitmapset  *insertedCols;
			Bitmapset  *updatedCols;

			/*
			 * child table has different attribute numbers, so we need to fix
			 * up them.
			 */
			selectedCols = fixup_inherited_columns(rte->relid, tableOid,
												   rte->selectedCols);
			insertedCols = fixup_inherited_columns(rte->relid, tableOid,
												   rte->insertedCols);
			updatedCols = fixup_inherited_columns(rte->relid, tableOid,
												  rte->updatedCols);

			/*
			 * check permissions on individual tables
			 */
			if (!check_relation_privileges(tableOid,
										   selectedCols,
										   insertedCols,
										   updatedCols,
										   required, abort_on_violation))
				return false;
		}
Esempio n. 4
0
/*
 * expand_inherited_rtentry
 *		Check whether a rangetable entry represents an inheritance set.
 *		If so, add entries for all the child tables to the query's
 *		rangetable, and build AppendRelInfo nodes for all the child tables
 *		and add them to root->append_rel_list.  If not, clear the entry's
 *		"inh" flag to prevent later code from looking for AppendRelInfos.
 *
 * Note that the original RTE is considered to represent the whole
 * inheritance set.  The first of the generated RTEs is an RTE for the same
 * table, but with inh = false, to represent the parent table in its role
 * as a simple member of the inheritance set.
 *
 * A childless table is never considered to be an inheritance set. For
 * regular inheritance, a parent RTE must always have at least two associated
 * AppendRelInfos: one corresponding to the parent table as a simple member of
 * inheritance set and one or more corresponding to the actual children.
 * Since a partitioned table is not scanned, it might have only one associated
 * AppendRelInfo.
 */
static void
expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
{
	Oid			parentOID;
	PlanRowMark *oldrc;
	Relation	oldrelation;
	LOCKMODE	lockmode;
	List	   *inhOIDs;
	ListCell   *l;

	/* Does RT entry allow inheritance? */
	if (!rte->inh)
		return;
	/* Ignore any already-expanded UNION ALL nodes */
	if (rte->rtekind != RTE_RELATION)
	{
		Assert(rte->rtekind == RTE_SUBQUERY);
		return;
	}
	/* Fast path for common case of childless table */
	parentOID = rte->relid;
	if (!has_subclass(parentOID))
	{
		/* Clear flag before returning */
		rte->inh = false;
		return;
	}

	/*
	 * The rewriter should already have obtained an appropriate lock on each
	 * relation named in the query.  However, for each child relation we add
	 * to the query, we must obtain an appropriate lock, because this will be
	 * the first use of those relations in the parse/rewrite/plan pipeline.
	 * Child rels should use the same lockmode as their parent.
	 */
	lockmode = rte->rellockmode;

	/* Scan for all members of inheritance set, acquire needed locks */
	inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);

	/*
	 * Check that there's at least one descendant, else treat as no-child
	 * case.  This could happen despite above has_subclass() check, if table
	 * once had a child but no longer does.
	 */
	if (list_length(inhOIDs) < 2)
	{
		/* Clear flag before returning */
		rte->inh = false;
		return;
	}

	/*
	 * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
	 * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
	 * child.
	 */
	oldrc = get_plan_rowmark(root->rowMarks, rti);
	if (oldrc)
		oldrc->isParent = true;

	/*
	 * Must open the parent relation to examine its tupdesc.  We need not lock
	 * it; we assume the rewriter already did.
	 */
	oldrelation = heap_open(parentOID, NoLock);

	/* Scan the inheritance set and expand it */
	if (RelationGetPartitionDesc(oldrelation) != NULL)
	{
		Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);

		/*
		 * If this table has partitions, recursively expand them in the order
		 * in which they appear in the PartitionDesc.  While at it, also
		 * extract the partition key columns of all the partitioned tables.
		 */
		expand_partitioned_rtentry(root, rte, rti, oldrelation, oldrc,
								   lockmode, &root->append_rel_list);
	}
	else
	{
		List	   *appinfos = NIL;
		RangeTblEntry *childrte;
		Index		childRTindex;

		/*
		 * This table has no partitions.  Expand any plain inheritance
		 * children in the order the OIDs were returned by
		 * find_all_inheritors.
		 */
		foreach(l, inhOIDs)
		{
			Oid			childOID = lfirst_oid(l);
			Relation	newrelation;

			/* Open rel if needed; we already have required locks */
			if (childOID != parentOID)
				newrelation = heap_open(childOID, NoLock);
			else
				newrelation = oldrelation;

			/*
			 * It is possible that the parent table has children that are temp
			 * tables of other backends.  We cannot safely access such tables
			 * (because of buffering issues), and the best thing to do seems
			 * to be to silently ignore them.
			 */
			if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
			{
				heap_close(newrelation, lockmode);
				continue;
			}

			expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
											newrelation,
											&appinfos, &childrte,
											&childRTindex);

			/* Close child relations, but keep locks */
			if (childOID != parentOID)
				heap_close(newrelation, NoLock);
		}

		/*
		 * If all the children were temp tables, pretend it's a
		 * non-inheritance situation; we don't need Append node in that case.
		 * The duplicate RTE we added for the parent table is harmless, so we
		 * don't bother to get rid of it; ditto for the useless PlanRowMark
		 * node.
		 */
		if (list_length(appinfos) < 2)
			rte->inh = false;
		else
			root->append_rel_list = list_concat(root->append_rel_list,
												appinfos);

	}