diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index d948ed487c6961ee36613839bb4fdb465b51710e..be4bbc736c745aefb0c6a3b757c91aadc6b7e8e9 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -2036,6 +2036,16 @@
       </entry>
      </row>
 
+     <row>
+      <entry><structfield>conisonly</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>
+       This constraint is defined locally for the relation.  It is a
+       non-inheritable constraint.
+      </entry>
+     </row>
+
      <row>
       <entry><structfield>conkey</structfield></entry>
       <entry><type>int2[]</type></entry>
diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml
index 00a477ef885d9338d23830aa057776f1c1830019..3b111a4c2b90a843a7411f1e7d0dddaf06e677cc 100644
--- a/doc/src/sgml/ref/alter_table.sgml
+++ b/doc/src/sgml/ref/alter_table.sgml
@@ -983,6 +983,14 @@ ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
 </programlisting>
   </para>
 
+  <para>
+   To add a check constraint only to a table and not to its children:
+<programlisting>
+ALTER TABLE ONLY distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
+</programlisting>
+   (The check constraint will not be inherited by future children, either.)
+  </para>
+
   <para>
    To remove a check constraint from a table and all its children:
 <programlisting>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e11d896ec8cd3a15f33393cf7f2b517520860890..2f6a6ffba170f864cd1ae05833ffd3117cc02a24 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -92,10 +92,10 @@ static Oid AddNewRelationType(const char *typeName,
 				   Oid new_array_type);
 static void RelationRemoveInheritance(Oid relid);
 static void StoreRelCheck(Relation rel, char *ccname, Node *expr,
-			  bool is_validated, bool is_local, int inhcount);
+			  bool is_validated, bool is_local, int inhcount, bool is_only);
 static void StoreConstraints(Relation rel, List *cooked_constraints);
 static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
-							bool allow_merge, bool is_local);
+							bool allow_merge, bool is_local, bool is_only);
 static void SetRelationNumChecks(Relation rel, int numchecks);
 static Node *cookConstraint(ParseState *pstate,
 			   Node *raw_constraint,
@@ -1859,7 +1859,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr)
  */
 static void
 StoreRelCheck(Relation rel, char *ccname, Node *expr,
-			  bool is_validated, bool is_local, int inhcount)
+			  bool is_validated, bool is_local, int inhcount, bool is_only)
 {
 	char	   *ccbin;
 	char	   *ccsrc;
@@ -1942,7 +1942,8 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
 						  ccbin,	/* Binary form of check constraint */
 						  ccsrc,	/* Source form of check constraint */
 						  is_local,		/* conislocal */
-						  inhcount);	/* coninhcount */
+						  inhcount,		/* coninhcount */
+						  is_only);		/* conisonly */
 
 	pfree(ccbin);
 	pfree(ccsrc);
@@ -1983,7 +1984,7 @@ StoreConstraints(Relation rel, List *cooked_constraints)
 				break;
 			case CONSTR_CHECK:
 				StoreRelCheck(rel, con->name, con->expr, !con->skip_validation,
-							  con->is_local, con->inhcount);
+							  con->is_local, con->inhcount, con->is_only);
 				numchecks++;
 				break;
 			default:
@@ -2026,7 +2027,8 @@ AddRelationNewConstraints(Relation rel,
 						  List *newColDefaults,
 						  List *newConstraints,
 						  bool allow_merge,
-						  bool is_local)
+						  bool is_local,
+						  bool is_only)
 {
 	List	   *cookedConstraints = NIL;
 	TupleDesc	tupleDesc;
@@ -2099,6 +2101,7 @@ AddRelationNewConstraints(Relation rel,
 		cooked->skip_validation = false;
 		cooked->is_local = is_local;
 		cooked->inhcount = is_local ? 0 : 1;
+		cooked->is_only = is_only;
 		cookedConstraints = lappend(cookedConstraints, cooked);
 	}
 
@@ -2166,7 +2169,7 @@ AddRelationNewConstraints(Relation rel,
 			 * what ATAddCheckConstraint wants.)
 			 */
 			if (MergeWithExistingConstraint(rel, ccname, expr,
-											allow_merge, is_local))
+								allow_merge, is_local, is_only))
 				continue;
 		}
 		else
@@ -2213,7 +2216,7 @@ AddRelationNewConstraints(Relation rel,
 		 * OK, store it.
 		 */
 		StoreRelCheck(rel, ccname, expr, !cdef->skip_validation, is_local,
-					  is_local ? 0 : 1);
+					  is_local ? 0 : 1, is_only);
 
 		numchecks++;
 
@@ -2225,6 +2228,7 @@ AddRelationNewConstraints(Relation rel,
 		cooked->skip_validation = cdef->skip_validation;
 		cooked->is_local = is_local;
 		cooked->inhcount = is_local ? 0 : 1;
+		cooked->is_only = is_only;
 		cookedConstraints = lappend(cookedConstraints, cooked);
 	}
 
@@ -2250,7 +2254,8 @@ AddRelationNewConstraints(Relation rel,
  */
 static bool
 MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
-							bool allow_merge, bool is_local)
+							bool allow_merge, bool is_local,
+							bool is_only)
 {
 	bool		found;
 	Relation	conDesc;
@@ -2312,6 +2317,11 @@ MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
 				con->conislocal = true;
 			else
 				con->coninhcount++;
+			if (is_only)
+			{
+				Assert(is_local);
+				con->conisonly = true;
+			}
 			simple_heap_update(conDesc, &tup->t_self, tup);
 			CatalogUpdateIndexes(conDesc, tup);
 			break;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 758872ff4eda584ab4f269c768226e10079ddf08..f9075c4752dfa1ea734524277be8d5bf78a01b4e 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1155,7 +1155,8 @@ index_constraint_create(Relation heapRelation,
 								   NULL,
 								   NULL,
 								   true,		/* islocal */
-								   0);	/* inhcount */
+								   0,			/* inhcount */
+								   false);		/* isonly */
 
 	/*
 	 * Register the index as internally dependent on the constraint.
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 69979942af42a00922fb4bce3ada1fa622dd2212..cfe82ea3a8c86df948c61bb328d8cfc6a3734ebf 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -66,7 +66,8 @@ CreateConstraintEntry(const char *constraintName,
 					  const char *conBin,
 					  const char *conSrc,
 					  bool conIsLocal,
-					  int conInhCount)
+					  int conInhCount,
+					  bool conIsOnly)
 {
 	Relation	conDesc;
 	Oid			conOid;
@@ -169,6 +170,7 @@ CreateConstraintEntry(const char *constraintName,
 	values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
 	values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
 	values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
+	values[Anum_pg_constraint_conisonly - 1] = BoolGetDatum(conIsOnly);
 
 	if (conkeyArray)
 		values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 135736a8dc64c8404060a9d6e225e6e9f6463800..00b6cb9d50dda8277dd4291648a2579a4f361a98 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -579,6 +579,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
 			cooked->skip_validation = false;
 			cooked->is_local = true;	/* not used for defaults */
 			cooked->inhcount = 0;		/* ditto */
+			cooked->is_only = false;
 			cookedDefaults = lappend(cookedDefaults, cooked);
 			descriptor->attrs[attnum - 1]->atthasdef = true;
 		}
@@ -638,7 +639,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
 	 */
 	if (rawDefaults || stmt->constraints)
 		AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
-								  true, true);
+								  true, true, false);
 
 	/*
 	 * Clean up.  We keep lock on new relation (although it shouldn't be
@@ -1599,6 +1600,10 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 				char	   *name = check[i].ccname;
 				Node	   *expr;
 
+				/* ignore if the constraint is non-inheritable */
+				if (check[i].cconly)
+					continue;
+
 				/* adjust varattnos of ccbin here */
 				expr = stringToNode(check[i].ccbin);
 				change_varattnos_of_a_node(expr, newattno);
@@ -1617,6 +1622,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 					cooked->skip_validation = false;
 					cooked->is_local = false;
 					cooked->inhcount = 1;
+					cooked->is_only = false;
 					constraints = lappend(constraints, cooked);
 				}
 			}
@@ -4501,7 +4507,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 		 * This function is intended for CREATE TABLE, so it processes a
 		 * _list_ of defaults, but we just do one.
 		 */
-		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true);
+		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true, false);
 
 		/* Make the additional catalog changes visible */
 		CommandCounterIncrement();
@@ -4898,7 +4904,7 @@ ATExecColumnDefault(Relation rel, const char *colName,
 		 * This function is intended for CREATE TABLE, so it processes a
 		 * _list_ of defaults, but we just do one.
 		 */
-		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true);
+		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true, false);
 	}
 }
 
@@ -5562,10 +5568,16 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	 * omitted from the returned list, which is what we want: we do not need
 	 * to do any validation work.  That can only happen at child tables,
 	 * though, since we disallow merging at the top level.
+	 *
+	 * Note: we set is_only based on the recurse flag which is false when
+	 * interpretInhOption() of our statement returns false all the way up
+	 * in AlterTable and gets passed all the way down to here.
 	 */
 	newcons = AddRelationNewConstraints(rel, NIL,
 										list_make1(copyObject(constr)),
-										recursing, !recursing);
+										recursing, /* allow_merge */
+										!recursing, /* is_local */
+										!recurse && !recursing); /* is_only */
 
 	/* Add each to-be-validated constraint to Phase 3's queue */
 	foreach(lcon, newcons)
@@ -5605,6 +5617,12 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	if (newcons == NIL)
 		return;
 
+	/*
+	 * Adding an ONLY constraint? No need to find our children
+	 */
+	if (!recurse && !recursing)
+		return;
+
 	/*
 	 * 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
@@ -5612,15 +5630,6 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	 */
 	children = find_inheritance_children(RelationGetRelid(rel), lockmode);
 
-	/*
-	 * 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 (children && !recurse)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-				 errmsg("constraint must be added to child tables too")));
-
 	foreach(child, children)
 	{
 		Oid			childrelid = lfirst_oid(child);
@@ -5914,7 +5923,8 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 									  NULL,
 									  NULL,
 									  true,		/* islocal */
-									  0);		/* inhcount */
+									  0,		/* inhcount */
+									  false);	/* isonly */
 
 	/*
 	 * Create the triggers that will enforce the constraint.
@@ -6755,6 +6765,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 	HeapTuple	tuple;
 	bool		found = false;
 	bool		is_check_constraint = false;
+	bool		is_only_constraint = false;
 
 	/* At top level, permission check was done in ATPrepCmd, else do it */
 	if (recursing)
@@ -6791,6 +6802,12 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 		/* Right now only CHECK constraints can be inherited */
 		if (con->contype == CONSTRAINT_CHECK)
 			is_check_constraint = true;
+		
+		if (con->conisonly)
+		{
+			Assert(is_check_constraint);
+			is_only_constraint = true;
+		}
 
 		/*
 		 * Perform the actual constraint deletion
@@ -6802,6 +6819,9 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 		performDeletion(&conobj, behavior);
 
 		found = true;
+
+		/* constraint found and dropped -- no need to keep looping */
+		break;
 	}
 
 	systable_endscan(scan);
@@ -6830,7 +6850,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 	 * 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.
 	 */
-	if (is_check_constraint)
+	if (is_check_constraint && !is_only_constraint)
 		children = find_inheritance_children(RelationGetRelid(rel), lockmode);
 	else
 		children = NIL;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index f4c93e5b25460be7c06543e2ecb754deed753eeb..eb5114079ad7248542066eff4a32ec2a88799ed8 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -449,7 +449,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 											  NULL,
 											  NULL,
 											  true,		/* islocal */
-											  0);		/* inhcount */
+											  0,		/* inhcount */
+											  false);	/* isonly */
 	}
 
 	/*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 2b8f9aec38400b3c7525b09313a7bd9f0e6de332..eda43d826fa29ce783487a7d0d1c568a5d8245cc 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2934,7 +2934,8 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
 						  ccbin,	/* Binary form of check constraint */
 						  ccsrc,	/* Source form of check constraint */
 						  true, /* is local */
-						  0);	/* inhcount */
+						  0,	/* inhcount */
+						  false);	/* is only */
 
 	/*
 	 * Return the compiled constraint expression so the calling routine can
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 603e4c1b621ba672a1f1b1088e78f83cf18f4bd5..f9ad75e7f8901261fa9b1d988ba3c57dc81dd1e5 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3261,6 +3261,7 @@ CheckConstraintFetch(Relation relation)
 				 RelationGetRelationName(relation));
 
 		check[found].ccvalid = conform->convalidated;
+		check[found].cconly	= conform->conisonly;
 		check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
 												  NameStr(conform->conname));
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 7dfa1dd8f8a2dcc60cbf500c080c259d53776f7a..5deb9d658d8ece96f069846e06835afaeb38b14a 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -6019,11 +6019,16 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 						  tbinfo->dobj.name);
 
 			resetPQExpBuffer(q);
-			if (g_fout->remoteVersion >= 90100)
+			if (g_fout->remoteVersion >= 90200)
 			{
+				/*
+				 * conisonly and convalidated are new in 9.2 (actually, the latter
+				 * is there in 9.1, but it wasn't ever false for check constraints
+				 * until 9.2).
+				 */
 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
 						   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
-								  "conislocal, convalidated "
+								  "conislocal, convalidated, conisonly "
 								  "FROM pg_catalog.pg_constraint "
 								  "WHERE conrelid = '%u'::pg_catalog.oid "
 								  "   AND contype = 'c' "
@@ -6034,7 +6039,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 			{
 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
 						   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
-								  "conislocal, true AS convalidated "
+								  "conislocal, true AS convalidated, "
+								  "false as conisonly "
 								  "FROM pg_catalog.pg_constraint "
 								  "WHERE conrelid = '%u'::pg_catalog.oid "
 								  "   AND contype = 'c' "
@@ -6045,7 +6051,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 			{
 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
 						   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
-								  "true AS conislocal, true AS convalidated "
+								  "true AS conislocal, true AS convalidated, "
+								  "false as conisonly "
 								  "FROM pg_catalog.pg_constraint "
 								  "WHERE conrelid = '%u'::pg_catalog.oid "
 								  "   AND contype = 'c' "
@@ -6057,7 +6064,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 				/* no pg_get_constraintdef, must use consrc */
 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
 								  "'CHECK (' || consrc || ')' AS consrc, "
-								  "true AS conislocal, true AS convalidated "
+								  "true AS conislocal, true AS convalidated, "
+								  "false as conisonly "
 								  "FROM pg_catalog.pg_constraint "
 								  "WHERE conrelid = '%u'::pg_catalog.oid "
 								  "   AND contype = 'c' "
@@ -6070,7 +6078,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 				appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
 								  "rcname AS conname, "
 								  "'CHECK (' || rcsrc || ')' AS consrc, "
-								  "true AS conislocal, true AS convalidated "
+								  "true AS conislocal, true AS convalidated, "
+								  "false as conisonly "
 								  "FROM pg_relcheck "
 								  "WHERE rcrelid = '%u'::oid "
 								  "ORDER BY rcname",
@@ -6081,7 +6090,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 				appendPQExpBuffer(q, "SELECT tableoid, oid, "
 								  "rcname AS conname, "
 								  "'CHECK (' || rcsrc || ')' AS consrc, "
-								  "true AS conislocal, true AS convalidated "
+								  "true AS conislocal, true AS convalidated, "
+								  "false as conisonly "
 								  "FROM pg_relcheck "
 								  "WHERE rcrelid = '%u'::oid "
 								  "ORDER BY rcname",
@@ -6094,7 +6104,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 								  "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
 								  "oid, rcname AS conname, "
 								  "'CHECK (' || rcsrc || ')' AS consrc, "
-								  "true AS conislocal, true AS convalidated "
+								  "true AS conislocal, true AS convalidated, "
+								  "false as conisonly "
 								  "FROM pg_relcheck "
 								  "WHERE rcrelid = '%u'::oid "
 								  "ORDER BY rcname",
@@ -6120,6 +6131,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 			for (j = 0; j < numConstrs; j++)
 			{
 				bool	validated = PQgetvalue(res, j, 5)[0] == 't';
+				bool	isonly = PQgetvalue(res, j, 6)[0] == 't';
 
 				constrs[j].dobj.objType = DO_CONSTRAINT;
 				constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
@@ -6136,12 +6148,14 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 				constrs[j].condeferrable = false;
 				constrs[j].condeferred = false;
 				constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
+				constrs[j].conisonly = isonly;
 				/*
 				 * An unvalidated constraint needs to be dumped separately, so
 				 * that potentially-violating existing data is loaded before
-				 * the constraint.
+				 * the constraint.  An ONLY constraint needs to be dumped
+				 * separately too.
 				 */
-				constrs[j].separate = !validated;
+				constrs[j].separate = !validated || isonly;
 
 				constrs[j].dobj.dump = tbinfo->dobj.dump;
 
@@ -6149,12 +6163,12 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 				 * Mark the constraint as needing to appear before the table
 				 * --- this is so that any other dependencies of the
 				 * constraint will be emitted before we try to create the
-				 * table.  If the constraint is not validated, it will be
+				 * table.  If the constraint is to be dumped separately, it will be
 				 * dumped after data is loaded anyway, so don't do it.  (There's
 				 * an automatic dependency in the opposite direction anyway, so
 				 * don't need to add one manually here.)
 				 */
-				if (validated)
+				if (!constrs[j].separate)
 					addObjectDependency(&tbinfo->dobj,
 										constrs[j].dobj.dumpId);
 
@@ -13193,9 +13207,9 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		/* Ignore if not to be dumped separately */
 		if (coninfo->separate)
 		{
-			/* not ONLY since we want it to propagate to children */
-			appendPQExpBuffer(q, "ALTER TABLE %s\n",
-							  fmtId(tbinfo->dobj.name));
+			/* add ONLY if we do not want it to propagate to children */
+			appendPQExpBuffer(q, "ALTER TABLE %s %s\n",
+							 coninfo->conisonly ? "ONLY" : "", fmtId(tbinfo->dobj.name));
 			appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
 							  fmtId(coninfo->dobj.name),
 							  coninfo->condef);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 31442f1622d76442fdee07d7ece7adb7a0469075..3bfeb317d6e05a4163d8efdefa82dd833ba8d6b0 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -378,6 +378,7 @@ typedef struct _constraintInfo
 	bool		condeferrable;	/* TRUE if constraint is DEFERRABLE */
 	bool		condeferred;	/* TRUE if constraint is INITIALLY DEFERRED */
 	bool		conislocal;		/* TRUE if constraint has local definition */
+	bool		conisonly;		/* TRUE if constraint is non-inheritable */
 	bool		separate;		/* TRUE if must dump as separate item */
 } ConstraintInfo;
 
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index dcafdd2c1aed1b18097f85a112b7414071f138ad..b6aeae22e5d1a5781e0578b35e136df0660c976b 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1781,12 +1781,20 @@ describeOneTableDetails(const char *schemaname,
 		/* print table (and column) check constraints */
 		if (tableinfo.checks)
 		{
+			char *is_only;
+
+			if (pset.sversion >= 90200)
+				is_only = "r.conisonly";
+			else
+				is_only = "false AS conisonly";
+
 			printfPQExpBuffer(&buf,
-							  "SELECT r.conname, "
+							  "SELECT r.conname, %s, "
 							  "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
 							  "FROM pg_catalog.pg_constraint r\n"
-				   "WHERE r.conrelid = '%s' AND r.contype = 'c'\nORDER BY 1;",
-							  oid);
+				   "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
+				   			  "ORDER BY 2 DESC, 1;",
+							  is_only, oid);
 			result = PSQLexec(buf.data, false);
 			if (!result)
 				goto error_return;
@@ -1799,9 +1807,10 @@ describeOneTableDetails(const char *schemaname,
 				for (i = 0; i < tuples; i++)
 				{
 					/* untranslated contraint name and def */
-					printfPQExpBuffer(&buf, "    \"%s\" %s",
+					printfPQExpBuffer(&buf, "    \"%s\"%s%s",
 									  PQgetvalue(result, i, 0),
-									  PQgetvalue(result, i, 1));
+									  (strcmp(PQgetvalue(result, i, 1), "t") == 0) ? " (ONLY) ":" ",
+									  PQgetvalue(result, i, 2));
 
 					printTableAddFooter(&cont, buf.data);
 				}
diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h
index 8b99cb849d8e201eef69de535607c485ed4e39e5..d5e1333d03933931ba6a3bbf45b6b4cde8130a2a 100644
--- a/src/include/access/tupdesc.h
+++ b/src/include/access/tupdesc.h
@@ -30,6 +30,7 @@ typedef struct constrCheck
 	char	   *ccname;
 	char	   *ccbin;			/* nodeToString representation of expr */
 	bool		ccvalid;
+	bool		cconly;			/* this is a non-inheritable constraint */
 } ConstrCheck;
 
 /* This structure contains constraints of a tuple */
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index aee2d88ebe233609d914d1e6adc070543c6830b5..07938137dece713cd168991f39e861c4e44d1421 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -33,6 +33,7 @@ typedef struct CookedConstraint
 	bool		skip_validation;	/* skip validation? (only for CHECK) */
 	bool		is_local;		/* constraint has local (non-inherited) def */
 	int			inhcount;		/* number of times constraint is inherited */
+	bool		is_only;		/* constraint has local def and cannot be inherited */
 } CookedConstraint;
 
 extern Relation heap_create(const char *relname,
@@ -91,7 +92,8 @@ extern List *AddRelationNewConstraints(Relation rel,
 						  List *newColDefaults,
 						  List *newConstraints,
 						  bool allow_merge,
-						  bool is_local);
+						  bool is_local,
+						  bool is_only);
 
 extern void StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr);
 
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 1566af2973549f7a9b2c9fd8de34b004ca41b105..dae42e8e5fb64e00c0979983bbe8ea7639f6e5f9 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -88,6 +88,9 @@ CATALOG(pg_constraint,2606)
 	/* Number of times inherited from direct parent relation(s) */
 	int4		coninhcount;
 
+	/* Has a local definition and cannot be inherited */
+	bool		conisonly;
+
 	/*
 	 * VARIABLE LENGTH FIELDS start here.  These fields may be NULL, too.
 	 */
@@ -149,7 +152,7 @@ typedef FormData_pg_constraint *Form_pg_constraint;
  *		compiler constants for pg_constraint
  * ----------------
  */
-#define Natts_pg_constraint					23
+#define Natts_pg_constraint					24
 #define Anum_pg_constraint_conname			1
 #define Anum_pg_constraint_connamespace		2
 #define Anum_pg_constraint_contype			3
@@ -165,14 +168,15 @@ typedef FormData_pg_constraint *Form_pg_constraint;
 #define Anum_pg_constraint_confmatchtype	13
 #define Anum_pg_constraint_conislocal		14
 #define Anum_pg_constraint_coninhcount		15
-#define Anum_pg_constraint_conkey			16
-#define Anum_pg_constraint_confkey			17
-#define Anum_pg_constraint_conpfeqop		18
-#define Anum_pg_constraint_conppeqop		19
-#define Anum_pg_constraint_conffeqop		20
-#define Anum_pg_constraint_conexclop		21
-#define Anum_pg_constraint_conbin			22
-#define Anum_pg_constraint_consrc			23
+#define Anum_pg_constraint_conisonly		16
+#define Anum_pg_constraint_conkey			17
+#define Anum_pg_constraint_confkey			18
+#define Anum_pg_constraint_conpfeqop		19
+#define Anum_pg_constraint_conppeqop		20
+#define Anum_pg_constraint_conffeqop		21
+#define Anum_pg_constraint_conexclop		22
+#define Anum_pg_constraint_conbin			23
+#define Anum_pg_constraint_consrc			24
 
 
 /* Valid values for contype */
@@ -227,7 +231,8 @@ extern Oid CreateConstraintEntry(const char *constraintName,
 					  const char *conBin,
 					  const char *conSrc,
 					  bool conIsLocal,
-					  int conInhCount);
+					  int conInhCount,
+					  bool conIsOnly);
 
 extern void RemoveConstraintById(Oid conId);
 extern void RenameConstraintById(Oid conId, const char *newname);
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 87432a8538108dd3571c4267fc04e79fbe0a5ad5..57096f230ebadac358a9d5058ff452b04d8b4431 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -498,22 +498,21 @@ select test2 from atacc2;
 drop table atacc2 cascade;
 NOTICE:  drop cascades to table atacc3
 drop table atacc1;
--- adding only to a parent is disallowed as of 8.4
+-- adding only to a parent is allowed as of 9.2
 create table atacc1 (test int);
 create table atacc2 (test2 int) inherits (atacc1);
--- fail:
-alter table only atacc1 add constraint foo check (test>0);
-ERROR:  constraint must be added to child tables too
 -- ok:
-alter table only atacc2 add constraint foo check (test>0);
--- check constraint not there on parent
+alter table only atacc1 add constraint foo check (test>0);
+-- check constraint is not there on child
+insert into atacc2 (test) values (-3);
+-- check constraint is there on parent
 insert into atacc1 (test) values (-3);
+ERROR:  new row for relation "atacc1" violates check constraint "foo"
+DETAIL:  Failing row contains (-3).
 insert into atacc1 (test) values (3);
--- check constraint is there on child
-insert into atacc2 (test) values (-3);
-ERROR:  new row for relation "atacc2" violates check constraint "foo"
-DETAIL:  Failing row contains (-3, null).
-insert into atacc2 (test) values (3);
+-- fail, violating row:
+alter table only atacc2 add constraint foo check (test>0);
+ERROR:  check constraint "foo" is violated by some row
 drop table atacc2;
 drop table atacc1;
 -- test unique constraint adding
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index d958da2652682b8bc9a5dc087b2a4ebcef9337a4..309c1db425eb183ccc6b660e81ac98eb84bf4317 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -683,6 +683,41 @@ select * from d;
  32 | one | two | three
 (1 row)
 
+-- Test non-inheritable parent constraints
+create table p1(ff1 int);
+alter table only p1 add constraint p1chk check (ff1 > 0);
+alter table p1 add constraint p2chk check (ff1 > 10);
+-- conisonly should be true for ONLY constraint
+select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.conisonly from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1';
+ relname | conname | contype | conislocal | coninhcount | conisonly 
+---------+---------+---------+------------+-------------+-----------
+ p1      | p1chk   | c       | t          |           0 | t
+ p1      | p2chk   | c       | t          |           0 | f
+(2 rows)
+
+-- Test that child does not inherit ONLY constraints
+create table c1 () inherits (p1);
+\d p1
+      Table "public.p1"
+ Column |  Type   | Modifiers 
+--------+---------+-----------
+ ff1    | integer | 
+Check constraints:
+    "p1chk" (ONLY) CHECK (ff1 > 0)
+    "p2chk" CHECK (ff1 > 10)
+Number of child tables: 1 (Use \d+ to list them.)
+
+\d c1
+      Table "public.c1"
+ Column |  Type   | Modifiers 
+--------+---------+-----------
+ ff1    | integer | 
+Check constraints:
+    "p2chk" CHECK (ff1 > 10)
+Inherits: p1
+
+drop table p1 cascade;
+NOTICE:  drop cascades to table c1
 -- Tests for casting between the rowtypes of parent and child
 -- tables. See the pgsql-hackers thread beginning Dec. 4/04
 create table base (i integer);
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index a477f0401b4651de7fdad6cef10c5bd55abf2830..faafb224ef43f62e5e61fcfafe1f2af24ffbe04b 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -450,20 +450,19 @@ select test2 from atacc2;
 drop table atacc2 cascade;
 drop table atacc1;
 
--- adding only to a parent is disallowed as of 8.4
+-- adding only to a parent is allowed as of 9.2
 
 create table atacc1 (test int);
 create table atacc2 (test2 int) inherits (atacc1);
--- fail:
-alter table only atacc1 add constraint foo check (test>0);
 -- ok:
-alter table only atacc2 add constraint foo check (test>0);
--- check constraint not there on parent
+alter table only atacc1 add constraint foo check (test>0);
+-- check constraint is not there on child
+insert into atacc2 (test) values (-3);
+-- check constraint is there on parent
 insert into atacc1 (test) values (-3);
 insert into atacc1 (test) values (3);
--- check constraint is there on child
-insert into atacc2 (test) values (-3);
-insert into atacc2 (test) values (3);
+-- fail, violating row:
+alter table only atacc2 add constraint foo check (test>0);
 drop table atacc2;
 drop table atacc1;
 
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index deda5a519ef6d7b6f678bb7b952bfbd6478b2c96..6914404023667476aaa96a65b61d448aa4bb401e 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -188,6 +188,20 @@ insert into d values('test','one','two','three');
 alter table a alter column aa type integer using bit_length(aa);
 select * from d;
 
+-- Test non-inheritable parent constraints
+create table p1(ff1 int);
+alter table only p1 add constraint p1chk check (ff1 > 0);
+alter table p1 add constraint p2chk check (ff1 > 10);
+-- conisonly should be true for ONLY constraint
+select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.conisonly from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1';
+
+-- Test that child does not inherit ONLY constraints
+create table c1 () inherits (p1);
+\d p1
+\d c1
+
+drop table p1 cascade;
+
 -- Tests for casting between the rowtypes of parent and child
 -- tables. See the pgsql-hackers thread beginning Dec. 4/04
 create table base (i integer);