diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 3553c3b..47d466c 100644
*** a/src/backend/catalog/heap.c
--- /bsrc/backend/catalog/heap.c
*************** static Oid AddNewRelationType(const char
*** 77,83 ****
  				   char new_rel_kind,
  				   Oid new_array_type);
  static void RelationRemoveInheritance(Oid relid);
! static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
  static void StoreConstraints(Relation rel, TupleDesc tupdesc);
  static void SetRelationNumChecks(Relation rel, int numchecks);
  static List *insert_ordered_unique_oid(List *list, Oid datum);
--- 77,83 ----
  				   char new_rel_kind,
  				   Oid new_array_type);
  static void RelationRemoveInheritance(Oid relid);
! static void StoreRelCheck(Relation rel, char *ccname, char *ccbin, const bool is_local, const int inhcount);
  static void StoreConstraints(Relation rel, TupleDesc tupdesc);
  static void SetRelationNumChecks(Relation rel, int numchecks);
  static List *insert_ordered_unique_oid(List *list, Oid datum);
*************** StoreAttrDefault(Relation rel, AttrNumbe
*** 1531,1537 ****
   * in the pg_class entry for the relation.
   */
  static void
! StoreRelCheck(Relation rel, char *ccname, char *ccbin)
  {
  	Node	   *expr;
  	char	   *ccsrc;
--- 1531,1537 ----
   * in the pg_class entry for the relation.
   */
  static void
! StoreRelCheck(Relation rel, char *ccname, char *ccbin, const bool is_local, const int inhcount)
  {
  	Node	   *expr;
  	char	   *ccsrc;
*************** StoreRelCheck(Relation rel, char *ccname
*** 1608,1614 ****
  						  InvalidOid,	/* no associated index */
  						  expr, /* Tree form check constraint */
  						  ccbin,	/* Binary form check constraint */
! 						  ccsrc);		/* Source form check constraint */
  
  	pfree(ccsrc);
  }
--- 1608,1616 ----
  						  InvalidOid,	/* no associated index */
  						  expr, /* Tree form check constraint */
  						  ccbin,	/* Binary form check constraint */
! 						  ccsrc, /* Source form check constraint */
! 						  is_local, /* islocal */
! 						  inhcount); /* coninhcount */
  
  	pfree(ccsrc);
  }
*************** StoreConstraints(Relation rel, TupleDesc
*** 1643,1649 ****
  
  	for (i = 0; i < constr->num_check; i++)
  		StoreRelCheck(rel, constr->check[i].ccname,
! 					  constr->check[i].ccbin);
  
  	if (constr->num_check > 0)
  		SetRelationNumChecks(rel, constr->num_check);
--- 1645,1653 ----
  
  	for (i = 0; i < constr->num_check; i++)
  		StoreRelCheck(rel, constr->check[i].ccname,
! 					  constr->check[i].ccbin,
! 					  constr->check[i].is_local,
! 					  constr->check[i].inhcount);
  
  	if (constr->num_check > 0)
  		SetRelationNumChecks(rel, constr->num_check);
*************** AddRelationRawConstraints(Relation rel,
*** 1811,1816 ****
--- 1815,1821 ----
  						(errcode(ERRCODE_DUPLICATE_OBJECT),
  				errmsg("constraint \"%s\" for relation \"%s\" already exists",
  					   ccname, RelationGetRelationName(rel))));
+ 
  			/* Check against other new constraints */
  			/* Needed because we don't do CommandCounterIncrement in loop */
  			foreach(cell2, checknames)
*************** AddRelationRawConstraints(Relation rel,
*** 1863,1869 ****
  		/*
  		 * OK, store it.
  		 */
! 		StoreRelCheck(rel, ccname, nodeToString(expr));
  
  		numchecks++;
  
--- 1868,1874 ----
  		/*
  		 * OK, store it.
  		 */
! 		StoreRelCheck(rel, ccname, nodeToString(expr), cdef->is_local, cdef->inhcount);
  
  		numchecks++;
  
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index f07d9ae..6db3084 100644
*** a/src/backend/catalog/index.c
--- /bsrc/backend/catalog/index.c
*************** index_create(Oid heapRelationId,
*** 716,722 ****
  										   InvalidOid,	/* no associated index */
  										   NULL,		/* no check constraint */
  										   NULL,
! 										   NULL);
  
  			referenced.classId = ConstraintRelationId;
  			referenced.objectId = conOid;
--- 716,724 ----
  										   InvalidOid,	/* no associated index */
  										   NULL,		/* no check constraint */
  										   NULL,
! 										   NULL,
! 										   true, /* islocal */
! 										   0); /* inhcount */
  
  			referenced.classId = ConstraintRelationId;
  			referenced.objectId = conOid;
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index d9b20fd..eafc143 100644
*** a/src/backend/catalog/pg_constraint.c
--- /bsrc/backend/catalog/pg_constraint.c
*************** CreateConstraintEntry(const char *constr
*** 60,66 ****
  					  Oid indexRelId,
  					  Node *conExpr,
  					  const char *conBin,
! 					  const char *conSrc)
  {
  	Relation	conDesc;
  	Oid			conOid;
--- 60,68 ----
  					  Oid indexRelId,
  					  Node *conExpr,
  					  const char *conBin,
! 					  const char *conSrc,
! 					  const bool conIsLocal,
! 					  const int conInhCount)
  {
  	Relation	conDesc;
  	Oid			conOid;
*************** CreateConstraintEntry(const char *constr
*** 171,176 ****
--- 173,181 ----
  	else
  		nulls[Anum_pg_constraint_conffeqop - 1] = 'n';
  
+ 	values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
+ 	values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
+ 
  	/*
  	 * initialize the binary form of the check constraint.
  	 */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 55c50f9..790b35a 100644
*** a/src/backend/commands/tablecmds.c
--- /bsrc/backend/commands/tablecmds.c
*************** static void truncate_check_rel(Relation 
*** 170,175 ****
--- 170,177 ----
  static List *MergeAttributes(List *schema, List *supers, bool istemp,
  				List **supOids, List **supconstr, int *supOidCount);
  static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
+ static void MergeInheritedConstraints(Relation rel, List *old_constraints,
+ 									List *new_constriants);
  static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
  static void add_nonduplicate_constraint(Constraint *cdef,
  							ConstrCheck *check, int *ncheck);
*************** static void ATExecDropColumn(Relation re
*** 232,245 ****
  				 bool recurse, bool recursing);
  static void ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
  			   IndexStmt *stmt, bool is_rebuild);
  static void ATExecAddConstraint(AlteredTableInfo *tab, Relation rel,
  					Node *newConstraint);
  static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
  						  FkConstraint *fkconstraint);
- static void ATPrepDropConstraint(List **wqueue, Relation rel,
- 					 bool recurse, AlterTableCmd *cmd);
  static void ATExecDropConstraint(Relation rel, const char *constrName,
! 					 DropBehavior behavior, bool quiet);
  static void ATPrepAlterColumnType(List **wqueue,
  					  AlteredTableInfo *tab, Relation rel,
  					  bool recurse, bool recursing,
--- 234,248 ----
  				 bool recurse, bool recursing);
  static void ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
  			   IndexStmt *stmt, bool is_rebuild);
+ static void ATPrepAddConstraint(List **wqueue, Relation rel, bool recurse,
+ 				AlterTableCmd *cmd);
  static void ATExecAddConstraint(AlteredTableInfo *tab, Relation rel,
  					Node *newConstraint);
  static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
  						  FkConstraint *fkconstraint);
  static void ATExecDropConstraint(Relation rel, const char *constrName,
! 					 DropBehavior behavior, 
! 					 bool recurse, bool recursing);
  static void ATPrepAlterColumnType(List **wqueue,
  					  AlteredTableInfo *tab, Relation rel,
  					  bool recurse, bool recursing,
*************** static void ATExecEnableDisableRule(Rela
*** 263,269 ****
  static void ATExecAddInherit(Relation rel, RangeVar *parent);
  static void ATExecDropInherit(Relation rel, RangeVar *parent);
  static void copy_relation_data(Relation rel, SMgrRelation dst);
! 
  
  /* ----------------------------------------------------------------
   *		DefineRelation
--- 266,276 ----
  static void ATExecAddInherit(Relation rel, RangeVar *parent);
  static void ATExecDropInherit(Relation rel, RangeVar *parent);
  static void copy_relation_data(Relation rel, SMgrRelation dst);
! static bool ConstraintIsEquiv(const HeapTuple a, const HeapTuple b,
! 							  const TupleDesc tupleDesc);
! static char *decompile_conbin(HeapTuple contup, TupleDesc tupdesc);
! static void change_opfuncid(Node *node, Oid opfuncid);
! static bool change_opfuncid_walker(Node *node, void *opfuncid);
  
  /* ----------------------------------------------------------------
   *		DefineRelation
*************** DefineRelation(CreateStmt *stmt, char re
*** 488,493 ****
--- 495,505 ----
  		}
  	}
  
+ 	if (old_constraints && stmt->constraints)
+ 	{
+ 		MergeInheritedConstraints(rel, old_constraints, stmt->constraints);
+ 	}
+ 
  	/*
  	 * Parse and add the defaults/constraints, if any.
  	 */
*************** MergeAttributes(List *schema, List *supe
*** 1053,1058 ****
--- 1065,1072 ----
  				Constraint *cdef = makeNode(Constraint);
  				Node	   *expr;
  
+ 				cdef->is_local = false;
+ 				cdef->inhcount = check[i].inhcount + 1;
  				cdef->contype = CONSTR_CHECK;
  				cdef->name = pstrdup(check[i].ccname);
  				cdef->raw_expr = NULL;
*************** MergeAttributes(List *schema, List *supe
*** 1175,1180 ****
--- 1189,1280 ----
  	return schema;
  }
  
+ /*
+  * Go through constraints in new constraints
+  * if we have a matching constraint in old_constraints and they have a
+  * matching definition, then remove the constraint from new_constraints
+  */
+ static void
+ MergeInheritedConstraints(Relation rel,
+ 						  List *old_constraints,
+ 						  List *new_constraints)
+ {
+ 	ListCell *cur_item;
+ 	ListCell *prev_item;
+ 	ListCell *listptr;
+ 
+ 	prev_item = NULL;
+ 	cur_item = list_head(new_constraints);
+ 
+ 	while (cur_item != NULL)
+ 	{
+ 		bool get_next = true;
+ 		Constraint *cdef = (Constraint *) lfirst(cur_item);
+ 
+ 		if (cdef->contype == CONSTR_CHECK &&
+ 			cdef->cooked_expr == NULL &&
+ 			cdef->name &&
+ 			cdef->raw_expr)
+ 		{
+ 			foreach(listptr, old_constraints)
+ 			{
+ 				Constraint *cdef1 = (Constraint *) lfirst(listptr);
+ 
+ 				if (cdef1->contype == CONSTR_CHECK &&
+ 					cdef1->name &&
+ 					strcmp(cdef->name, cdef1->name) == 0)
+ 				{
+ 					ParseState		*pstate;
+ 					RangeTblEntry	*rte;
+ 					Node			*expr;
+ 					char 			*cooked;
+ 
+ 					pstate = make_parsestate(NULL);
+ 					rte = addRangeTableEntryForRelation(pstate,
+ 														rel,
+ 														NULL,
+ 														false,
+ 														true);
+ 					addRTEtoQuery(pstate, rte, true, true, true);
+ 
+ 					expr = transformExpr(pstate, cdef->raw_expr);
+ 					expr = coerce_to_boolean(pstate, expr, "CHECK");
+ 					change_opfuncid(expr, 0);
+ 
+ 					cooked = nodeToString(expr);
+ 
+ 					if (strcmp(cooked, cdef1->cooked_expr) == 0)
+ 					{
+ 						ereport(NOTICE,
+ 							(errmsg("merging constraint \"%s\" with inherited definition",
+ 							cdef->name)));
+ 
+ 						list_delete_cell(new_constraints, cur_item, prev_item);
+ 						pfree(cdef);
+ 						get_next = false;
+ 						if(prev_item)
+ 							cur_item = lnext(prev_item);
+ 						else
+ 							cur_item = list_head(new_constraints);
+ 					}else
+ 					{
+ 						ereport(ERROR,
+ 								(errmsg("constraint \"%s\" does not match inherited definition",
+ 								cdef->name)));
+ 					}
+ 
+ 					break;
+ 				}
+ 			}
+ 		}
+ 
+ 		if(get_next)
+ 		{
+ 			prev_item = cur_item;
+ 			cur_item = lnext(prev_item);
+ 		}
+ 	}
+ }
  
  /*
   * In multiple-inheritance situations, it's possible to inherit
*************** add_nonduplicate_constraint(Constraint *
*** 1208,1213 ****
--- 1308,1315 ----
  	/* No match on name, so add it to array */
  	check[*ncheck].ccname = cdef->name;
  	check[*ncheck].ccbin = pstrdup(cdef->cooked_expr);
+ 	check[*ncheck].inhcount = cdef->inhcount;
+ 	check[*ncheck].is_local = cdef->is_local;
  	(*ncheck)++;
  }
  
*************** varattnos_map_schema(TupleDesc old, List
*** 1306,1311 ****
--- 1408,1445 ----
  	return attmap;
  }
  
+ /*
+  * change an opfuncid of a Node
+  *
+  * Note that the passed node tree is modified in-place!
+  */
+ static void
+ change_opfuncid(Node *node, Oid opfuncid)
+ {
+ 	Oid *o = palloc(sizeof(Oid));
+ 	*o = opfuncid;
+ 	(void) change_opfuncid_walker(node, (void*)o);
+ 	pfree(o);
+ }
+ 
+ static bool
+ change_opfuncid_walker(Node *node, void *opfuncid)
+ {
+ 	if (node == NULL)
+ 		return false;
+ 
+ 	if (IsA(node, OpExpr))
+ 	{
+ 		Oid		*o = (Oid*)opfuncid;
+ 		OpExpr	*op = (OpExpr *) node;
+ 
+ 		op->opfuncid = *o;
+ 		return false;
+ 	}
+ 	return expression_tree_walker(node, change_opfuncid_walker,
+ 								  opfuncid);
+ 
+ }
  
  /*
   * StoreCatalogInheritance
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2038,2064 ****
  			break;
  		case AT_AddConstraint:	/* ADD CONSTRAINT */
  			ATSimplePermissions(rel, false);
! 
! 			/*
! 			 * Currently we recurse only for CHECK constraints, never for
! 			 * foreign-key constraints.  UNIQUE/PKEY constraints won't be seen
! 			 * here.
! 			 */
! 			if (IsA(cmd->def, Constraint))
! 				ATSimpleRecursion(wqueue, rel, cmd, recurse);
! 			/* No command-specific prep needed */
  			pass = AT_PASS_ADD_CONSTR;
  			break;
  		case AT_DropConstraint:	/* DROP CONSTRAINT */
  			ATSimplePermissions(rel, false);
! 			/* Performs own recursion */
! 			ATPrepDropConstraint(wqueue, rel, recurse, cmd);
! 			pass = AT_PASS_DROP;
! 			break;
! 		case AT_DropConstraintQuietly:	/* DROP CONSTRAINT for child */
! 			ATSimplePermissions(rel, false);
! 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
! 			/* No command-specific prep needed */
  			pass = AT_PASS_DROP;
  			break;
  		case AT_AlterColumnType:		/* ALTER COLUMN TYPE */
--- 2172,2187 ----
  			break;
  		case AT_AddConstraint:	/* ADD CONSTRAINT */
  			ATSimplePermissions(rel, false);
! 			ATPrepAddConstraint(wqueue, rel, recurse, cmd);
  			pass = AT_PASS_ADD_CONSTR;
  			break;
  		case AT_DropConstraint:	/* DROP CONSTRAINT */
  			ATSimplePermissions(rel, false);
! 			/* we follow AT_DropColumns example for better or for worse so
! 			 * Recursion occurs during execution phase
! 			 * No command-specific prep needed except saving recurse flag */
! 			if (recurse)
! 				cmd->subtype = AT_DropConstraintRecurse;
  			pass = AT_PASS_DROP;
  			break;
  		case AT_AlterColumnType:		/* ALTER COLUMN TYPE */
*************** ATExecCmd(AlteredTableInfo *tab, Relatio
*** 2247,2256 ****
  			ATExecAddConstraint(tab, rel, cmd->def);
  			break;
  		case AT_DropConstraint:	/* DROP CONSTRAINT */
! 			ATExecDropConstraint(rel, cmd->name, cmd->behavior, false);
  			break;
! 		case AT_DropConstraintQuietly:	/* DROP CONSTRAINT for child */
! 			ATExecDropConstraint(rel, cmd->name, cmd->behavior, true);
  			break;
  		case AT_AlterColumnType:		/* ALTER COLUMN TYPE */
  			ATExecAlterColumnType(tab, rel, cmd->name, (TypeName *) cmd->def);
--- 2370,2379 ----
  			ATExecAddConstraint(tab, rel, cmd->def);
  			break;
  		case AT_DropConstraint:	/* DROP CONSTRAINT */
! 			ATExecDropConstraint(rel, cmd->name, cmd->behavior, false, false);
  			break;
! 		case AT_DropConstraintRecurse:	/* DROP CONSTRAINT for child */
! 			ATExecDropConstraint(rel, cmd->name, cmd->behavior, true, false);
  			break;
  		case AT_AlterColumnType:		/* ALTER COLUMN TYPE */
  			ATExecAlterColumnType(tab, rel, cmd->name, (TypeName *) cmd->def);
*************** ATExecAddIndex(AlteredTableInfo *tab, Re
*** 3925,3930 ****
--- 4048,4102 ----
   * ALTER TABLE ADD CONSTRAINT
   */
  static void
+ ATPrepAddConstraint(List **wqueue, Relation rel, bool recurse,
+ 				AlterTableCmd *cmd)
+ {
+ 	/*
+ 	 * Currently we recurse only for CHECK constraints, never for
+ 	 * foreign-key constraints.  UNIQUE/PKEY constraints won't be seen
+ 	 * here.
+ 	 */
+ 	if (!IsA(cmd->def, Constraint))
+ 	{
+ 		return;
+ 	}
+ 
+ 	/*
+ 	 * Recurse to add the column to child classes, if requested.
+ 	 *
+ 	 * We must recurse one level at a time, so that multiply-inheriting
+ 	 * children are visited the right number of times and end up with the
+ 	 * right coninhcount.
+ 	 */
+ 	if (recurse)
+ 	{
+ 		AlterTableCmd	*childCmd = copyObject(cmd);
+ 		Constraint		*constr = (Constraint *) childCmd->def;
+ 
+ 		/* child should see column as singly inherited */
+ 		constr->inhcount = 1;
+ 		constr->is_local = false;
+ 
+ 		ATOneLevelRecursion(wqueue, rel, childCmd);
+ 	}
+ 	else
+ 	{
+ 		/*
+ 		 * If we are told not to recurse, there had better not be any child
+ 		 * tables; else the addition would put them out of step.
+ 		 */
+ 		if (find_inheritance_children(RelationGetRelid(rel)) != NIL)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ 					 errmsg("constraint must be added to child tables too")));
+ 	}
+ }
+ 
+ 
+ /*
+  * ALTER TABLE ADD CONSTRAINT
+  */
+ static void
  ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint)
  {
  	switch (nodeTag(newConstraint))
*************** ATAddForeignKeyConstraint(AlteredTableIn
*** 4284,4290 ****
  									  indexOid,
  									  NULL,		/* no check constraint */
  									  NULL,
! 									  NULL);
  
  	/*
  	 * Create the triggers that will enforce the constraint.
--- 4456,4464 ----
  									  indexOid,
  									  NULL,		/* no check constraint */
  									  NULL,
! 									  NULL,
! 									  true, /* islocal */
! 									  0); /* inhcount */
  
  	/*
  	 * Create the triggers that will enforce the constraint.
*************** createForeignKeyTriggers(Relation rel, F
*** 4804,4847 ****
   * ALTER TABLE DROP CONSTRAINT
   */
  static void
! ATPrepDropConstraint(List **wqueue, Relation rel,
! 					 bool recurse, AlterTableCmd *cmd)
  {
  	/*
! 	 * We don't want errors or noise from child tables, so we have to pass
! 	 * down a modified command.
  	 */
! 	if (recurse)
  	{
! 		AlterTableCmd *childCmd = copyObject(cmd);
  
! 		childCmd->subtype = AT_DropConstraintQuietly;
! 		ATSimpleRecursion(wqueue, rel, childCmd, recurse);
! 	}
! }
  
! static void
! ATExecDropConstraint(Relation rel, const char *constrName,
! 					 DropBehavior behavior, bool quiet)
! {
! 	int			deleted;
  
! 	deleted = RemoveRelConstraints(rel, constrName, behavior);
  
! 	if (!quiet)
! 	{
! 		/* If zero constraints deleted, complain */
! 		if (deleted == 0)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_UNDEFINED_OBJECT),
! 					 errmsg("constraint \"%s\" does not exist",
! 							constrName)));
! 		/* Otherwise if more than one constraint deleted, notify */
! 		else if (deleted > 1)
! 			ereport(NOTICE,
! 					(errmsg("multiple constraints named \"%s\" were dropped",
! 							constrName)));
  	}
  }
  
  /*
--- 4978,5096 ----
   * ALTER TABLE DROP CONSTRAINT
   */
  static void
! ATExecDropConstraint(Relation rel, const char *constrName,
! 					 DropBehavior behavior,
! 					 bool recurse, bool recursing)
  {
+ 	HeapTuple	tuple;
+ 	List		*children;
+ 	Relation	conrel;
+ 	TupleDesc	tupdesc;
+ 	Oid		relid;
+ 	Form_pg_constraint con;
+ 
+ 	relid = RelationGetRelid(rel);
+ 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
+ 	tupdesc = RelationGetDescr(conrel);
+ 
+ 	/* At top level, permission check was done in ATPrepCmd, else do it */
+ 	if (recursing)
+ 		ATSimplePermissions(rel, false);
+ 
+ 	tuple = SearchSysCache(CONSTRNAME,
+ 						   ObjectIdGetDatum(relid),
+ 						   CStringGetDatum(constrName),
+ 						   0, 0);
+ 
+ 	if (!HeapTupleIsValid(tuple))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_COLUMN),
+ 				 errmsg("constraint \"%s\" of relation \"%s\" does not exist",
+ 						constrName, RelationGetRelationName(rel))));
+ 
+ 	con = (Form_pg_constraint) GETSTRUCT(tuple);
+ 
+ 	/* Don't drop inherited constraints */
+ 	if (con->coninhcount > 0 && !recursing)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ 				 errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
+ 						constrName,
+ 						RelationGetRelationName(rel))));
+ 
+ 	ReleaseSysCache(tuple);
+ 
  	/*
! 	 * Propagate to children as appropriate.  Unlike most other ALTER
! 	 * routines, we have to do this one level of recursion at a time; we can't
! 	 * use find_all_inheritors to do it in one pass.
  	 */
! 	children = find_inheritance_children(RelationGetRelid(rel));
! 
! 	if (children)
  	{
! 		ListCell   *child;
  
! 		foreach(child, children)
! 		{
! 			Oid			childrelid = lfirst_oid(child);
! 			Relation	childrel;
! 			Form_pg_constraint childcon;
  
! 			childrel = heap_open(childrelid, AccessExclusiveLock);
! 			CheckTableNotInUse(childrel, "ALTER TABLE");
  
! 			tuple = SearchSysCacheCopy(CONSTRNAME,
! 								   ObjectIdGetDatum(childrelid),
! 								   CStringGetDatum(constrName),
! 								   0, 0);
! 			if (!HeapTupleIsValid(tuple))
! 				elog(ERROR, "cache lookup failed for constraint \"%s\" of relation %u",
! 					 constrName, childrelid);
! 
! 			childcon = (Form_pg_constraint) GETSTRUCT(tuple);
! 
! 			if (childcon->coninhcount <= 0)
! 				elog(ERROR, "relation %u has non-inherited constraint \"%s\"",
! 					 childrelid, constrName);
  
! 			if (recurse)
! 			{
! 				if (childcon->coninhcount == 1 && !childcon->conislocal)
! 				{
! 					ATExecDropConstraint(childrel, constrName, behavior, true, true);
! 				}
! 				else
! 				{
! 					childcon->coninhcount--;
! 
! 					simple_heap_update(conrel, &tuple->t_self, tuple);
! 					CatalogUpdateIndexes(conrel, tuple);
! 				}
! 			}
! 			else
! 			{
! 				/*
! 				 * If we were told to drop ONLY in this table (no recursion),
! 				 * we need to mark the inheritors' attribute as locally
! 				 * defined rather than inherited.
! 				 */
! 
! 				childcon->coninhcount--;
! 				childcon->conislocal = true;
! 
! 				simple_heap_update(conrel, &tuple->t_self, tuple);
! 				CatalogUpdateIndexes(conrel, tuple);
! 			}
! 
! 			heap_freetuple(tuple);
! 			heap_close(childrel, AccessExclusiveLock);
! 		}
  	}
+ 
+ 	RemoveRelConstraints(rel, constrName, behavior);
+ 
+ 	heap_close(conrel, RowExclusiveLock);
  }
  
  /*
*************** decompile_conbin(HeapTuple contup, Tuple
*** 6249,6254 ****
--- 6498,6523 ----
  }
  
  /*
+  * See if two constraints are "functionally" equivalent, but not necessarily equal
+  */
+ static bool
+ ConstraintIsEquiv(const HeapTuple a, const HeapTuple b, const TupleDesc tupleDesc)
+ {
+ 	const Form_pg_constraint acon = (Form_pg_constraint) GETSTRUCT(a);
+ 	const Form_pg_constraint bcon = (Form_pg_constraint) GETSTRUCT(b);
+ 
+ 	if (acon->condeferrable != bcon->condeferrable ||
+ 		acon->condeferred != bcon->condeferred ||
+ 			strcmp(decompile_conbin(a, tupleDesc),
+ 				   decompile_conbin(b, tupleDesc)) != 0)
+ 	{
+ 		return 0;
+ 	}else
+ 	{
+ 		return 1;
+ 	}
+ }
+ /*
   * Check columns in child table match up with columns in parent, and increment
   * their attinhcount.
   *
*************** MergeAttributesIntoExisting(Relation chi
*** 6342,6350 ****
   * make it possible to ensure no records are mistakenly inserted into the
   * master in partitioned tables rather than the appropriate child.
   *
-  * XXX This is O(N^2) which may be an issue with tables with hundreds of
-  * constraints. As long as tables have more like 10 constraints it shouldn't be
-  * a problem though. Even 100 constraints ought not be the end of the world.
   */
  static void
  MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
--- 6611,6616 ----
*************** MergeConstraintsIntoExisting(Relation ch
*** 6354,6439 ****
  	SysScanDesc scan;
  	ScanKeyData key;
  	HeapTuple	constraintTuple;
- 	ListCell   *elem;
- 	List	   *constraints;
  
! 	/* First gather up the child's constraint definitions */
! 	catalogRelation = heap_open(ConstraintRelationId, AccessShareLock);
  	tupleDesc = RelationGetDescr(catalogRelation);
  
  	ScanKeyInit(&key,
  				Anum_pg_constraint_conrelid,
  				BTEqualStrategyNumber, F_OIDEQ,
! 				ObjectIdGetDatum(RelationGetRelid(child_rel)));
  	scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
  							  true, SnapshotNow, 1, &key);
  
- 	constraints = NIL;
- 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
- 	{
- 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
- 
- 		if (con->contype != CONSTRAINT_CHECK)
- 			continue;
- 
- 		constraints = lappend(constraints, heap_copytuple(constraintTuple));
- 	}
- 
- 	systable_endscan(scan);
- 
- 	/* Then scan through the parent's constraints looking for matches */
- 	ScanKeyInit(&key,
- 				Anum_pg_constraint_conrelid,
- 				BTEqualStrategyNumber, F_OIDEQ,
- 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
- 	scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId, true,
- 							  SnapshotNow, 1, &key);
- 
  	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
  	{
  		Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
- 		bool		found = false;
- 		Form_pg_constraint child_con = NULL;
- 		HeapTuple	child_contuple = NULL;
  
  		if (parent_con->contype != CONSTRAINT_CHECK)
  			continue;
  
! 		foreach(elem, constraints)
! 		{
! 			child_contuple = (HeapTuple) lfirst(elem);
! 			child_con = (Form_pg_constraint) GETSTRUCT(child_contuple);
! 			if (strcmp(NameStr(parent_con->conname),
! 					   NameStr(child_con->conname)) == 0)
! 			{
! 				found = true;
! 				break;
! 			}
! 		}
  
! 		if (!found)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("child table is missing constraint \"%s\"",
  							NameStr(parent_con->conname))));
  
! 		if (parent_con->condeferrable != child_con->condeferrable ||
! 			parent_con->condeferred != child_con->condeferred ||
! 			strcmp(decompile_conbin(constraintTuple, tupleDesc),
! 				   decompile_conbin(child_contuple, tupleDesc)) != 0)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("constraint definition for check constraint \"%s\" does not match",
  							NameStr(parent_con->conname))));
  
! 		/*
! 		 * TODO: add conislocal,coninhcount to constraints. This is where we
! 		 * would have to bump them just like attributes
! 		 */
  	}
  
  	systable_endscan(scan);
! 	heap_close(catalogRelation, AccessShareLock);
  }
  
  /*
--- 6620,6673 ----
  	SysScanDesc scan;
  	ScanKeyData key;
  	HeapTuple	constraintTuple;
  
! 	catalogRelation = heap_open(ConstraintRelationId, RowExclusiveLock);
  	tupleDesc = RelationGetDescr(catalogRelation);
  
  	ScanKeyInit(&key,
  				Anum_pg_constraint_conrelid,
  				BTEqualStrategyNumber, F_OIDEQ,
! 				ObjectIdGetDatum(RelationGetRelid(parent_rel)));
  	scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
  							  true, SnapshotNow, 1, &key);
  
  	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
  	{
+ 		HeapTuple childTuple;
+ 		Form_pg_constraint child_con;
  		Form_pg_constraint parent_con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
  
  		if (parent_con->contype != CONSTRAINT_CHECK)
  			continue;
  
! 		childTuple = SearchSysCacheCopy(CONSTRNAME,
! 									ObjectIdGetDatum(RelationGetRelid(child_rel)),
! 									CStringGetDatum(NameStr(parent_con->conname)),
! 									0, 0);
  
! 		if (!HeapTupleIsValid(childTuple))
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("child table is missing constraint \"%s\"",
  							NameStr(parent_con->conname))));
  
! 		child_con = (Form_pg_constraint) GETSTRUCT(childTuple);
! 
! 		if (!ConstraintIsEquiv(constraintTuple, childTuple, tupleDesc))
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("constraint definition for check constraint \"%s\" does not match",
  							NameStr(parent_con->conname))));
  
! 		/* increment coninhcount */
! 		child_con->coninhcount++;
! 		simple_heap_update(catalogRelation, &childTuple->t_self, childTuple);
! 		CatalogUpdateIndexes(catalogRelation, childTuple);
! 		heap_freetuple(childTuple);
  	}
  
  	systable_endscan(scan);
! 	heap_close(catalogRelation, RowExclusiveLock);
  }
  
  /*
*************** ATExecDropInherit(Relation rel, RangeVar
*** 6458,6465 ****
--- 6692,6701 ----
  	ScanKeyData key[3];
  	HeapTuple	inheritsTuple,
  				attributeTuple,
+ 				constraintTuple,
  				depTuple;
  	bool		found = false;
+ 	TupleDesc	tupdesc;
  
  	/*
  	 * AccessShareLock on the parent is probably enough, seeing that DROP
*************** ATExecDropInherit(Relation rel, RangeVar
*** 6497,6503 ****
  			break;
  		}
  	}
- 
  	systable_endscan(scan);
  	heap_close(catalogRelation, RowExclusiveLock);
  
--- 6733,6738 ----
*************** ATExecDropInherit(Relation rel, RangeVar
*** 6547,6552 ****
--- 6782,6822 ----
  	systable_endscan(scan);
  	heap_close(catalogRelation, RowExclusiveLock);
  
+ 	catalogRelation = heap_open(ConstraintRelationId, RowExclusiveLock);
+ 	ScanKeyInit(&key[0],
+ 				Anum_pg_constraint_conrelid,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(RelationGetRelid(rel)));
+ 	scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
+ 							  true, SnapshotNow, 1, key);
+ 
+ 	tupdesc = RelationGetDescr(catalogRelation);
+ 
+ 	while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
+ 	{
+ 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
+ 
+ 		if (con->contype != CONSTRAINT_CHECK)
+ 			continue;
+ 
+ 		if (con->coninhcount > 0)
+ 		{
+ 			HeapTuple	copyTuple = heap_copytuple(constraintTuple);
+ 			Form_pg_constraint copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
+ 
+ 			copy_con->coninhcount--;
+ 			if (copy_con->coninhcount == 0)
+ 				copy_con->conislocal = true;
+ 
+ 			simple_heap_update(catalogRelation, &copyTuple->t_self, copyTuple);
+ 			CatalogUpdateIndexes(catalogRelation, copyTuple);
+ 			heap_freetuple(copyTuple);
+ 		}
+ 	}
+ 
+ 	systable_endscan(scan);
+ 	heap_close(catalogRelation, RowExclusiveLock);
+ 
  	/*
  	 * Drop the dependency
  	 *
*************** AtEOSubXact_on_commit_actions(bool isCom
*** 7050,7052 ****
--- 7320,7324 ----
  		}
  	}
  }
+ 
+ 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 188fe43..123209d 100644
*** a/src/backend/commands/typecmds.c
--- /bsrc/backend/commands/typecmds.c
*************** domainAddConstraint(Oid domainOid, Oid d
*** 2206,2212 ****
  						  InvalidOid,
  						  expr, /* Tree form check constraint */
  						  ccbin,	/* Binary form check constraint */
! 						  ccsrc);		/* Source form check constraint */
  
  	/*
  	 * Return the compiled constraint expression so the calling routine can
--- 2206,2214 ----
  						  InvalidOid,
  						  expr, /* Tree form check constraint */
  						  ccbin,	/* Binary form check constraint */
! 						  ccsrc,	/* Source form check constraint */
! 						  true, /* is local */
! 						  0); /* inhcount */
  
  	/*
  	 * Return the compiled constraint expression so the calling routine can
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 77bba77..c7fc509 100644
*** a/src/backend/nodes/copyfuncs.c
--- /bsrc/backend/nodes/copyfuncs.c
*************** _copyConstraint(Constraint *from)
*** 1814,1819 ****
--- 1814,1821 ----
  	COPY_NODE_FIELD(keys);
  	COPY_NODE_FIELD(options);
  	COPY_STRING_FIELD(indexspace);
+ 	COPY_SCALAR_FIELD(inhcount);
+ 	COPY_SCALAR_FIELD(is_local);
  
  	return newnode;
  }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7645e45..fe4ca20 100644
*** a/src/backend/nodes/equalfuncs.c
--- /bsrc/backend/nodes/equalfuncs.c
*************** _equalConstraint(Constraint *a, Constrai
*** 1839,1844 ****
--- 1839,1846 ----
  	COMPARE_NODE_FIELD(keys);
  	COMPARE_NODE_FIELD(options);
  	COMPARE_STRING_FIELD(indexspace);
+ 	COMPARE_SCALAR_FIELD(inhcount);
+ 	COMPARE_SCALAR_FIELD(is_local);
  
  	return true;
  }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 72ee2ff..450186c 100644
*** a/src/backend/nodes/outfuncs.c
--- /bsrc/backend/nodes/outfuncs.c
*************** _outConstraint(StringInfo str, Constrain
*** 2033,2038 ****
--- 2033,2041 ----
  			appendStringInfo(str, "<unrecognized_constraint>");
  			break;
  	}
+ 
+ 	WRITE_INT_FIELD(inhcount);
+ 	WRITE_BOOL_FIELD(is_local);
  }
  
  static void
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index efd50f6..a5f6932 100644
*** a/src/backend/parser/gram.y
--- /bsrc/backend/parser/gram.y
*************** ColConstraintElem:
*** 2068,2073 ****
--- 2068,2075 ----
  					n->cooked_expr = NULL;
  					n->keys = NULL;
  					n->indexspace = NULL;
+ 					n->is_local = true;
+ 					n->inhcount = 0;
  					$$ = (Node *)n;
  				}
  			| DEFAULT b_expr
*************** ConstraintElem:
*** 2208,2213 ****
--- 2210,2217 ----
  					n->raw_expr = $3;
  					n->cooked_expr = NULL;
  					n->indexspace = NULL;
+ 					n->inhcount = 0;
+ 					n->is_local = true;
  					$$ = (Node *)n;
  				}
  			| UNIQUE '(' columnList ')' opt_definition OptConsTableSpace
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index f2087e4..f105d39 100644
*** a/src/backend/parser/parse_utilcmd.c
--- /bsrc/backend/parser/parse_utilcmd.c
*************** transformColumnDefinition(ParseState *ps
*** 409,414 ****
--- 409,417 ----
  	{
  		constraint = lfirst(clist);
  
+ 		constraint->is_local = true;
+ 		constraint->inhcount = 0;
+ 
  		/*
  		 * If this column constraint is a FOREIGN KEY constraint, then we fill
  		 * in the current attribute's name and throw it into the list of FK
*************** transformInhRelation(ParseState *pstate,
*** 685,690 ****
--- 688,695 ----
  			n->cooked_expr = nodeToString(ccbin_node);
  			n->indexspace = NULL;
  			cxt->ckconstraints = lappend(cxt->ckconstraints, (Node *) n);
+ 			n->is_local = true;
+ 			n->inhcount = 0;
  		}
  	}
  
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 3f3c67d..250d468 100644
*** a/src/backend/utils/cache/catcache.c
--- /bsrc/backend/utils/cache/catcache.c
*************** CatalogCacheInitializeCache(CatCache *ca
*** 962,968 ****
  		else
  		{
  			if (cache->cc_key[i] != ObjectIdAttributeNumber)
! 				elog(FATAL, "only sys attr supported in caches is OID");
  			keytype = OIDOID;
  		}
  
--- 962,968 ----
  		else
  		{
  			if (cache->cc_key[i] != ObjectIdAttributeNumber)
! 				elog(FATAL, "only sys attr supported in caches is OID for rel: %s", cache->cc_relname);
  			keytype = OIDOID;
  		}
  
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 7ff0e8a..789c6a4 100644
*** a/src/backend/utils/cache/syscache.c
--- /bsrc/backend/utils/cache/syscache.c
*************** static const struct cachedesc cacheinfo[
*** 305,310 ****
--- 305,322 ----
  		},
  		128
  	},
+ 	{ConstraintRelationId,		// CONSTRNAME
+ 		ConstraintRelidNameIndexId,
+ 		Anum_pg_constraint_conrelid,
+ 		2,
+ 		{
+ 			Anum_pg_constraint_conrelid,
+ 			Anum_pg_constraint_conname,
+ 			0,
+ 			0
+ 		},
+ 		256,
+ 	},
  	{ConstraintRelationId,		/* CONSTROID */
  		ConstraintOidIndexId,
  		0,
diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h
index c5fb69a..aa683be 100644
*** a/src/include/access/tupdesc.h
--- /bsrc/include/access/tupdesc.h
*************** typedef struct attrDefault
*** 27,34 ****
  
  typedef struct constrCheck
  {
! 	char	   *ccname;
! 	char	   *ccbin;			/* nodeToString representation of expr */
  } ConstrCheck;
  
  /* This structure contains constraints of a tuple */
--- 27,36 ----
  
  typedef struct constrCheck
  {
! 	char	*ccname;
! 	char	*ccbin;			/* nodeToString representation of expr */
! 	bool	is_local;
! 	int		inhcount;
  } ConstrCheck;
  
  /* This structure contains constraints of a tuple */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index b9f34f2..9b17a73 100644
*** a/src/include/catalog/catversion.h
--- /bsrc/include/catalog/catversion.h
***************
*** 53,58 ****
   */
  
  /*							yyyymmddN */
! #define CATALOG_VERSION_NO	200803222
  
  #endif
--- 53,58 ----
   */
  
  /*							yyyymmddN */
! #define CATALOG_VERSION_NO	200803290
  
  #endif
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 7dc5215..d962930 100644
*** a/src/include/catalog/indexing.h
--- /bsrc/include/catalog/indexing.h
*************** DECLARE_INDEX(pg_constraint_contypid_ind
*** 121,126 ****
--- 121,128 ----
  #define ConstraintTypidIndexId	2666
  DECLARE_UNIQUE_INDEX(pg_constraint_oid_index, 2667, on pg_constraint using btree(oid oid_ops));
  #define ConstraintOidIndexId  2667
+ DECLARE_UNIQUE_INDEX(pg_constraint_relid_coname_index, 2700, on pg_constraint using btree(conrelid oid_ops, conname name_ops));
+ #define ConstraintRelidNameIndexId  2700
  
  DECLARE_UNIQUE_INDEX(pg_conversion_default_index, 2668, on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops, oid oid_ops));
  #define ConversionDefaultIndexId  2668
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 501899d..9e4a7c9 100644
*** a/src/include/catalog/pg_constraint.h
--- /bsrc/include/catalog/pg_constraint.h
*************** CATALOG(pg_constraint,2606)
*** 71,76 ****
--- 71,82 ----
  	char		confdeltype;	/* foreign key's ON DELETE action */
  	char		confmatchtype;	/* foreign key's match type */
  
+ 	/* Has a local definition (hence, do not drop when coninhcount is 0) */
+ 	bool conislocal;
+ 
+ 	/* Number of times inherited from direct parent relation(s) */
+ 	int4 coninhcount;
+ 
  	/*
  	 * VARIABLE LENGTH FIELDS start here.  These fields may be NULL, too.
  	 */
*************** typedef FormData_pg_constraint *Form_pg_
*** 125,150 ****
   *		compiler constants for pg_constraint
   * ----------------
   */
! #define Natts_pg_constraint					18
! #define Anum_pg_constraint_conname			1
! #define Anum_pg_constraint_connamespace		2
! #define Anum_pg_constraint_contype			3
! #define Anum_pg_constraint_condeferrable	4
! #define Anum_pg_constraint_condeferred		5
! #define Anum_pg_constraint_conrelid			6
! #define Anum_pg_constraint_contypid			7
! #define Anum_pg_constraint_confrelid		8
! #define Anum_pg_constraint_confupdtype		9
! #define Anum_pg_constraint_confdeltype		10
! #define Anum_pg_constraint_confmatchtype	11
! #define Anum_pg_constraint_conkey			12
! #define Anum_pg_constraint_confkey			13
! #define Anum_pg_constraint_conpfeqop		14
! #define Anum_pg_constraint_conppeqop		15
! #define Anum_pg_constraint_conffeqop		16
! #define Anum_pg_constraint_conbin			17
! #define Anum_pg_constraint_consrc			18
! 
  
  /* Valid values for contype */
  #define CONSTRAINT_CHECK			'c'
--- 131,157 ----
   *		compiler constants for pg_constraint
   * ----------------
   */
! #define Natts_pg_constraint					20
! #define	Anum_pg_constraint_conname			1
! #define	Anum_pg_constraint_connamespace		2
! #define	Anum_pg_constraint_contype			3
! #define	Anum_pg_constraint_condeferrable	4
! #define	Anum_pg_constraint_condeferred		5
! #define	Anum_pg_constraint_conrelid			6
! #define	Anum_pg_constraint_contypid			7
! #define	Anum_pg_constraint_confrelid		8
! #define	Anum_pg_constraint_confupdtype		9
! #define	Anum_pg_constraint_confdeltype		10
! #define	Anum_pg_constraint_confmatchtype	11
! #define	Anum_pg_constraint_conislocal		12
! #define	Anum_pg_constraint_coninhcount		13
! #define	Anum_pg_constraint_conkey			14
! #define	Anum_pg_constraint_confkey			15
! #define	Anum_pg_constraint_conpfeqop		16
! #define	Anum_pg_constraint_conppeqop		17
! #define	Anum_pg_constraint_conffeqop		18
! #define	Anum_pg_constraint_conbin			19
! #define	Anum_pg_constraint_consrc			20
  
  /* Valid values for contype */
  #define CONSTRAINT_CHECK			'c'
*************** extern Oid CreateConstraintEntry(const c
*** 192,198 ****
  					  Oid indexRelId,
  					  Node *conExpr,
  					  const char *conBin,
! 					  const char *conSrc);
  
  extern void RemoveConstraintById(Oid conId);
  extern void RenameConstraintById(Oid conId, const char *newname);
--- 199,207 ----
  					  Oid indexRelId,
  					  Node *conExpr,
  					  const char *conBin,
! 					  const char *conSrc,
! 					  const bool conIsLocal,
! 					  const int conInhCout);
  
  extern void RemoveConstraintById(Oid conId);
  extern void RenameConstraintById(Oid conId, const char *newname);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index f786f18..e5c1d65 100644
*** a/src/include/nodes/parsenodes.h
--- /bsrc/include/nodes/parsenodes.h
*************** typedef enum AlterTableType
*** 902,908 ****
  	AT_ProcessedConstraint,		/* pre-processed add constraint (local in
  								 * parser/parse_utilcmd.c) */
  	AT_DropConstraint,			/* drop constraint */
! 	AT_DropConstraintQuietly,	/* drop constraint, no error/warning (local in
  								 * commands/tablecmds.c) */
  	AT_AlterColumnType,			/* alter column type */
  	AT_ChangeOwner,				/* change owner */
--- 902,908 ----
  	AT_ProcessedConstraint,		/* pre-processed add constraint (local in
  								 * parser/parse_utilcmd.c) */
  	AT_DropConstraint,			/* drop constraint */
! 	AT_DropConstraintRecurse,	/* drop constraint recursion (local in
  								 * commands/tablecmds.c) */
  	AT_AlterColumnType,			/* alter column type */
  	AT_ChangeOwner,				/* change owner */
*************** typedef struct Constraint
*** 1165,1170 ****
--- 1165,1172 ----
  	List	   *options;		/* options from WITH clause */
  	char	   *indexspace;		/* index tablespace for PKEY/UNIQUE
  								 * constraints; NULL for default */
+ 	bool is_local;
+ 	int inhcount;
  } Constraint;
  
  /* ----------
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 76248de..b99da72 100644
*** a/src/include/utils/syscache.h
--- /bsrc/include/utils/syscache.h
***************
*** 28,81 ****
   *		Keep them in alphabetical order.
   */
  
! #define AGGFNOID			0
! #define AMNAME				1
! #define AMOID				2
! #define AMOPOPID			3
! #define AMOPSTRATEGY		4
! #define AMPROCNUM			5
! #define ATTNAME				6
! #define ATTNUM				7
! #define AUTHMEMMEMROLE		8
! #define AUTHMEMROLEMEM		9
! #define AUTHNAME			10
! #define AUTHOID				11
! #define CASTSOURCETARGET	12
! #define CLAAMNAMENSP		13
! #define CLAOID				14
! #define CONDEFAULT			15
! #define CONNAMENSP			16
! #define CONSTROID			17
! #define CONVOID				18
! #define DATABASEOID			19
! #define ENUMOID				20
! #define ENUMTYPOIDNAME		21
! #define INDEXRELID			22
! #define LANGNAME			23
! #define LANGOID				24
! #define NAMESPACENAME		25
! #define NAMESPACEOID		26
! #define OPERNAMENSP			27
! #define OPEROID				28
! #define OPFAMILYAMNAMENSP	29
! #define OPFAMILYOID			30
! #define PROCNAMEARGSNSP		31
! #define PROCOID				32
! #define RELNAMENSP			33
! #define RELOID				34
! #define RULERELNAME			35
! #define STATRELATT			36
! #define TSCONFIGMAP			37
! #define TSCONFIGNAMENSP		38
! #define TSCONFIGOID			39
! #define TSDICTNAMENSP		40
! #define TSDICTOID			41
! #define TSPARSERNAMENSP		42
! #define TSPARSEROID			43
! #define TSTEMPLATENAMENSP	44
! #define TSTEMPLATEOID		45
! #define TYPENAMENSP			46
! #define TYPEOID				47
  
  extern void InitCatalogCache(void);
  extern void InitCatalogCachePhase2(void);
--- 28,84 ----
   *		Keep them in alphabetical order.
   */
  
! enum SysCacheIdent {
! 	AGGFNOID = 0,
! 	AMNAME,
! 	AMOID,
! 	AMOPOPID,
! 	AMOPSTRATEGY,
! 	AMPROCNUM,
! 	ATTNAME,
! 	ATTNUM,
! 	AUTHMEMMEMROLE,
! 	AUTHMEMROLEMEM,
! 	AUTHNAME,
! 	AUTHOID,
! 	CASTSOURCETARGET,
! 	CLAAMNAMENSP,
! 	CLAOID,
! 	CONDEFAULT,
! 	CONNAMENSP,
! 	CONSTRNAME,
! 	CONSTROID,
! 	CONVOID,
! 	DATABASEOID,
! 	ENUMOID,
! 	ENUMTYPOIDNAME,
! 	INDEXRELID,
! 	LANGNAME,
! 	LANGOID,
! 	NAMESPACENAME,
! 	NAMESPACEOID,
! 	OPERNAMENSP,
! 	OPEROID,
! 	OPFAMILYAMNAMENSP,
! 	OPFAMILYOID,
! 	PROCNAMEARGSNSP,
! 	PROCOID,
! 	RELNAMENSP,
! 	RELOID,
! 	RULERELNAME,
! 	STATRELATT,
! 	TSCONFIGMAP,
! 	TSCONFIGNAMENSP,
! 	TSCONFIGOID,
! 	TSDICTNAMENSP,
! 	TSDICTOID,
! 	TSPARSERNAMENSP,
! 	TSPARSEROID,
! 	TSTEMPLATENAMENSP,
! 	TSTEMPLATEOID,
! 	TYPENAMENSP,
! 	TYPEOID,
! };
  
  extern void InitCatalogCache(void);
  extern void InitCatalogCachePhase2(void);
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index cba489d..58ee537 100644
*** a/src/test/regress/expected/alter_table.out
--- /bsrc/test/regress/expected/alter_table.out
*************** create table atacc1 (test int);
*** 383,391 ****
  create table atacc2 (test2 int);
  create table atacc3 (test3 int) inherits (atacc1, atacc2);
  alter table only atacc2 add constraint foo check (test2>0);
  -- fail and then succeed on atacc2
  insert into atacc2 (test2) values (-3);
- ERROR:  new row for relation "atacc2" violates check constraint "foo"
  insert into atacc2 (test2) values (3);
  -- both succeed on atacc3
  insert into atacc3 (test2) values (-3);
--- 383,391 ----
  create table atacc2 (test2 int);
  create table atacc3 (test3 int) inherits (atacc1, atacc2);
  alter table only atacc2 add constraint foo check (test2>0);
+ ERROR:  constraint must be added to child tables too
  -- fail and then succeed on atacc2
  insert into atacc2 (test2) values (-3);
  insert into atacc2 (test2) values (3);
  -- both succeed on atacc3
  insert into atacc3 (test2) values (-3);
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index f81776f..b2c684b 100644
*** a/src/test/regress/expected/inherit.out
--- /bsrc/test/regress/expected/inherit.out
*************** drop function p2text(p2);
*** 692,694 ****
--- 692,770 ----
  drop table c1;
  drop table p2;
  drop table p1;
+ CREATE TABLE ac (aa TEXT);
+ alter table ac add constraint ac_check check (aa is not null);
+ CREATE TABLE bc (bb TEXT) INHERITS (ac);
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+  conname  | contype | conislocal | coninhcount |      consrc      
+ ----------+---------+------------+-------------+------------------
+  ac_check | c       | t          |           0 | (aa IS NOT NULL)
+  ac_check | c       | f          |           1 | (aa IS NOT NULL)
+ (2 rows)
+ 
+ alter table bc drop constraint ac_check;
+ ERROR:  cannot drop inherited constraint "ac_check" of relation "bc"
+ alter table ac drop constraint ac_check;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+  conname | contype | conislocal | coninhcount | consrc 
+ ---------+---------+------------+-------------+--------
+ (0 rows)
+ 
+ alter table ac add constraint ac_check check (aa is not null);
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+  conname  | contype | conislocal | coninhcount |      consrc      
+ ----------+---------+------------+-------------+------------------
+  ac_check | c       | t          |           0 | (aa IS NOT NULL)
+  ac_check | c       | f          |           1 | (aa IS NOT NULL)
+ (2 rows)
+ 
+ insert into ac (aa) values (NULL);
+ ERROR:  new row for relation "ac" violates check constraint "ac_check"
+ insert into bc (aa) values (NULL);
+ ERROR:  new row for relation "bc" violates check constraint "ac_check"
+ alter table bc drop constraint ac_check;
+ ERROR:  cannot drop inherited constraint "ac_check" of relation "bc"
+ alter table ac drop constraint ac_check;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+  conname | contype | conislocal | coninhcount | consrc 
+ ---------+---------+------------+-------------+--------
+ (0 rows)
+ 
+ alter table ac add constraint ac_check check (aa is not null);
+ alter table bc no inherit ac;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+  conname  | contype | conislocal | coninhcount |      consrc      
+ ----------+---------+------------+-------------+------------------
+  ac_check | c       | t          |           0 | (aa IS NOT NULL)
+  ac_check | c       | t          |           0 | (aa IS NOT NULL)
+ (2 rows)
+ 
+ alter table bc drop constraint ac_check;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+  conname  | contype | conislocal | coninhcount |      consrc      
+ ----------+---------+------------+-------------+------------------
+  ac_check | c       | t          |           0 | (aa IS NOT NULL)
+ (1 row)
+ 
+ alter table ac drop constraint ac_check;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+  conname | contype | conislocal | coninhcount | consrc 
+ ---------+---------+------------+-------------+--------
+ (0 rows)
+ 
+ drop table bc;
+ drop table ac;
+ create table ac (a int constraint check_a check (a <> 0));
+ create table bc (a int constraint check_a check (a <> 0), b int constraint check_b check (b <> 0)) inherits (ac);
+ NOTICE:  merging column "a" with inherited definition
+ NOTICE:  merging constraint "check_a" with inherited definition
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+  conname | contype | conislocal | coninhcount |  consrc  
+ ---------+---------+------------+-------------+----------
+  check_a | c       | t          |           0 | (a <> 0)
+  check_b | c       | t          |           0 | (b <> 0)
+  check_a | c       | f          |           1 | (a <> 0)
+ (3 rows)
+ 
+ drop table bc;
+ drop table ac;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index b0499a6..9c17849 100644
*** a/src/test/regress/sql/inherit.sql
--- /bsrc/test/regress/sql/inherit.sql
*************** drop function p2text(p2);
*** 196,198 ****
--- 196,236 ----
  drop table c1;
  drop table p2;
  drop table p1;
+ 
+ CREATE TABLE ac (aa TEXT);
+ alter table ac add constraint ac_check check (aa is not null);
+ CREATE TABLE bc (bb TEXT) INHERITS (ac);
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+ 
+ alter table bc drop constraint ac_check;
+ alter table ac drop constraint ac_check;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+ 
+ alter table ac add constraint ac_check check (aa is not null);
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+ 
+ insert into ac (aa) values (NULL);
+ insert into bc (aa) values (NULL);
+ 
+ alter table bc drop constraint ac_check;
+ alter table ac drop constraint ac_check;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+ 
+ alter table ac add constraint ac_check check (aa is not null);
+ alter table bc no inherit ac;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+ alter table bc drop constraint ac_check;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+ alter table ac drop constraint ac_check;
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+ 
+ drop table bc;
+ drop table ac;
+ 
+ create table ac (a int constraint check_a check (a <> 0));
+ create table bc (a int constraint check_a check (a <> 0), b int constraint check_b check (b <> 0)) inherits (ac);
+ select pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.consrc from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname in ('ac', 'bc') order by pc.relname;
+ 
+ 
+ drop table bc;
+ drop table ac;
