diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 7304f6c..86b512a 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -34,6 +34,7 @@
 #include "nodes/nodeFuncs.h"
 #include "nodes/parsenodes.h"
 #include "optimizer/clauses.h"
+#include "optimizer/prep.h"
 #include "optimizer/planmain.h"
 #include "optimizer/var.h"
 #include "rewrite/rewriteManip.h"
@@ -88,6 +89,10 @@ 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 */
 } PartitionBoundInfoData;
 
 #define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1)
@@ -121,14 +126,15 @@ static int32 qsort_partition_rbound_cmp(const void *a, const void *b,
 static Oid get_partition_operator(PartitionKey key, int col,
 					   StrategyNumber strategy, bool *need_relabel);
 static Expr *make_partition_op_expr(PartitionKey key, int keynum,
-					   uint16 strategy, Expr *arg1, Expr *arg2);
+					   uint16 strategy, Expr *arg1, Expr *arg2, bool is_def);
 static void get_range_key_properties(PartitionKey key, int keynum,
 						 PartitionRangeDatum *ldatum,
 						 PartitionRangeDatum *udatum,
 						 ListCell **partexprs_item,
 						 Expr **keyCol,
 						 Const **lower_val, Const **upper_val);
-static List *get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec);
+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 *generate_partition_qual(Relation rel);
 
@@ -173,6 +179,8 @@ RelationBuildPartitionDesc(Relation rel)
 
 	/* List partitioning specific */
 	PartitionListValue **all_values = NULL;
+	bool		found_def = false;
+	int			def_index = -1;
 	int			null_index = -1;
 
 	/* Range partitioning specific */
@@ -255,9 +263,16 @@ RelationBuildPartitionDesc(Relation rel)
 
 				foreach(c, spec->listdatums)
 				{
+					Node *value = lfirst(c);
 					Const	   *val = lfirst(c);
 					PartitionListValue *list_value = NULL;
 
+					if (isDefaultPartitionBound(value))
+					{
+						found_def = true;
+						def_index = i;
+						continue;
+					}
 					if (!val->constisnull)
 					{
 						list_value = (PartitionListValue *)
@@ -463,6 +478,7 @@ RelationBuildPartitionDesc(Relation rel)
 		{
 			case PARTITION_STRATEGY_LIST:
 				{
+					boundinfo->has_default = found_def;
 					boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
 
 					/*
@@ -503,9 +519,15 @@ RelationBuildPartitionDesc(Relation rel)
 					}
 					else
 						boundinfo->null_index = -1;
+					if (found_def && mapping[def_index] == -1)
+						mapping[def_index] = next_index++;
 
 					/* All partition must now have a valid mapping */
 					Assert(next_index == nparts);
+					if (found_def)
+						boundinfo->default_index = mapping[def_index];
+					else
+						boundinfo->default_index = -1;
 					break;
 				}
 
@@ -515,6 +537,7 @@ RelationBuildPartitionDesc(Relation rel)
 												sizeof(RangeDatumContent *));
 					boundinfo->indexes = (int *) palloc((ndatums + 1) *
 														sizeof(int));
+					boundinfo->has_default = found_def;
 
 					for (i = 0; i < ndatums; i++)
 					{
@@ -670,6 +693,7 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound)
 	PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
 	PartitionKey key = RelationGetPartitionKey(parent);
 	PartitionDesc partdesc = RelationGetPartitionDesc(parent);
+	PartitionBoundInfo boundinfo = partdesc->boundinfo;
 	ParseState *pstate = make_parsestate(NULL);
 	int			with = -1;
 	bool		overlap = false;
@@ -682,19 +706,20 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound)
 
 				if (partdesc->nparts > 0)
 				{
-					PartitionBoundInfo boundinfo = partdesc->boundinfo;
 					ListCell   *cell;
 
 					Assert(boundinfo &&
 						   boundinfo->strategy == PARTITION_STRATEGY_LIST &&
 						   (boundinfo->ndatums > 0 ||
-							partition_bound_accepts_nulls(boundinfo)));
+							partition_bound_accepts_nulls(boundinfo) ||
+							boundinfo->has_default));
 
 					foreach(cell, spec->listdatums)
 					{
-						Const	   *val = lfirst(cell);
+						Node	   *value = lfirst(cell);
+						Const	   *val = (Const *) value;
 
-						if (!val->constisnull)
+						if (!val->constisnull && !(isDefaultPartitionBound(value)))
 						{
 							int			offset;
 							bool		equal;
@@ -709,7 +734,15 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound)
 								break;
 							}
 						}
-						else if (partition_bound_accepts_nulls(boundinfo))
+						else if (isDefaultPartitionBound(value) &&
+								 boundinfo->has_default)
+						{
+							overlap = true;
+							with = boundinfo->default_index;
+							break;
+						}
+
+						else if (val->constisnull && partition_bound_accepts_nulls(boundinfo))
 						{
 							overlap = true;
 							with = boundinfo->null_index;
@@ -836,6 +869,112 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound)
 						relname, get_rel_name(partdesc->oids[with])),
 				 parser_errposition(pstate, spec->location)));
 	}
+
+	/*
+	 * 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.
+	 */
+	if (spec->strategy == PARTITION_STRATEGY_LIST && partdesc->nparts > 0
+		&& boundinfo->has_default)
+	{
+		List	       *partConstraint = NIL;
+		ExprContext    *econtext;
+		EState	       *estate;
+		Relation	    defrel;
+		HeapScanDesc    scan;
+		HeapTuple	    tuple;
+		ExprState	   *partqualstate = NULL;
+		Snapshot	    snapshot;
+		Oid			    defid;
+		MemoryContext   oldCxt;
+		TupleTableSlot *tupslot;
+		TupleDesc	    tupdesc;
+		List           *all_parts;
+		ListCell       *lc;
+
+
+		partConstraint = generate_qual_for_defaultpart(parent, bound, &defid);
+		partConstraint = (List *) eval_const_expressions(NULL,
+													(Node *) partConstraint);
+		partConstraint = (List *) canonicalize_qual((Expr *) partConstraint);
+		partConstraint = list_make1(make_ands_explicit(partConstraint));
+
+		/*
+		 * Generate the constraint and default execution states
+		 */
+		defrel = heap_open(defid, AccessExclusiveLock);
+
+		if (defrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+			all_parts = find_all_inheritors(RelationGetRelid(defrel),
+											AccessExclusiveLock, NULL);
+		else
+			all_parts = list_make1_oid(RelationGetRelid(defrel));
+
+		foreach(lc, all_parts)
+		{
+			Oid			part_relid = lfirst_oid(lc);
+			Relation	part_rel;
+			Expr	   *constr;
+			Expr	   *partition_constraint;
+
+			if (part_relid != RelationGetRelid(defrel))
+				part_rel = heap_open(part_relid, NoLock);
+			else
+				part_rel = defrel;
+
+			/*
+			 * Skip if it's a partitioned table.  Only RELKIND_RELATION
+			 * relations (ie, leaf partitions) need to be scanned.
+			 */
+			if (part_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+			{
+				heap_close(part_rel, NoLock);
+				continue;
+			}
+			tupdesc = CreateTupleDescCopy(RelationGetDescr(part_rel));
+			constr = linitial(partConstraint);
+			partition_constraint = (Expr *)
+				map_partition_varattnos((List *) constr, 1,
+										part_rel, parent);
+			estate = CreateExecutorState();
+
+			/* Build expression execution states for partition check quals */
+			partqualstate = ExecPrepareExpr(partition_constraint,
+							estate);
+
+			econtext = GetPerTupleExprContext(estate);
+			snapshot = RegisterSnapshot(GetLatestSnapshot());
+			scan = heap_beginscan(part_rel, snapshot, 0, NULL);
+			tupslot = MakeSingleTupleTableSlot(tupdesc);
+
+			/*
+			 * Switch to per-tuple memory context and reset it for each tuple
+			 * produced, so we don't leak memory.
+			 */
+			oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
+
+			while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+			{
+				ExecStoreTuple(tuple, tupslot, InvalidBuffer, false);
+				econtext->ecxt_scantuple = tupslot;
+				if (partqualstate && !ExecCheck(partqualstate, econtext))
+					ereport(ERROR,
+							(errcode(ERRCODE_CHECK_VIOLATION),
+					errmsg("new default partition constraint is violated by some row")));
+				ResetExprContext(econtext);
+				CHECK_FOR_INTERRUPTS();
+			}
+			CacheInvalidateRelcache(part_rel);
+			MemoryContextSwitchTo(oldCxt);
+			heap_endscan(scan);
+			UnregisterSnapshot(snapshot);
+			ExecDropSingleTupleTableSlot(tupslot);
+			FreeExecutorState(estate);
+			heap_close(part_rel, NoLock);
+		}
+	}
 }
 
 /*
@@ -884,6 +1023,116 @@ get_partition_parent(Oid relid)
 }
 
 /*
+ * Returns true if the partition bound is default
+ */
+bool
+isDefaultPartitionBound(Node *value)
+{
+	if (IsA(value, DefElem))
+	{
+		DefElem *defvalue = (DefElem *) value;
+		if(!strcmp(defvalue->defname, "DEFAULT"))
+			return true;
+	}
+	return false;
+}
+
+/*
+ * Return the bound spec list to be used
+ * in partition constraint of default partition
+ */
+List *
+get_qual_for_default(Relation parent, Oid *defid)
+{
+	List	   *inhoids;
+	ListCell   *cell;
+	List	   *boundspecs = NIL;
+
+	inhoids = find_inheritance_children(RelationGetRelid(parent), AccessExclusiveLock);
+	foreach(cell, inhoids)
+	{
+		Oid			inhrelid = lfirst_oid(cell);
+		HeapTuple	tuple;
+		Datum		datum;
+		bool		isnull;
+		bool		def_elem = false;
+		PartitionBoundSpec *bspec;
+		ListCell *cell1;
+
+		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));
+		foreach(cell1, bspec->listdatums)
+		{
+			Node *value = lfirst(cell1);
+			if (isDefaultPartitionBound(value))
+			{
+				def_elem = true;
+				*defid  = inhrelid;
+				break;
+			}
+		}
+		if (!def_elem)
+		{
+			foreach(cell1, bspec->listdatums)
+			{
+				Node *value = lfirst(cell1);
+				boundspecs = lappend(boundspecs, value);
+			}
+		}
+		ReleaseSysCache(tuple);
+	}
+	return boundspecs;
+}
+
+/*
+ * Return a list of executable expressions as new partition constraint
+ * for default partition while adding a new partition after default
+ */
+List *
+generate_qual_for_defaultpart(Relation parent, Node *bound, Oid * defid)
+{
+	PartitionKey key = RelationGetPartitionKey(parent);
+	PartitionBoundSpec *spec;
+	List	   *partConstraint = NIL;
+	ListCell   *cell;
+	List       *boundspecs = NIL;
+	List       *bound_datums;
+
+	spec = (PartitionBoundSpec *) bound;
+	bound_datums = list_copy(spec->listdatums);
+
+	boundspecs = get_qual_for_default(parent, defid);
+
+	foreach(cell, bound_datums)
+	{
+		Node *value = lfirst(cell);
+		boundspecs = lappend(boundspecs, value);
+	}
+	partConstraint = get_qual_for_list(key, spec, true, boundspecs);
+	return partConstraint;
+}
+
+/*
  * get_qual_from_partbound
  *		Given a parser node for partition bound, return the list of executable
  *		expressions as partition constraint
@@ -894,6 +1143,10 @@ get_qual_from_partbound(Relation rel, Relation parent, Node *bound)
 	PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
 	PartitionKey key = RelationGetPartitionKey(parent);
 	List	   *my_qual = NIL;
+	bool		is_def = false;
+	Oid        defid;
+	ListCell   *cell;
+	List	   *boundspecs = NIL;
 
 	Assert(key != NULL);
 
@@ -901,9 +1154,16 @@ get_qual_from_partbound(Relation rel, Relation parent, Node *bound)
 	{
 		case PARTITION_STRATEGY_LIST:
 			Assert(spec->strategy == PARTITION_STRATEGY_LIST);
-			my_qual = get_qual_for_list(key, spec);
+			foreach(cell, spec->listdatums)
+			{
+				Node *value = lfirst(cell);
+				if (isDefaultPartitionBound(value))
+					is_def = true;
+			}
+			if (is_def)
+				boundspecs = get_qual_for_default(parent, &defid);
+			my_qual = get_qual_for_list(key, spec, is_def, boundspecs);
 			break;
-
 		case PARTITION_STRATEGY_RANGE:
 			Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
 			my_qual = get_qual_for_range(key, spec);
@@ -1231,7 +1491,8 @@ get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
  */
 static Expr *
 make_partition_op_expr(PartitionKey key, int keynum,
-					   uint16 strategy, Expr *arg1, Expr *arg2)
+					   uint16 strategy, Expr *arg1, Expr *arg2,
+					   bool is_def)
 {
 	Oid			operoid;
 	bool		need_relabel = false;
@@ -1261,11 +1522,17 @@ make_partition_op_expr(PartitionKey key, int keynum,
 			{
 				ScalarArrayOpExpr *saopexpr;
 
+				if (is_def && ((operoid = get_negator(operoid)) == InvalidOid))
+					ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION),
+									errmsg("DEFAULT partition cannot be used"
+										   " without negator of operator  %s",
+										   get_opname(operoid))));
+
 				/* Build leftop = ANY (rightop) */
 				saopexpr = makeNode(ScalarArrayOpExpr);
 				saopexpr->opno = operoid;
 				saopexpr->opfuncid = get_opcode(operoid);
-				saopexpr->useOr = true;
+				saopexpr->useOr = !is_def;
 				saopexpr->inputcollid = key->partcollation[keynum];
 				saopexpr->args = list_make2(arg1, arg2);
 				saopexpr->location = -1;
@@ -1297,7 +1564,8 @@ make_partition_op_expr(PartitionKey key, int keynum,
  * Returns a list of expressions to use as a list partition's constraint.
  */
 static List *
-get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
+get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec, bool is_def,
+					List *boundspecs)
 {
 	List	   *result;
 	ArrayExpr  *arr;
@@ -1321,12 +1589,14 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
 	else
 		keyCol = (Expr *) copyObject(linitial(key->partexprs));
 
+	if (!is_def)
+		boundspecs = spec->listdatums;
 	/*
 	 * We must remove any NULL value in the list; we handle it separately
 	 * below.
 	 */
 	prev = NULL;
-	for (cell = list_head(spec->listdatums); cell; cell = next)
+	for (cell = list_head(boundspecs); cell; cell = next)
 	{
 		Const	   *val = (Const *) lfirst(cell);
 
@@ -1335,14 +1605,14 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
 		if (val->constisnull)
 		{
 			list_has_null = true;
-			spec->listdatums = list_delete_cell(spec->listdatums,
+			boundspecs = list_delete_cell(boundspecs,
 												cell, prev);
 		}
 		else
 			prev = cell;
 	}
 
-	if (!list_has_null)
+	if ((is_def && list_has_null) || (!is_def && !list_has_null))
 	{
 		/*
 		 * Gin up a col IS NOT NULL test that will be AND'd with other
@@ -1354,7 +1624,7 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
 		nulltest1->argisrow = false;
 		nulltest1->location = -1;
 	}
-	else
+	else if(!is_def && list_has_null)
 	{
 		/*
 		 * Gin up a col IS NULL test that will be OR'd with other expressions
@@ -1373,13 +1643,13 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
 		: key->parttypid[0];
 	arr->array_collid = key->parttypcoll[0];
 	arr->element_typeid = key->parttypid[0];
-	arr->elements = spec->listdatums;
+	arr->elements = boundspecs;
 	arr->multidims = false;
 	arr->location = -1;
 
 	/* Generate the main expression, i.e., keyCol = ANY (arr) */
 	opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
-									keyCol, (Expr *) arr);
+									keyCol, (Expr *) arr, is_def);
 
 	if (nulltest1)
 		result = list_make2(nulltest1, opexpr);
@@ -1594,7 +1864,7 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 		oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
 		test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
 										   (Expr *) lower_val,
-										   (Expr *) upper_val);
+										   (Expr *) upper_val, false);
 		fix_opfuncids((Node *) test_expr);
 		test_exprstate = ExecInitExpr(test_expr, NULL);
 		test_result = ExecEvalExprSwitchContext(test_exprstate,
@@ -1618,7 +1888,8 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 		/* Equal, so generate keyCol = lower_val expression */
 		result = lappend(result,
 						 make_partition_op_expr(key, i, BTEqualStrategyNumber,
-												keyCol, (Expr *) lower_val));
+												keyCol, (Expr *) lower_val,
+												false));
 
 		i++;
 	}
@@ -1676,7 +1947,8 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 											make_partition_op_expr(key, j,
 																   strategy,
 																   keyCol,
-														(Expr *) lower_val));
+														(Expr *) lower_val,
+																   false));
 			}
 
 			if (need_next_upper_arm && upper_val)
@@ -1698,7 +1970,8 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 											make_partition_op_expr(key, j,
 																   strategy,
 																   keyCol,
-														(Expr *) upper_val));
+														(Expr *) upper_val,
+																   false));
 
 			}
 
@@ -2034,10 +2307,25 @@ get_partition_for_tuple(PartitionDispatch *pd,
 		 */
 		if (cur_index < 0)
 		{
-			result = -1;
-			*failed_at = parent;
-			*failed_slot = slot;
-			break;
+			/*
+			 * If partitioned table has a default partition, return
+			 * its sequence number
+			 */
+			if (partdesc->boundinfo->has_default)
+			{
+				result = parent->indexes[partdesc->boundinfo->default_index];
+				if (result >= 0)
+					break;
+				else
+					parent = pd[-parent->indexes[partdesc->boundinfo->default_index]];
+			}
+			else
+			{
+				result = -1;
+				*failed_at = parent;
+				*failed_slot = slot;
+				break;
+			}
 		}
 		else if (parent->indexes[cur_index] >= 0)
 		{
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 2822331..3af286f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -578,6 +578,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <node>		ForValues
 %type <node>		partbound_datum
 %type <list>		partbound_datum_list
+%type <list>		default_partition
 %type <partrange_datum>	PartitionRangeDatum
 %type <list>		range_datum_list
 
@@ -2676,6 +2677,17 @@ ForValues:
 
 					$$ = (Node *) n;
 				}
+			| default_partition
+				{
+					PartitionBoundSpec *n = makeNode(PartitionBoundSpec);
+
+					n->strategy = PARTITION_DEFAULT;
+					n->listdatums = $1;
+					n->location = @1;
+
+					$$ = (Node *) n;
+				}
+
 		;
 
 partbound_datum:
@@ -2690,6 +2702,12 @@ partbound_datum_list:
 												{ $$ = lappend($1, $3); }
 		;
 
+default_partition:
+			DEFAULT	{
+						Node *def = (Node *)makeDefElem("DEFAULT", NULL, @1);
+						$$ = list_make1(def);
+					}
+
 range_datum_list:
 			PartitionRangeDatum					{ $$ = list_make1($1); }
 			| range_datum_list ',' PartitionRangeDatum
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index beb0995..306a5d1 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -33,6 +33,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/partition.h"
 #include "catalog/pg_am.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
@@ -3310,55 +3311,67 @@ transformPartitionBound(ParseState *pstate, Relation parent, Node *bound)
 										 false, false);
 
 		if (spec->strategy != PARTITION_STRATEGY_LIST)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-				  errmsg("invalid bound specification for a list partition"),
+		{
+			/*
+			 * If the partition is the default partition switch
+			 * back to PARTITION_STRATEGY_LIST
+			 */
+			if (spec->strategy == PARTITION_DEFAULT)
+				result_spec->strategy = PARTITION_STRATEGY_LIST;
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+					 errmsg("invalid bound specification for a list partition"),
 					 parser_errposition(pstate, exprLocation(bound))));
+		}
 
 		result_spec->listdatums = NIL;
 		foreach(cell, spec->listdatums)
 		{
-			A_Const    *con = (A_Const *) lfirst(cell);
-			Node	   *value;
-			ListCell   *cell2;
-			bool		duplicate;
-
-			value = (Node *) make_const(pstate, &con->val, con->location);
-			value = coerce_to_target_type(pstate,
-										  value, exprType(value),
-										  get_partition_col_typid(key, 0),
-										  get_partition_col_typmod(key, 0),
-										  COERCION_ASSIGNMENT,
-										  COERCE_IMPLICIT_CAST,
-										  -1);
-
-			if (value == NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_DATATYPE_MISMATCH),
-						 errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"",
-							 format_type_be(get_partition_col_typid(key, 0)),
-								colname),
-						 parser_errposition(pstate,
-											exprLocation((Node *) con))));
-
-			/* Simplify the expression */
-			value = (Node *) expression_planner((Expr *) value);
-
-			/* Don't add to the result if the value is a duplicate */
-			duplicate = false;
-			foreach(cell2, result_spec->listdatums)
+			Node *value = lfirst(cell);
+			/* Perform the transformation only for non default partition */
+			if (!(isDefaultPartitionBound(value)))
 			{
-				Const	   *value2 = (Const *) lfirst(cell2);
+				A_Const    *con = (A_Const *) lfirst(cell);
+				ListCell   *cell2;
+				bool		duplicate;
+
+				value = (Node *) make_const(pstate, &con->val, con->location);
+				value = coerce_to_target_type(pstate,
+											value, exprType(value),
+											get_partition_col_typid(key, 0),
+											get_partition_col_typmod(key, 0),
+											COERCION_ASSIGNMENT,
+											COERCE_IMPLICIT_CAST,
+											-1);
 
-				if (equal(value, value2))
+				if (value == NULL)
+					ereport(ERROR,
+							(errcode(ERRCODE_DATATYPE_MISMATCH),
+							errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"",
+								format_type_be(get_partition_col_typid(key, 0)),
+									colname),
+							parser_errposition(pstate,
+												exprLocation((Node *) con))));
+
+				/* Simplify the expression */
+				value = (Node *) expression_planner((Expr *) value);
+
+				/* Don't add to the result if the value is a duplicate */
+				duplicate = false;
+				foreach(cell2, result_spec->listdatums)
 				{
-					duplicate = true;
-					break;
+					Const	   *value2 = (Const *) lfirst(cell2);
+
+					if (equal(value, value2))
+					{
+						duplicate = true;
+						break;
+					}
 				}
+				if (duplicate)
+					continue;
 			}
-			if (duplicate)
-				continue;
-
 			result_spec->listdatums = lappend(result_spec->listdatums,
 											  value);
 		}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 9234bc2..5bff62a 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8646,12 +8646,28 @@ get_rule_expr(Node *node, deparse_context *context,
 				PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
 				ListCell   *cell;
 				char	   *sep;
+				bool       is_def = false;
 
 				switch (spec->strategy)
 				{
 					case PARTITION_STRATEGY_LIST:
 						Assert(spec->listdatums != NIL);
 
+						foreach(cell, spec->listdatums)
+						{
+							Node *value = lfirst(cell);
+
+							if (isDefaultPartitionBound(value))
+							{
+								appendStringInfoString(buf, "DEFAULT");
+								is_def = true;
+								break;
+							}
+						}
+
+						if (is_def)
+							break;
+
 						appendStringInfoString(buf, "FOR VALUES");
 						appendStringInfoString(buf, " IN (");
 						sep = "";
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 2abd087..b01ba07 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2044,7 +2044,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 	/* Limited completion support for partition bound specification */
 	else if (TailMatches3("ATTACH", "PARTITION", MatchAny))
-		COMPLETE_WITH_CONST("FOR VALUES");
+		COMPLETE_WITH_LIST2("FOR VALUES", "DEFAULT");
 	else if (TailMatches2("FOR", "VALUES"))
 		COMPLETE_WITH_LIST2("FROM (", "IN (");
 
@@ -2483,7 +2483,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_partitioned_tables, "");
 	/* Limited completion support for partition bound specification */
 	else if (TailMatches3("PARTITION", "OF", MatchAny))
-		COMPLETE_WITH_CONST("FOR VALUES");
+		COMPLETE_WITH_LIST2("FOR VALUES", "DEFAULT");
 
 /* CREATE TABLESPACE */
 	else if (Matches3("CREATE", "TABLESPACE", MatchAny))
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index 25fb0a0..68f46fe 100644
--- a/src/include/catalog/partition.h
+++ b/src/include/catalog/partition.h
@@ -74,9 +74,12 @@ extern void RelationBuildPartitionDesc(Relation relation);
 extern bool partition_bounds_equal(PartitionKey key,
 					   PartitionBoundInfo p1, PartitionBoundInfo p2);
 
+extern bool isDefaultPartitionBound(Node *value);
 extern void check_new_partition_bound(char *relname, Relation parent, Node *bound);
 extern Oid	get_partition_parent(Oid relid);
 extern List *get_qual_from_partbound(Relation rel, Relation parent, Node *bound);
+extern List *generate_qual_for_defaultpart(Relation parent, Node *bound, Oid *defid);
+extern List *get_qual_for_default(Relation parent, Oid *defid);
 extern List *map_partition_varattnos(List *expr, int target_varno,
 						Relation partrel, Relation parent);
 extern List *RelationGetPartitionQual(Relation rel);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 4b8727e..e632a42 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -780,6 +780,7 @@ typedef struct PartitionSpec
 
 #define PARTITION_STRATEGY_LIST		'l'
 #define PARTITION_STRATEGY_RANGE	'r'
+#define PARTITION_DEFAULT	'd'
 
 /*
  * PartitionBoundSpec - a partition bound specification
