diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 86b512a..df370a7 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -72,7 +72,8 @@ typedef enum RangeDatumContent
 {
 	RANGE_DATUM_FINITE = 0,		/* actual datum stored elsewhere */
 	RANGE_DATUM_NEG_INF,		/* negative infinity */
-	RANGE_DATUM_POS_INF			/* positive infinity */
+	RANGE_DATUM_POS_INF,		/* positive infinity */
+	RANGE_DATUM_DEFAULT			/* Default Datum */
 } RangeDatumContent;
 
 typedef struct PartitionBoundInfoData
@@ -89,13 +90,12 @@ typedef struct PartitionBoundInfoData
 								 * partitioned table) */
 	int			null_index;		/* Index of the null-accepting partition; -1
 								 * if there isn't one */
-	bool		has_default;		/* Is there a default partition? Currently false
-								 * for a range partitioned table */
-	int			default_index;		/* Index of the default list partition. -1 for
-								 * range partitioned tables */
+	bool		has_default;	/* Is there a default partition? */
+	int			default_index;	/* Index of the default list partition. */
 } PartitionBoundInfoData;
 
 #define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1)
+#define partition_bound_has_default(bi) ((bi)->default_index != -1)
 
 /*
  * When qsort'ing partition bounds after reading from the catalog, each bound
@@ -135,7 +135,8 @@ static void get_range_key_properties(PartitionKey key, int keynum,
 						 Const **lower_val, Const **upper_val);
 static List *get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec,
 							   bool is_def, List *boundspecs);
-static List *get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec);
+static List *get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec,
+				   bool is_def);
 static List *generate_partition_qual(Relation rel);
 
 static PartitionRangeBound *make_one_range_bound(PartitionKey key, int index,
@@ -146,6 +147,9 @@ static int32 partition_rbound_cmp(PartitionKey key,
 static int32 partition_rbound_datum_cmp(PartitionKey key,
 						   Datum *rb_datums, RangeDatumContent *rb_content,
 						   Datum *tuple_datums);
+static List *get_qual_for_range_default(Relation parent,
+						   PartitionBoundSpec *new_spec, Oid *defid);
+static List *get_range_nulltest(PartitionKey key);
 
 static int32 partition_bound_cmp(PartitionKey key,
 					PartitionBoundInfo boundinfo,
@@ -176,11 +180,11 @@ RelationBuildPartitionDesc(Relation rel)
 	MemoryContext oldcxt;
 
 	int			ndatums = 0;
+	bool		found_def = false;
+	int			def_index = -1;
 
 	/* List partitioning specific */
 	PartitionListValue **all_values = NULL;
-	bool		found_def = false;
-	int			def_index = -1;
 	int			null_index = -1;
 
 	/* Range partitioning specific */
@@ -349,6 +353,9 @@ RelationBuildPartitionDesc(Relation rel)
 				if (spec->strategy != PARTITION_STRATEGY_RANGE)
 					elog(ERROR, "invalid strategy in partition bound spec");
 
+				if (isDefaultPartitionBound((Node *) linitial(spec->lowerdatums)))
+					def_index = i;
+
 				lower = make_one_range_bound(key, i, spec->lowerdatums,
 											 true);
 				upper = make_one_range_bound(key, i, spec->upperdatums,
@@ -537,7 +544,6 @@ RelationBuildPartitionDesc(Relation rel)
 												sizeof(RangeDatumContent *));
 					boundinfo->indexes = (int *) palloc((ndatums + 1) *
 														sizeof(int));
-					boundinfo->has_default = found_def;
 
 					for (i = 0; i < ndatums; i++)
 					{
@@ -559,6 +565,9 @@ RelationBuildPartitionDesc(Relation rel)
 							boundinfo->content[i][j] = rbounds[i]->content[j];
 						}
 
+						if (def_index != -1 && mapping[def_index] == -1)
+							mapping[def_index] = next_index++;
+
 						/*
 						 * There is no mapping for invalid indexes.
 						 *
@@ -581,6 +590,10 @@ RelationBuildPartitionDesc(Relation rel)
 							boundinfo->indexes[i] = mapping[orig_index];
 						}
 					}
+
+					boundinfo->default_index = (def_index == -1) ?
+												-1 : mapping[def_index];
+
 					boundinfo->indexes[i] = -1;
 					break;
 				}
@@ -764,8 +777,24 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound)
 				upper = make_one_range_bound(key, -1, spec->upperdatums, false);
 
 				/*
-				 * First check if the resulting range would be empty with
-				 * specified lower and upper bounds
+				 * If the new partition is default check if the parent table
+				 * already has a default partition
+				 */
+
+				if ((lower->content[0] == RANGE_DATUM_DEFAULT))
+				{
+					if (partdesc->nparts > 0 &&
+						partition_bound_has_default(partdesc->boundinfo))
+					{
+						overlap = true;
+						with = partdesc->boundinfo->default_index;
+					}
+					break;
+				}
+
+				/*
+				 * Check if the resulting range would be empty with specified
+				 * lower and upper bounds
 				 */
 				if (partition_rbound_cmp(key, lower->datums, lower->content, true,
 										 upper) >= 0)
@@ -871,13 +900,12 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound)
 	}
 
 	/*
-	 * When adding a list partition after default partition, scan the
-	 * default partition for rows satisfying the new partition
-	 * constraint. If found don't allow addition of a new partition.
-	 * Otherwise continue with the creation of new  partition.
+	 * When adding a partition after default partition, scan the default
+	 * partition for rows satisfying the new partition constraint. If found,
+	 * don't allow addition of a new partition. Otherwise continue with the
+	 * creation of new	partition.
 	 */
-	if (spec->strategy == PARTITION_STRATEGY_LIST && partdesc->nparts > 0
-		&& boundinfo->has_default)
+	if (partdesc->nparts > 0 && partition_bound_has_default(boundinfo))
 	{
 		List	       *partConstraint = NIL;
 		ExprContext    *econtext;
@@ -891,11 +919,13 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound)
 		MemoryContext   oldCxt;
 		TupleTableSlot *tupslot;
 		TupleDesc	    tupdesc;
-		List           *all_parts;
+		List		   *all_parts;
 		ListCell       *lc;
 
+		partConstraint = (key->strategy == PARTITION_STRATEGY_LIST)
+			? generate_qual_for_defaultpart(parent, bound, &defid)
+			: get_qual_for_range_default(parent, spec, &defid);
 
-		partConstraint = generate_qual_for_defaultpart(parent, bound, &defid);
 		partConstraint = (List *) eval_const_expressions(NULL,
 													(Node *) partConstraint);
 		partConstraint = (List *) canonicalize_qual((Expr *) partConstraint);
@@ -1104,6 +1134,148 @@ get_qual_for_default(Relation parent, Oid *defid)
 	return boundspecs;
 }
 
+ /*
+  * A non-default range partiton 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;
+}
+
+/*
+ * Return a qual for the default partition of range.
+ *
+ * Generally it is negation of the constraints of all other partitions:
+ * NOT ( <partiton1 constraint> [ || <partiontion2 constraint>] [|| ...])
+ *
+ * When it is called for the insertion of a new partiton after default, the
+ * list will also have the constraints of new_spec.
+ *
+ * If DEFAULT is the only partiton for the table then this returns TRUE.
+ *
+ * If the only other partition is [UNBOUNDED, UNBOUNDED]; this returns
+ * NOT ( <keycol1> != NULL [ AND <keycol2> != NULL] [AND ...])
+ * In this case, default will only store tuples where keycol value is NULL.
+ */
+static List *
+get_qual_for_range_default(Relation parent, PartitionBoundSpec *new_spec, Oid *defid)
+{
+	PartitionKey key = RelationGetPartitionKey(parent);
+	List	   *inhoids,
+			   *result = NIL,
+			   *or_expr_args = NIL;
+	ListCell   *cell;
+
+	inhoids = find_inheritance_children(RelationGetRelid(parent), AccessExclusiveLock);
+
+	foreach(cell, inhoids)
+	{
+		Oid			inhrelid = lfirst_oid(cell);
+		HeapTuple	tuple;
+		Datum		datum;
+		bool		isnull;
+		PartitionBoundSpec *bspec;
+
+		tuple = SearchSysCache1(RELOID, inhrelid);
+		if (!HeapTupleIsValid(tuple))
+			elog(ERROR, "cache lookup failed for relation %u", inhrelid);
+
+		/*
+		 * It is possible that the pg_class tuple of a partition has not been
+		 * updated yet to set its relpartbound field.  The only case where
+		 * this happens is when we open the parent relation to check using its
+		 * partition descriptor that a new partition's bound does not overlap
+		 * some existing partition.
+		 */
+		if (!((Form_pg_class) GETSTRUCT(tuple))->relispartition)
+		{
+			ReleaseSysCache(tuple);
+			continue;
+		}
+
+		datum = SysCacheGetAttr(RELOID, tuple,
+								Anum_pg_class_relpartbound,
+								&isnull);
+
+		Assert(!isnull);
+		bspec = (PartitionBoundSpec *) stringToNode(TextDatumGetCString(datum));
+
+		if (isDefaultPartitionBound((linitial(bspec->lowerdatums))))
+			*defid = inhrelid;
+		else
+		{
+			List	   *part_qual = get_qual_for_range(key, 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);
+	}
+
+	if (new_spec != NULL)
+	{
+		List	   *part_qual = get_qual_for_range(key, new_spec, true);
+
+		or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
+							   ? makeBoolExpr(AND_EXPR, part_qual, -1)
+							   : linitial(part_qual));
+	}
+
+	if (or_expr_args != NIL)
+	{
+		/* 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	/* When default is the only partition */
+		result = list_make1(makeBoolConst(true, false));
+
+	return result;
+}
+
 /*
  * Return a list of executable expressions as new partition constraint
  * for default partition while adding a new partition after default
@@ -1144,7 +1316,7 @@ get_qual_from_partbound(Relation rel, Relation parent, Node *bound)
 	PartitionKey key = RelationGetPartitionKey(parent);
 	List	   *my_qual = NIL;
 	bool		is_def = false;
-	Oid        defid;
+	Oid			defid;
 	ListCell   *cell;
 	List	   *boundspecs = NIL;
 
@@ -1166,7 +1338,11 @@ get_qual_from_partbound(Relation rel, Relation parent, Node *bound)
 			break;
 		case PARTITION_STRATEGY_RANGE:
 			Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
-			my_qual = get_qual_for_range(key, spec);
+
+			if (isDefaultPartitionBound((Node *) linitial(spec->lowerdatums)))
+				my_qual = get_qual_for_range_default(parent, NULL, &defid);
+			else
+				my_qual = get_qual_for_range(key, spec, is_def);
 			break;
 
 		default:
@@ -1754,7 +1930,7 @@ get_range_key_properties(PartitionKey key, int keynum,
  * expect a non-empty list.
  */
 static List *
-get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
+get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec, bool is_def)
 {
 	List	   *result = NIL;
 	ListCell   *cell1,
@@ -1768,7 +1944,6 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 	Expr	   *keyCol;
 	Const	   *lower_val,
 			   *upper_val;
-	NullTest   *nulltest;
 	List	   *lower_or_arms,
 			   *upper_or_arms;
 	int			num_or_arms,
@@ -1782,39 +1957,8 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 	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++)
-	{
-		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);
-	}
+	if (!is_def)
+		result = get_range_nulltest(key);
 
 	/*
 	 * Iterate over the key columns and check if the corresponding lower and
@@ -2030,7 +2174,9 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 
 	/* As noted above, caller expects the list to be non-empty. */
 	if (result == NULL)
-		result = list_make1(makeBoolConst(true, false));
+		result = is_def
+			? get_range_nulltest(key)
+			: list_make1(makeBoolConst(true, false));
 
 	return result;
 }
@@ -2197,8 +2343,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;
@@ -2242,33 +2387,16 @@ get_partition_for_tuple(PartitionDispatch *pd,
 		ecxt->ecxt_scantuple = slot;
 		FormPartitionKeyDatum(parent, slot, estate, values, isnull);
 
-		if (key->strategy == PARTITION_STRATEGY_RANGE)
+		if (key->strategy == PARTITION_STRATEGY_LIST && isnull[0])
 		{
 			/*
-			 * Since we cannot route tuples with NULL partition keys through
-			 * a range-partitioned table, simply return that no partition
-			 * exists
+			 * A null partition key is only acceptable if null-accepting list
+			 * partition exists.
 			 */
-			for (i = 0; i < key->partnatts; i++)
-			{
-				if (isnull[i])
-				{
-					*failed_at = parent;
-					*failed_slot = slot;
-					result = -1;
-					goto error_exit;
-				}
-			}
+			if (partition_bound_accepts_nulls(partdesc->boundinfo))
+				cur_index = partdesc->boundinfo->null_index;
 		}
-
-		/*
-		 * A null partition key is only acceptable if null-accepting list
-		 * partition exists.
-		 */
-		cur_index = -1;
-		if (isnull[0] && partition_bound_accepts_nulls(partdesc->boundinfo))
-			cur_index = partdesc->boundinfo->null_index;
-		else if (!isnull[0])
+		else
 		{
 			/* Else bsearch in partdesc->boundinfo */
 			bool		equal = false;
@@ -2311,7 +2439,7 @@ get_partition_for_tuple(PartitionDispatch *pd,
 			 * If partitioned table has a default partition, return
 			 * its sequence number
 			 */
-			if (partdesc->boundinfo->has_default)
+			if (partition_bound_has_default(partdesc->boundinfo))
 			{
 				result = parent->indexes[partdesc->boundinfo->default_index];
 				if (result >= 0)
@@ -2385,10 +2513,12 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
 		PartitionRangeDatum *datum = lfirst(cell);
 
 		/* What's contained in this range datum? */
-		bound->content[i] = !datum->infinite
-			? RANGE_DATUM_FINITE
-			: (lower ? RANGE_DATUM_NEG_INF
-			   : RANGE_DATUM_POS_INF);
+		bound->content[i] = (datum->type == T_DefElem)
+			? RANGE_DATUM_DEFAULT
+			: (!datum->infinite
+			   ? RANGE_DATUM_FINITE
+			   : (lower ? RANGE_DATUM_NEG_INF
+				  : RANGE_DATUM_POS_INF));
 
 		if (bound->content[i] == RANGE_DATUM_FINITE)
 		{
@@ -2436,9 +2566,19 @@ partition_rbound_cmp(PartitionKey key,
 	for (i = 0; i < key->partnatts; i++)
 	{
 		/*
-		 * First, handle cases involving infinity, which don't require
-		 * invoking the comparison proc.
+		 * First, handle cases involving infinity and default, which don't
+		 * require invoking the comparison proc.
 		 */
+		if (content1[i] == RANGE_DATUM_DEFAULT ||
+			content2[i] == RANGE_DATUM_DEFAULT)
+		{
+			if (content1[i] == content2[i])
+				return 0;
+			else if (content1[i] == RANGE_DATUM_DEFAULT)
+				return -1;
+			else
+				return 1;
+		}
 		if (content1[i] != RANGE_DATUM_FINITE &&
 			content2[i] != RANGE_DATUM_FINITE)
 
@@ -2489,6 +2629,9 @@ partition_rbound_datum_cmp(PartitionKey key,
 
 	for (i = 0; i < key->partnatts; i++)
 	{
+		if (rb_content[i] == RANGE_DATUM_DEFAULT)
+			continue;
+
 		if (rb_content[i] != RANGE_DATUM_FINITE)
 			return rb_content[i] == RANGE_DATUM_NEG_INF ? -1 : 1;
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 3af286f..26c00ad 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2683,6 +2683,8 @@ ForValues:
 
 					n->strategy = PARTITION_DEFAULT;
 					n->listdatums = $1;
+					n->lowerdatums = $1;
+					n->upperdatums = $1;
 					n->location = @1;
 
 					$$ = (Node *) n;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 306a5d1..5e13772 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -3384,23 +3384,38 @@ transformPartitionBound(ParseState *pstate, Relation parent, Node *bound)
 					j;
 		char	   *colname;
 		bool		seen_unbounded;
+		bool		is_def;
 
 		if (spec->strategy != PARTITION_STRATEGY_RANGE)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+		{
+			/*
+			 * If the partition is the default partition switch back to
+			 * PARTITION_STRATEGY_RANGE
+			 */
+			if (spec->strategy == PARTITION_DEFAULT)
+			{
+				is_def = true;
+				result_spec->strategy = PARTITION_STRATEGY_RANGE;
+			}
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 				 errmsg("invalid bound specification for a range partition"),
-					 parser_errposition(pstate, exprLocation(bound))));
-
+						 parser_errposition(pstate, exprLocation(bound))));
+		}
 		Assert(spec->lowerdatums != NIL && spec->upperdatums != NIL);
 
-		if (list_length(spec->lowerdatums) != partnatts)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-					 errmsg("FROM must specify exactly one value per partitioning column")));
-		if (list_length(spec->upperdatums) != partnatts)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-					 errmsg("TO must specify exactly one value per partitioning column")));
+		if (!is_def)
+		{
+			if (list_length(spec->lowerdatums) != partnatts)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+						 errmsg("FROM must specify exactly one value per partitioning column")));
+			if (list_length(spec->upperdatums) != partnatts)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+						 errmsg("TO must specify exactly one value per partitioning column")));
+		}
 
 		/*
 		 * Check that no finite value follows a UNBOUNDED literal in either of
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 5bff62a..038c937 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8689,6 +8689,17 @@ get_rule_expr(Node *node, deparse_context *context,
 							   list_length(spec->lowerdatums) ==
 							   list_length(spec->upperdatums));
 
+						foreach(cell, spec->lowerdatums)
+						{
+							if (isDefaultPartitionBound((Node *) lfirst(cell)))
+							{
+								appendStringInfoString(buf, "DEFAULT");
+								is_def = true;
+								break;
+							}
+						}
+						if (is_def)
+							break;
 						appendStringInfoString(buf, "FOR VALUES");
 						appendStringInfoString(buf, " FROM");
 						appendStringInfoString(buf, " (");
