diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index e0b9dec..75b03d2 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -127,7 +127,9 @@ static void get_range_key_properties(PartitionKey key, int keynum,
 						 Expr **keyCol,
 						 Const **lower_val, Const **upper_val);
 static List *get_qual_for_list(Relation parent, PartitionBoundSpec *spec);
-static List *get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec);
+static List *get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
+				   bool for_default);
+static List *get_range_nulltest(PartitionKey key);
 static List *generate_partition_qual(Relation rel);
 
 static PartitionRangeBound *make_one_range_bound(PartitionKey key, int index,
@@ -168,11 +170,11 @@ RelationBuildPartitionDesc(Relation rel)
 	MemoryContext oldcxt;
 
 	int			ndatums = 0;
+	int			default_index = -1;
 
 	/* List partitioning specific */
 	PartitionListValue **all_values = NULL;
 	int			null_index = -1;
-	int			default_index = -1;
 
 	/* Range partitioning specific */
 	PartitionRangeBound **rbounds = NULL;
@@ -322,21 +324,18 @@ RelationBuildPartitionDesc(Relation rel)
 		}
 		else if (key->strategy == PARTITION_STRATEGY_RANGE)
 		{
-			int			j,
-						k;
+			int			k;
 			PartitionRangeBound **all_bounds,
 					   *prev;
-			bool	   *distinct_indexes;
 
 			all_bounds = (PartitionRangeBound **) palloc0(2 * nparts *
 														  sizeof(PartitionRangeBound *));
-			distinct_indexes = (bool *) palloc(2 * nparts * sizeof(bool));
 
 			/*
 			 * Create a unified list of range bounds across all the
 			 * partitions.
 			 */
-			i = j = 0;
+			i = ndatums = 0;
 			foreach(cell, boundspecs)
 			{
 				PartitionBoundSpec *spec = castNode(PartitionBoundSpec,
@@ -347,30 +346,41 @@ RelationBuildPartitionDesc(Relation rel)
 				if (spec->strategy != PARTITION_STRATEGY_RANGE)
 					elog(ERROR, "invalid strategy in partition bound spec");
 
+				/*
+				 * Note the index of the partition bound spec for the default
+				 * partition. There's no datum to add to the allbounds array
+				 * for this partition.
+				 */
+				if (spec->is_default)
+				{
+					default_index = i++;
+					continue;
+				}
+
 				lower = make_one_range_bound(key, i, spec->lowerdatums,
 											 true);
 				upper = make_one_range_bound(key, i, spec->upperdatums,
 											 false);
-				all_bounds[j] = lower;
-				all_bounds[j + 1] = upper;
-				j += 2;
+				all_bounds[ndatums++] = lower;
+				all_bounds[ndatums++] = upper;
 				i++;
 			}
-			Assert(j == 2 * nparts);
+
+			Assert(ndatums == nparts * 2 ||
+				   (default_index != -1 && ndatums == (nparts - 1) * 2));
 
 			/* Sort all the bounds in ascending order */
-			qsort_arg(all_bounds, 2 * nparts,
+			qsort_arg(all_bounds, ndatums,
 					  sizeof(PartitionRangeBound *),
 					  qsort_partition_rbound_cmp,
 					  (void *) key);
 
-			/*
-			 * Count the number of distinct bounds to allocate an array of
-			 * that size.
-			 */
-			ndatums = 0;
+			/* Pick out distinct datums and store it in a new array. */
+			rbounds = (PartitionRangeBound **) palloc(ndatums *
+													  sizeof(PartitionRangeBound *));
+			k = 0;
 			prev = NULL;
-			for (i = 0; i < 2 * nparts; i++)
+			for (i = 0; i < ndatums; i++)
 			{
 				PartitionRangeBound *cur = all_bounds[i];
 				bool		is_distinct = false;
@@ -407,34 +417,17 @@ RelationBuildPartitionDesc(Relation rel)
 				}
 
 				/*
-				 * Count the current bound if it is distinct from the previous
-				 * one.  Also, store if the index i contains a distinct bound
-				 * that we'd like put in the relcache array.
+				 * If distinct, save into array from where they will be copied
+				 * into the relcache.
 				 */
 				if (is_distinct)
-				{
-					distinct_indexes[i] = true;
-					ndatums++;
-				}
-				else
-					distinct_indexes[i] = false;
+					rbounds[k++] = all_bounds[i];
 
 				prev = cur;
 			}
 
-			/*
-			 * Finally save them in an array from where they will be copied
-			 * into the relcache.
-			 */
-			rbounds = (PartitionRangeBound **) palloc(ndatums *
-													  sizeof(PartitionRangeBound *));
-			k = 0;
-			for (i = 0; i < 2 * nparts; i++)
-			{
-				if (distinct_indexes[i])
-					rbounds[k++] = all_bounds[i];
-			}
-			Assert(k == ndatums);
+			/* Update ndatums to hold the count of distinct datums. */
+			ndatums = k;
 		}
 		else
 			elog(ERROR, "unexpected partition strategy: %d",
@@ -581,6 +574,14 @@ RelationBuildPartitionDesc(Relation rel)
 							boundinfo->indexes[i] = mapping[orig_index];
 						}
 					}
+
+					/* Assign mapped index for the default partition. */
+					if (default_index != -1)
+					{
+						Assert(default_index >= 0 && mapping[default_index] == -1);
+						mapping[default_index] = next_index++;
+						boundinfo->default_index = mapping[default_index];
+					}
 					boundinfo->indexes[i] = -1;
 					break;
 				}
@@ -787,8 +788,10 @@ check_new_partition_bound(char *relname, Relation parent,
 					int			offset;
 					bool		equal;
 
-					Assert(boundinfo && boundinfo->ndatums > 0 &&
-						   boundinfo->strategy == PARTITION_STRATEGY_RANGE);
+					Assert(boundinfo &&
+						   boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
+						   (boundinfo->ndatums > 0 ||
+							partition_bound_has_default(boundinfo)));
 
 					/*
 					 * Test whether the new lower bound (which is treated
@@ -880,10 +883,10 @@ check_default_allows_bound(Relation parent, Relation default_rel,
 	List	   *all_parts;
 	ListCell   *lc;
 
-	/* Currently default partition is supported only for LIST partition. */
-	Assert(new_spec->strategy == PARTITION_STRATEGY_LIST);
 
-	new_part_constraints = get_qual_for_list(parent, new_spec);
+	new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
+		? get_qual_for_list(parent, new_spec)
+		: get_qual_for_range(parent, new_spec, false);
 	def_part_constraints =
 		get_default_part_validation_constraint(new_part_constraints);
 
@@ -1083,7 +1086,7 @@ get_qual_from_partbound(Relation rel, Relation parent,
 
 		case PARTITION_STRATEGY_RANGE:
 			Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
-			my_qual = get_qual_for_range(key, spec);
+			my_qual = get_qual_for_range(parent, spec, false);
 			break;
 
 		default:
@@ -1706,6 +1709,53 @@ get_range_key_properties(PartitionKey key, int keynum,
 		*upper_val = NULL;
 }
 
+ /*
+  * get_range_nulltest
+  *
+  * A non-default range partition table does not currently allow partition
+  * keys to be null, so emit an IS NOT NULL expression for each key column.
+  */
+static List *
+get_range_nulltest(PartitionKey key)
+{
+	List	   *result = NIL;
+	NullTest   *nulltest;
+	ListCell   *partexprs_item;
+	int			i;
+
+	partexprs_item = list_head(key->partexprs);
+	for (i = 0; i < key->partnatts; i++)
+	{
+		Expr	   *keyCol;
+
+		if (key->partattrs[i] != 0)
+		{
+			keyCol = (Expr *) makeVar(1,
+									  key->partattrs[i],
+									  key->parttypid[i],
+									  key->parttypmod[i],
+									  key->parttypcoll[i],
+									  0);
+		}
+		else
+		{
+			if (partexprs_item == NULL)
+				elog(ERROR, "wrong number of partition key expressions");
+			keyCol = copyObject(lfirst(partexprs_item));
+			partexprs_item = lnext(partexprs_item);
+		}
+
+		nulltest = makeNode(NullTest);
+		nulltest->arg = keyCol;
+		nulltest->nulltesttype = IS_NOT_NULL;
+		nulltest->argisrow = false;
+		nulltest->location = -1;
+		result = lappend(result, nulltest);
+	}
+
+	return result;
+}
+
 /*
  * get_qual_for_range
  *
@@ -1744,11 +1794,15 @@ get_range_key_properties(PartitionKey key, int keynum,
  * In most common cases with only one partition column, say a, the following
  * expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
  *
+ * For default partition, it returns the negation of the constraints of all
+ * the other partitions.
+ *
  * If we end up with an empty result list, we return a single-member list
  * containing a constant TRUE, because callers expect a non-empty list.
  */
 static List *
-get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
+get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
+				   bool for_default)
 {
 	List	   *result = NIL;
 	ListCell   *cell1,
@@ -1759,10 +1813,10 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 				j;
 	PartitionRangeDatum *ldatum,
 			   *udatum;
+	PartitionKey key = RelationGetPartitionKey(parent);
 	Expr	   *keyCol;
 	Const	   *lower_val,
 			   *upper_val;
-	NullTest   *nulltest;
 	List	   *lower_or_arms,
 			   *upper_or_arms;
 	int			num_or_arms,
@@ -1772,44 +1826,70 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 	bool		need_next_lower_arm,
 				need_next_upper_arm;
 
-	lower_or_start_datum = list_head(spec->lowerdatums);
-	upper_or_start_datum = list_head(spec->upperdatums);
-	num_or_arms = key->partnatts;
-
-	/*
-	 * A range-partitioned table does not currently allow partition keys to be
-	 * null, so emit an IS NOT NULL expression for each key column.
-	 */
-	partexprs_item = list_head(key->partexprs);
-	for (i = 0; i < key->partnatts; i++)
+	if (spec->is_default)
 	{
-		Expr	   *keyCol;
+		List	   *or_expr_args = NIL;
+		PartitionDesc pdesc = RelationGetPartitionDesc(parent);
+		Oid		   *inhoids = pdesc->oids;
+		int			nparts = pdesc->nparts,
+					i;
 
-		if (key->partattrs[i] != 0)
+		for (i = 0; i < nparts; i++)
 		{
-			keyCol = (Expr *) makeVar(1,
-									  key->partattrs[i],
-									  key->parttypid[i],
-									  key->parttypmod[i],
-									  key->parttypcoll[i],
-									  0);
+			Oid			inhrelid = inhoids[i];
+			HeapTuple	tuple;
+			Datum		datum;
+			bool		isnull;
+			PartitionBoundSpec *bspec;
+
+			tuple = SearchSysCache1(RELOID, inhrelid);
+			if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for relation %u", inhrelid);
+
+			datum = SysCacheGetAttr(RELOID, tuple,
+									Anum_pg_class_relpartbound,
+									&isnull);
+
+			Assert(!isnull);
+			bspec = (PartitionBoundSpec *) stringToNode(TextDatumGetCString(datum));
+
+			if (!bspec->is_default)
+			{
+				List	   *part_qual = get_qual_for_range(parent, bspec, true);
+
+				/*
+				 * AND the constraints of the partition and add to
+				 * or_expr_args
+				 */
+				or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
+									   ? makeBoolExpr(AND_EXPR, part_qual, -1)
+									   : linitial(part_qual));
+			}
+			ReleaseSysCache(tuple);
 		}
-		else
+
+		if (or_expr_args != NIL)
 		{
-			if (partexprs_item == NULL)
-				elog(ERROR, "wrong number of partition key expressions");
-			keyCol = copyObject(lfirst(partexprs_item));
-			partexprs_item = lnext(partexprs_item);
+			/* OR all the non-default partition constraints; then negate it */
+			result = lappend(result,
+							 list_length(or_expr_args) > 1
+							 ? makeBoolExpr(OR_EXPR, or_expr_args, -1)
+							 : linitial(or_expr_args));
+			result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
 		}
+		else					/* default is the only partition */
+			result = list_make1(makeBoolConst(true, false));
 
-		nulltest = makeNode(NullTest);
-		nulltest->arg = keyCol;
-		nulltest->nulltesttype = IS_NOT_NULL;
-		nulltest->argisrow = false;
-		nulltest->location = -1;
-		result = lappend(result, nulltest);
+		return result;
 	}
 
+	lower_or_start_datum = list_head(spec->lowerdatums);
+	upper_or_start_datum = list_head(spec->upperdatums);
+	num_or_arms = key->partnatts;
+
+	if (!for_default)
+		result = get_range_nulltest(key);
+
 	/*
 	 * Iterate over the key columns and check if the corresponding lower and
 	 * upper datums are equal using the btree equality operator for the
@@ -2033,7 +2113,9 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 
 	/* As noted above, caller expects the list to be non-empty. */
 	if (result == NIL)
-		result = list_make1(makeBoolConst(true, false));
+		result = for_default
+			? get_range_nulltest(key)
+			: list_make1(makeBoolConst(true, false));
 
 	return result;
 }
@@ -2201,8 +2283,7 @@ get_partition_for_tuple(PartitionDispatch *pd,
 	Datum		values[PARTITION_MAX_KEYS];
 	bool		isnull[PARTITION_MAX_KEYS];
 	int			cur_offset,
-				cur_index;
-	int			i,
+				cur_index = -1,
 				result;
 	ExprContext *ecxt = GetPerTupleExprContext(estate);
 	TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
@@ -2246,24 +2327,6 @@ get_partition_for_tuple(PartitionDispatch *pd,
 		ecxt->ecxt_scantuple = slot;
 		FormPartitionKeyDatum(parent, slot, estate, values, isnull);
 
-		if (key->strategy == PARTITION_STRATEGY_RANGE)
-		{
-			/*
-			 * Since we cannot route tuples with NULL partition keys through a
-			 * range-partitioned table, simply return that no partition exists
-			 */
-			for (i = 0; i < key->partnatts; i++)
-			{
-				if (isnull[i])
-				{
-					*failed_at = parent;
-					*failed_slot = slot;
-					result = -1;
-					goto error_exit;
-				}
-			}
-		}
-
 		/*
 		 * If this is a NULL, route it to the null-accepting partition. 
 		 * Otherwise, route by searching the array of partition bounds.
@@ -2366,6 +2429,8 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
 	ListCell   *lc;
 	int			i;
 
+	Assert(datums != NULL);
+
 	bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
 	bound->index = index;
 	bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 6830b64..6157613 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -3307,11 +3307,6 @@ transformPartitionBound(ParseState *pstate, Relation parent,
 
 	if (spec->is_default)
 	{
-		if (strategy != PARTITION_STRATEGY_LIST)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-					 errmsg("default partition is supported only for a list partitioned table")));
-
 		/*
 		 * In case of the default partition, parser had no way to identify the
 		 * partition strategy. Assign the parent strategy to the default
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index e066159..67a5c62 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8700,7 +8700,6 @@ get_rule_expr(Node *node, deparse_context *context,
 
 				if (spec->is_default)
 				{
-					Assert(strategy == PARTITION_STRATEGY_LIST);
 					appendStringInfoString(buf, "DEFAULT");
 					break;
 				}
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 9a5f6bf..6855d71 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3356,6 +3356,19 @@ CREATE TABLE part2 (
 );
 ALTER TABLE range_parted ATTACH PARTITION part2 FOR VALUES FROM (1, 10) TO (1, 20);
 INFO:  partition constraint for table "part2" is implied by existing constraints
+-- Create default partition
+CREATE TABLE partr_def1 PARTITION OF range_parted DEFAULT;
+-- Only one default partition is allowed, hence, following should give error
+CREATE TABLE partr_def2 (LIKE part1 INCLUDING CONSTRAINTS);
+ALTER TABLE range_parted ATTACH PARTITION partr_def2 DEFAULT;
+ERROR:  partition "partr_def2" conflicts with existing default partition "partr_def1"
+-- Overlapping partitions cannot be attached, hence, following should give error
+INSERT INTO partr_def1 VALUES (2, 10);
+CREATE TABLE part3 (LIKE range_parted);
+ALTER TABLE range_parted ATTACH partition part3 FOR VALUES FROM (2, 10) TO (2, 20);
+ERROR:  updated partition constraint for default partition would be violated by some row
+-- Attaching partitions should be successful when there are no overlapping rows
+ALTER TABLE range_parted ATTACH partition part3 FOR VALUES FROM (3, 10) TO (3, 20);
 -- check that leaf partitions are scanned when attaching a partitioned
 -- table
 CREATE TABLE part_5 (
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 9615c07..55914e4 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -517,9 +517,6 @@ ERROR:  TO must specify exactly one value per partitioning column
 -- cannot specify null values in range bounds
 CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (maxvalue);
 ERROR:  cannot specify NULL in range bound
--- range partition cannot have default partition
-CREATE TABLE fail_part PARTITION OF range_parted DEFAULT;
-ERROR:  default partition is supported only for a list partitioned table
 -- check if compatible with the specified parent
 -- cannot create as partition of a non-partitioned table
 CREATE TABLE unparted (
@@ -594,6 +591,16 @@ CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (30);
 ERROR:  partition "fail_part" would overlap partition "part2"
 CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (50);
 ERROR:  partition "fail_part" would overlap partition "part2"
+-- Create a default partition for range partitioned table
+CREATE TABLE range2_default PARTITION OF range_parted2 DEFAULT;
+-- More than one default partition is not allowed, so this should give error
+CREATE TABLE fail_default_part PARTITION OF range_parted2 DEFAULT;
+ERROR:  partition "fail_default_part" conflicts with existing default partition "range2_default"
+-- Check if the range for default partitions overlap
+INSERT INTO range_parted2 VALUES (85);
+CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (80) TO (90);
+ERROR:  updated partition constraint for default partition "range2_default" would be violated by some row
+CREATE TABLE part4 PARTITION OF range_parted2 FOR VALUES FROM (90) TO (100);
 -- now check for multi-column range partition key
 CREATE TABLE range_parted3 (
 	a int,
@@ -607,6 +614,7 @@ CREATE TABLE part11 PARTITION OF range_parted3 FOR VALUES FROM (1, 1) TO (1, 10)
 CREATE TABLE part12 PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, maxvalue);
 CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, 20);
 ERROR:  partition "fail_part" would overlap partition "part12"
+CREATE TABLE range3_default PARTITION OF range_parted3 DEFAULT;
 -- cannot create a partition that says column b is allowed to range
 -- from -infinity to +infinity, while there exist partitions that have
 -- more specific ranges
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index 3319f6d..cc28bdc 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -271,6 +271,18 @@ insert into range_parted values ('b', 10);
 insert into range_parted values ('a');
 ERROR:  no partition of relation "range_parted" found for row
 DETAIL:  Partition key of the failing row contains (a, (b + 0)) = (a, null).
+-- Check default partition
+create table part_def partition of range_parted default;
+-- fail
+insert into part_def values ('b', 10);
+ERROR:  new row for relation "part_def" violates partition constraint
+DETAIL:  Failing row contains (b, 10).
+-- ok
+insert into part_def values ('c', 10);
+insert into range_parted values (null, null);
+insert into range_parted values ('a', null);
+insert into range_parted values (null, 19);
+insert into range_parted values ('b', 20);
 select tableoid::regclass, * from range_parted;
  tableoid | a | b  
 ----------+---+----
@@ -280,7 +292,12 @@ select tableoid::regclass, * from range_parted;
  part3    | b |  1
  part4    | b | 10
  part4    | b | 10
-(6 rows)
+ part_def | c | 10
+ part_def |   |   
+ part_def | a |   
+ part_def |   | 19
+ part_def | b | 20
+(11 rows)
 
 -- ok
 insert into list_parted values (null, 1);
@@ -467,6 +484,36 @@ insert into mlparted5 (a, b, c) values (1, 40, 'a');
 ERROR:  new row for relation "mlparted5a" violates partition constraint
 DETAIL:  Failing row contains (b, 1, 40).
 drop table mlparted5;
+alter table mlparted drop constraint check_b;
+-- Check multi-level default partition
+create table mlparted_def partition of mlparted default partition by range(a);
+create table mlparted_def1 partition of mlparted_def for values from (40) to (50);
+create table mlparted_def2 partition of mlparted_def for values from (50) to (60);
+insert into mlparted values (40, 100);
+insert into mlparted_def1 values (42, 100);
+insert into mlparted_def2 values (54, 50);
+-- fail
+insert into mlparted values (70, 100);
+ERROR:  no partition of relation "mlparted_def" found for row
+DETAIL:  Partition key of the failing row contains (a) = (70).
+insert into mlparted_def1 values (52, 50);
+ERROR:  new row for relation "mlparted_def1" violates partition constraint
+DETAIL:  Failing row contains (52, 50, null).
+insert into mlparted_def2 values (34, 50);
+ERROR:  new row for relation "mlparted_def2" violates partition constraint
+DETAIL:  Failing row contains (34, 50, null).
+-- ok
+create table mlparted_defd partition of mlparted_def default;
+insert into mlparted values (70, 100);
+select tableoid::regclass, * from mlparted_def;
+   tableoid    | a  |  b  | c 
+---------------+----+-----+---
+ mlparted_def1 | 40 | 100 | 
+ mlparted_def1 | 42 | 100 | 
+ mlparted_def2 | 54 |  50 | 
+ mlparted_defd | 70 | 100 | 
+(4 rows)
+
 -- check that message shown after failure to find a partition shows the
 -- appropriate key description (or none) in various situations
 create table key_desc (a int, b int) partition by list ((a+0));
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 6750152..e996640 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -77,6 +77,10 @@ mlparted12|f
 mlparted2|f
 mlparted3|f
 mlparted4|f
+mlparted_def|f
+mlparted_def1|f
+mlparted_def2|f
+mlparted_defd|f
 money_data|f
 num_data|f
 num_exp_add|t
diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out
index 9912ef2..cfb6aa8 100644
--- a/src/test/regress/expected/update.out
+++ b/src/test/regress/expected/update.out
@@ -218,6 +218,15 @@ ERROR:  new row for relation "part_b_10_b_20" violates partition constraint
 DETAIL:  Failing row contains (b, 9).
 -- ok
 update range_parted set b = b + 1 where b = 10;
+-- Creating default partition for range
+create table part_def partition of range_parted default;
+insert into range_parted values ('c', 9);
+-- ok
+update part_def set a = 'd' where a = 'c';
+-- fail
+update part_def set a = 'a' where a = 'd';
+ERROR:  new row for relation "part_def" violates partition constraint
+DETAIL:  Failing row contains (a, 9).
 create table list_parted (
 	a text,
 	b int
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 935b24b..d4ca7f1 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2181,6 +2181,21 @@ CREATE TABLE part2 (
 );
 ALTER TABLE range_parted ATTACH PARTITION part2 FOR VALUES FROM (1, 10) TO (1, 20);
 
+-- Create default partition
+CREATE TABLE partr_def1 PARTITION OF range_parted DEFAULT;
+
+-- Only one default partition is allowed, hence, following should give error
+CREATE TABLE partr_def2 (LIKE part1 INCLUDING CONSTRAINTS);
+ALTER TABLE range_parted ATTACH PARTITION partr_def2 DEFAULT;
+
+-- Overlapping partitions cannot be attached, hence, following should give error
+INSERT INTO partr_def1 VALUES (2, 10);
+CREATE TABLE part3 (LIKE range_parted);
+ALTER TABLE range_parted ATTACH partition part3 FOR VALUES FROM (2, 10) TO (2, 20);
+
+-- Attaching partitions should be successful when there are no overlapping rows
+ALTER TABLE range_parted ATTACH partition part3 FOR VALUES FROM (3, 10) TO (3, 20);
+
 -- check that leaf partitions are scanned when attaching a partitioned
 -- table
 CREATE TABLE part_5 (
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 1eefa0e..e4fde85 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -486,8 +486,6 @@ CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a') TO ('z',
 
 -- cannot specify null values in range bounds
 CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (maxvalue);
--- range partition cannot have default partition
-CREATE TABLE fail_part PARTITION OF range_parted DEFAULT;
 
 -- check if compatible with the specified parent
 
@@ -554,6 +552,17 @@ CREATE TABLE part3 PARTITION OF range_parted2 FOR VALUES FROM (30) TO (40);
 CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (30);
 CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (50);
 
+-- Create a default partition for range partitioned table
+CREATE TABLE range2_default PARTITION OF range_parted2 DEFAULT;
+
+-- More than one default partition is not allowed, so this should give error
+CREATE TABLE fail_default_part PARTITION OF range_parted2 DEFAULT;
+
+-- Check if the range for default partitions overlap
+INSERT INTO range_parted2 VALUES (85);
+CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (80) TO (90);
+CREATE TABLE part4 PARTITION OF range_parted2 FOR VALUES FROM (90) TO (100);
+
 -- now check for multi-column range partition key
 CREATE TABLE range_parted3 (
 	a int,
@@ -567,6 +576,7 @@ CREATE TABLE part10 PARTITION OF range_parted3 FOR VALUES FROM (1, minvalue) TO
 CREATE TABLE part11 PARTITION OF range_parted3 FOR VALUES FROM (1, 1) TO (1, 10);
 CREATE TABLE part12 PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, maxvalue);
 CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, 20);
+CREATE TABLE range3_default PARTITION OF range_parted3 DEFAULT;
 
 -- cannot create a partition that says column b is allowed to range
 -- from -infinity to +infinity, while there exist partitions that have
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index 7bf1778..6f5689f 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -168,8 +168,19 @@ insert into range_parted values ('b', 1);
 insert into range_parted values ('b', 10);
 -- fail (partition key (b+0) is null)
 insert into range_parted values ('a');
-select tableoid::regclass, * from range_parted;
 
+-- Check default partition
+create table part_def partition of range_parted default;
+-- fail
+insert into part_def values ('b', 10);
+-- ok
+insert into part_def values ('c', 10);
+insert into range_parted values (null, null);
+insert into range_parted values ('a', null);
+insert into range_parted values (null, 19);
+insert into range_parted values ('b', 20);
+
+select tableoid::regclass, * from range_parted;
 -- ok
 insert into list_parted values (null, 1);
 insert into list_parted (a) values ('aA');
@@ -299,6 +310,24 @@ create function mlparted5abrtrig_func() returns trigger as $$ begin new.c = 'b';
 create trigger mlparted5abrtrig before insert on mlparted5a for each row execute procedure mlparted5abrtrig_func();
 insert into mlparted5 (a, b, c) values (1, 40, 'a');
 drop table mlparted5;
+alter table mlparted drop constraint check_b;
+
+-- Check multi-level default partition
+create table mlparted_def partition of mlparted default partition by range(a);
+create table mlparted_def1 partition of mlparted_def for values from (40) to (50);
+create table mlparted_def2 partition of mlparted_def for values from (50) to (60);
+insert into mlparted values (40, 100);
+insert into mlparted_def1 values (42, 100);
+insert into mlparted_def2 values (54, 50);
+-- fail
+insert into mlparted values (70, 100);
+insert into mlparted_def1 values (52, 50);
+insert into mlparted_def2 values (34, 50);
+-- ok
+create table mlparted_defd partition of mlparted_def default;
+insert into mlparted values (70, 100);
+
+select tableoid::regclass, * from mlparted_def;
 
 -- check that message shown after failure to find a partition shows the
 -- appropriate key description (or none) in various situations
diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql
index 44fb0dc..1ce7a94 100644
--- a/src/test/regress/sql/update.sql
+++ b/src/test/regress/sql/update.sql
@@ -125,6 +125,14 @@ update range_parted set b = b - 1 where b = 10;
 -- ok
 update range_parted set b = b + 1 where b = 10;
 
+-- Creating default partition for range
+create table part_def partition of range_parted default;
+insert into range_parted values ('c', 9);
+-- ok
+update part_def set a = 'd' where a = 'c';
+-- fail
+update part_def set a = 'a' where a = 'd';
+
 create table list_parted (
 	a text,
 	b int
