At Mon, 28 Aug 2017 18:28:07 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI 
<horiguchi.kyot...@lab.ntt.co.jp> wrote in 
<20170828.182807.98097766.horiguchi.kyot...@lab.ntt.co.jp>
> I'll add this to CF2017-09.

This patch got deadly atack from the commit 30833ba. I changed
the signature of expand_single_inheritance_child in addition to
make_inh_translation_list to notify that the specified child is
no longer a child of the parent.

This passes regular regression test and fixed the the problem.

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
*** a/src/backend/catalog/pg_inherits.c
--- b/src/backend/catalog/pg_inherits.c
***************
*** 42,47 **** typedef struct SeenRelsEntry
--- 42,49 ----
  	ListCell   *numparents_cell;	/* corresponding list cell */
  } SeenRelsEntry;
  
+ static bool is_descendent_of_internal(Oid parentId, Oid childId,
+ 									  HTAB *seen_rels);
  /*
   * find_inheritance_children
   *
***************
*** 400,402 **** typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
--- 402,472 ----
  
  	return result;
  }
+ 
+ /*
+  * Check if the child is really a descendent of the parent
+  */
+ bool
+ is_descendent_of(Oid parentId, Oid childId)
+ {
+ 	HTAB	   *seen_rels;
+ 	HASHCTL		ctl;
+ 	bool		ischild = false;
+ 
+ 	memset(&ctl, 0, sizeof(ctl));
+ 	ctl.keysize = sizeof(Oid);
+ 	ctl.entrysize = sizeof(Oid);
+ 	ctl.hcxt = CurrentMemoryContext;
+ 
+ 	seen_rels = hash_create("is_descendent_of temporary table",
+ 							32, /* start small and extend */
+ 							&ctl,
+ 							HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
+ 
+ 	ischild = is_descendent_of_internal(parentId, childId, seen_rels);
+ 
+ 	hash_destroy(seen_rels);
+ 
+ 	return ischild;
+ }
+ 
+ static bool
+ is_descendent_of_internal(Oid parentId, Oid childId, HTAB *seen_rels)
+ {
+ 	Relation	inhrel;
+ 	SysScanDesc scan;
+ 	ScanKeyData key[1];
+ 	bool		ischild = false;
+ 	HeapTuple	inheritsTuple;
+ 
+ 	inhrel = heap_open(InheritsRelationId, AccessShareLock);
+ 	ScanKeyInit(&key[0], Anum_pg_inherits_inhparent,
+ 				BTEqualStrategyNumber, F_OIDEQ,	ObjectIdGetDatum(parentId));
+ 	scan = systable_beginscan(inhrel, InheritsParentIndexId, true,
+ 							  NULL, 1, key);
+ 
+ 	while ((inheritsTuple = systable_getnext(scan)) != NULL)
+ 	{
+ 		bool found;
+ 		Oid inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
+ 
+ 		hash_search(seen_rels, &inhrelid, HASH_ENTER, &found);
+ 
+ 		/*
+ 		 * Recursively check into children. Although there can't theoretically
+ 		 * be any cycles in the inheritance graph, check the cycles following
+ 		 * find_all_inheritors.
+ 		 */
+ 		if (inhrelid == childId ||
+ 			(!found && is_descendent_of_internal(inhrelid, childId, seen_rels)))
+ 		{
+ 			ischild = true;
+ 			break;
+ 		}
+ 	}
+ 
+ 	systable_endscan(scan);
+ 	heap_close(inhrel, AccessShareLock);
+ 
+ 	return ischild;
+ }
*** a/src/backend/optimizer/prep/prepunion.c
--- b/src/backend/optimizer/prep/prepunion.c
***************
*** 108,123 **** static void expand_partitioned_rtentry(PlannerInfo *root,
  						   LOCKMODE lockmode,
  						   bool *has_child, List **appinfos,
  						   List **partitioned_child_rels);
! static void expand_single_inheritance_child(PlannerInfo *root,
  								RangeTblEntry *parentrte,
  								Index parentRTindex, Relation parentrel,
  								PlanRowMark *parentrc, Relation childrel,
  								bool *has_child, List **appinfos,
  								List **partitioned_child_rels);
! static void make_inh_translation_list(Relation oldrelation,
  						  Relation newrelation,
! 						  Index newvarno,
! 						  List **translated_vars);
  static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
  					List *translated_vars);
  static Node *adjust_appendrel_attrs_mutator(Node *node,
--- 108,122 ----
  						   LOCKMODE lockmode,
  						   bool *has_child, List **appinfos,
  						   List **partitioned_child_rels);
! static bool expand_single_inheritance_child(PlannerInfo *root,
  								RangeTblEntry *parentrte,
  								Index parentRTindex, Relation parentrel,
  								PlanRowMark *parentrc, Relation childrel,
  								bool *has_child, List **appinfos,
  								List **partitioned_child_rels);
! static List *make_inh_translation_list(Relation oldrelation,
  						  Relation newrelation,
! 						  Index newvarno);
  static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
  					List *translated_vars);
  static Node *adjust_appendrel_attrs_mutator(Node *node,
***************
*** 1476,1481 **** expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
--- 1475,1482 ----
  		 * in which they appear in the PartitionDesc.  But first, expand the
  		 * parent itself.
  		 */
+ 
+ 		/* ignore the return value since this doesn't exclude the parent */
  		expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
  										oldrelation,
  										&has_child, &appinfos,
***************
*** 1497,1502 **** expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
--- 1498,1504 ----
  		{
  			Oid			childOID = lfirst_oid(l);
  			Relation	newrelation;
+ 			bool		expanded = false;
  
  			/* Open rel if needed; we already have required locks */
  			if (childOID != parentOID)
***************
*** 1516,1529 **** expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
  				continue;
  			}
  
! 			expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
  											newrelation,
  											&has_child, &appinfos,
  											&partitioned_child_rels);
  
! 			/* Close child relations, but keep locks */
  			if (childOID != parentOID)
! 				heap_close(newrelation, NoLock);
  		}
  	}
  
--- 1518,1532 ----
  				continue;
  			}
  
! 			expanded = expand_single_inheritance_child(root,
! 											rte, rti, oldrelation, oldrc,
  											newrelation,
  											&has_child, &appinfos,
  											&partitioned_child_rels);
  
! 			/* Close child relations, but keep locks if expanded */
  			if (childOID != parentOID)
! 				heap_close(newrelation, expanded ? NoLock : lockmode);
  		}
  	}
  
***************
*** 1581,1586 **** expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
--- 1584,1590 ----
  	{
  		Oid			childOID = partdesc->oids[i];
  		Relation	childrel;
+ 		bool		expanded = false;
  
  		/* Open rel; we already have required locks */
  		childrel = heap_open(childOID, NoLock);
***************
*** 1592,1598 **** expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
  			continue;
  		}
  
! 		expand_single_inheritance_child(root, parentrte, parentRTindex,
  										parentrel, parentrc, childrel,
  										has_child, appinfos,
  										partitioned_child_rels);
--- 1596,1603 ----
  			continue;
  		}
  
! 		expanded = expand_single_inheritance_child(root,
! 										parentrte, parentRTindex,
  										parentrel, parentrc, childrel,
  										has_child, appinfos,
  										partitioned_child_rels);
***************
*** 1606,1613 **** expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
  										  has_child, appinfos,
  										  partitioned_child_rels);
  
! 		/* Close child relation, but keep locks */
! 		heap_close(childrel, NoLock);
  	}
  }
  
--- 1611,1618 ----
  										  has_child, appinfos,
  										  partitioned_child_rels);
  
! 		/* Close child relation, but keep locks if expanded */
! 		heap_close(childrel, expanded ? NoLock : lockmode);
  	}
  }
  
***************
*** 1619,1626 **** expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
   * anything at all.  Otherwise, we'll set "has_child" to true, build a
   * RangeTblEntry and either a PartitionedChildRelInfo or AppendRelInfo as
   * appropriate, plus maybe a PlanRowMark.
   */
! static void
  expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
  								Index parentRTindex, Relation parentrel,
  								PlanRowMark *parentrc, Relation childrel,
--- 1624,1634 ----
   * anything at all.  Otherwise, we'll set "has_child" to true, build a
   * RangeTblEntry and either a PartitionedChildRelInfo or AppendRelInfo as
   * appropriate, plus maybe a PlanRowMark.
+  *
+  * Returns false if the child has been found that no longer a child of the
+  * parent.
   */
! static bool
  expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
  								Index parentRTindex, Relation parentrel,
  								PlanRowMark *parentrc, Relation childrel,
***************
*** 1661,1666 **** expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
--- 1669,1692 ----
  	 */
  	if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
  	{
+ 		List *translated_vars =
+ 			make_inh_translation_list(parentrel, childrel, childRTindex);
+ 
+ 		/*
+ 		 * It may happen that the childOID is no longer a child of the
+ 		 * parent.
+ 		 */
+ 		if (!translated_vars)
+ 		{
+ 			/*
+ 			 * This childrel is no longer a child of the parent.  Return doing
+ 			 * nothing. Halfway built childrte is abandoned but this happens
+ 			 * really rarely.
+ 			 */
+ 			Assert (childOID != parentOID);
+ 			return false;
+ 		}
+ 
  		/* Remember if we saw a real child. */
  		if (childOID != parentOID)
  			*has_child = true;
***************
*** 1670,1677 **** expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
  		appinfo->child_relid = childRTindex;
  		appinfo->parent_reltype = parentrel->rd_rel->reltype;
  		appinfo->child_reltype = childrel->rd_rel->reltype;
! 		make_inh_translation_list(parentrel, childrel, childRTindex,
! 								  &appinfo->translated_vars);
  		appinfo->parent_reloid = parentOID;
  		*appinfos = lappend(*appinfos, appinfo);
  
--- 1696,1702 ----
  		appinfo->child_relid = childRTindex;
  		appinfo->parent_reltype = parentrel->rd_rel->reltype;
  		appinfo->child_reltype = childrel->rd_rel->reltype;
! 		appinfo->translated_vars = translated_vars;
  		appinfo->parent_reloid = parentOID;
  		*appinfos = lappend(*appinfos, appinfo);
  
***************
*** 1726,1744 **** expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
  
  		root->rowMarks = lappend(root->rowMarks, childrc);
  	}
  }
  
  /*
   * make_inh_translation_list
   *	  Build the list of translations from parent Vars to child Vars for
!  *	  an inheritance child.
   *
   * For paranoia's sake, we match type/collation as well as attribute name.
   */
! static void
  make_inh_translation_list(Relation oldrelation, Relation newrelation,
! 						  Index newvarno,
! 						  List **translated_vars)
  {
  	List	   *vars = NIL;
  	TupleDesc	old_tupdesc = RelationGetDescr(oldrelation);
--- 1751,1771 ----
  
  		root->rowMarks = lappend(root->rowMarks, childrc);
  	}
+ 
+ 	return true;
  }
  
  /*
   * make_inh_translation_list
   *	  Build the list of translations from parent Vars to child Vars for
!  *	  an inheritance child. Returns NULL if the two relations are no longer in
!  *	  a inheritance relationship.
   *
   * For paranoia's sake, we match type/collation as well as attribute name.
   */
! static List *
  make_inh_translation_list(Relation oldrelation, Relation newrelation,
! 						  Index newvarno)
  {
  	List	   *vars = NIL;
  	TupleDesc	old_tupdesc = RelationGetDescr(oldrelation);
***************
*** 1808,1815 **** make_inh_translation_list(Relation oldrelation, Relation newrelation,
--- 1835,1852 ----
  					break;
  			}
  			if (new_attno >= newnatts)
+ 			{
+ 				/*
+ 				 * It's possible that newrelation is no longer a child of the
+ 				 * oldrelation. We just ingore it for the case.
+ 				 */
+ 				if (!is_descendent_of(oldrelation->rd_id, newrelation->rd_id))
+ 					return NULL;
+ 
+ 				/* If still a child, something's wrong. */
  				elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
  					 attname, RelationGetRelationName(newrelation));
+ 			}
  		}
  
  		/* Found it, check type and collation match */
***************
*** 1828,1834 **** make_inh_translation_list(Relation oldrelation, Relation newrelation,
  									 0));
  	}
  
! 	*translated_vars = vars;
  }
  
  /*
--- 1865,1871 ----
  									 0));
  	}
  
! 	return vars;
  }
  
  /*
*** a/src/include/catalog/pg_inherits_fn.h
--- b/src/include/catalog/pg_inherits_fn.h
***************
*** 23,27 **** extern List *find_all_inheritors(Oid parentrelId, LOCKMODE lockmode,
--- 23,28 ----
  extern bool has_subclass(Oid relationId);
  extern bool has_superclass(Oid relationId);
  extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
+ extern bool is_descendent_of(Oid parentId, Oid childId);
  
  #endif							/* PG_INHERITS_FN_H */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to