? diff.txt
? partitioning.patch
Index: GNUmakefile.in
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/GNUmakefile.in,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** GNUmakefile.in	19 May 2009 06:59:31 -0000	1.1.1.2
--- GNUmakefile.in	26 May 2009 08:04:44 -0000	1.1.1.2.2.1
***************
*** 6,23 ****
--- 6,26 ----
  
  subdir =
  top_builddir = .
+ tmp = `pwd`
  include $(top_builddir)/src/Makefile.global
  
  all:
  	$(MAKE) -C doc all
  	$(MAKE) -C src all
  	$(MAKE) -C config all
+ 	@$(tmp)/partition.sh $(tmp) > $(tmp)/partition.sql
  	@echo "All of PostgreSQL successfully made. Ready to install."
  
  install:
  	$(MAKE) -C doc $@
  	$(MAKE) -C src $@
  	$(MAKE) -C config $@
+ 	@$(tmp)/partition.sh $(tmp) > $(tmp)/partition.sql
  	@echo "PostgreSQL installation complete."
  
  installdirs uninstall:
Index: src/backend/catalog/Makefile
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/catalog/Makefile,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/catalog/Makefile	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/catalog/Makefile	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 27,33 ****
  
  POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
  	pg_proc.h pg_type.h pg_attribute.h pg_class.h \
! 	pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
  	pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
  	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
  	pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
--- 27,33 ----
  
  POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
  	pg_proc.h pg_type.h pg_attribute.h pg_class.h \
! 	pg_attrdef.h pg_constraint.h pg_inherits.h pg_partition.h pg_index.h pg_operator.h \
  	pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
  	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
  	pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
Index: src/backend/catalog/pg_inherits.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/catalog/pg_inherits.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -c -r1.1.1.1 -r1.1.1.1.2.1
*** src/backend/catalog/pg_inherits.c	19 May 2009 06:59:32 -0000	1.1.1.1
--- src/backend/catalog/pg_inherits.c	8 Jun 2009 08:28:51 -0000	1.1.1.1.2.1
***************
*** 287,289 ****
--- 287,357 ----
  
  	return result;
  }
+ 
+ /*
+  * find_inheritance_parents
+  *
+  * Returns a list containing the OIDs of all relations which
+  * are *direct* parents of the relation with OID 'inhchild'.
+  *
+  * This method is a logical copy of find_inheritance_children
+  */
+ List *
+ find_inheritance_parents(Oid inhchild)
+ {
+ 	List	   *list = NIL;
+ 	Relation	relation;
+ 	HeapScanDesc scan;
+ 	HeapTuple	inheritsTuple;
+ 	Oid			parentrelid;
+ 	ScanKeyData key[1];
+ 
+ 	/*
+ 	 * XXX : Can skip the scan if pg_attribute shows the relation has no
+ 	 * inherited column.. not sure if that will be any faster
+ 	 */
+ 
+ 	ScanKeyInit(&key[0],
+ 				Anum_pg_inherits_inhrelid,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(inhchild));
+ 	relation = heap_open(InheritsRelationId, AccessShareLock);
+ 	scan = heap_beginscan(relation, SnapshotNow, 1, key);
+ 	while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+ 	{
+ 		parentrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent;
+ 		list = lappend_oid(list, parentrelid);
+ 	}
+ 	heap_endscan(scan);
+ 	heap_close(relation, AccessShareLock);
+ 	return list;
+ }
+ 
+ /*
+  * find_all_ancestors -
+  *		Returns a list of relation OIDs of all direct and indirect
+  *		parents of the specified relation; the returned list DOES NOT
+  *		include the specified child relation OID.
+  *
+  *	Code is a logical copy of find_all_inheritors; refer comments in that method.
+  */
+ List *
+ find_all_ancestors(Oid childrel)
+ {
+ 	List	   *rels_list;
+ 	ListCell   *l;
+ 
+ 	rels_list = find_inheritance_parents(childrel);
+ 
+ 	/* see comments in find_all_inheritors for how this foreach works */
+ 	foreach(l, rels_list)
+ 	{
+ 		Oid			currentrel = lfirst_oid(l);
+ 		List	   *currentParents;
+ 
+ 		currentParents = find_inheritance_parents(currentrel);
+ 		rels_list = list_concat_unique_oid(rels_list, currentParents);
+ 	}
+ 
+ 	return rels_list;
+ }
Index: src/backend/catalog/pg_operator.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/catalog/pg_operator.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/backend/catalog/pg_operator.c	19 May 2009 06:59:32 -0000	1.1.1.2
--- src/backend/catalog/pg_operator.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 35,41 ****
  #include "utils/syscache.h"
  
  
! static Oid OperatorGet(const char *operatorName,
  			Oid operatorNamespace,
  			Oid leftObjectId,
  			Oid rightObjectId,
--- 35,41 ----
  #include "utils/syscache.h"
  
  
! Oid OperatorGet(const char *operatorName,
  			Oid operatorNamespace,
  			Oid leftObjectId,
  			Oid rightObjectId,
***************
*** 127,133 ****
   *
   *		*defined is set TRUE if defined (not a shell)
   */
! static Oid
  OperatorGet(const char *operatorName,
  			Oid operatorNamespace,
  			Oid leftObjectId,
--- 127,133 ----
   *
   *		*defined is set TRUE if defined (not a shell)
   */
! Oid
  OperatorGet(const char *operatorName,
  			Oid operatorNamespace,
  			Oid leftObjectId,
Index: src/backend/commands/copy.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/commands/copy.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/commands/copy.c	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/commands/copy.c	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 277,283 ****
  static bool CopyGetInt32(CopyState cstate, int32 *val);
  static void CopySendInt16(CopyState cstate, int16 val);
  static bool CopyGetInt16(CopyState cstate, int16 *val);
! 
  
  /*
   * Send copy start/stop messages for frontend copies.  These have changed
--- 277,284 ----
  static bool CopyGetInt32(CopyState cstate, int32 *val);
  static void CopySendInt16(CopyState cstate, int16 val);
  static bool CopyGetInt16(CopyState cstate, int16 *val);
! extern int GetPartitionsCount(Oid parentOid);
! extern List* GetPartitions(Oid parentOid);
  
  /*
   * Send copy start/stop messages for frontend copies.  These have changed
***************
*** 1401,1424 ****
  		bool	   *nulls;
  		HeapScanDesc scandesc;
  		HeapTuple	tuple;
  
  		values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
  		nulls = (bool *) palloc(num_phys_attrs * sizeof(bool));
  
! 		scandesc = heap_beginscan(cstate->rel, GetActiveSnapshot(), 0, NULL);
! 
! 		while ((tuple = heap_getnext(scandesc, ForwardScanDirection)) != NULL)
  		{
! 			CHECK_FOR_INTERRUPTS();
  
! 			/* Deconstruct the tuple ... faster than repeated heap_getattr */
! 			heap_deform_tuple(tuple, tupDesc, values, nulls);
  
- 			/* Format and send the data */
- 			CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls);
  		}
  
! 		heap_endscan(scandesc);
  	}
  	else
  	{
--- 1402,1460 ----
  		bool	   *nulls;
  		HeapScanDesc scandesc;
  		HeapTuple	tuple;
+ 		List		*partitions = NULL;
+ 		ListCell	*partition = NULL;		
+ 		Relation    tmpRel;
  
  		values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
  		nulls = (bool *) palloc(num_phys_attrs * sizeof(bool));
  
! 		/* If we are operating on partitioned table, then copy data in all the partitions.*/
! 		if(GetPartitionsCount(RelationGetRelid(cstate->rel)) > 0)
  		{
! 			/* Get partitions for table, if any.*/
! 			partitions = GetPartitions(RelationGetRelid(cstate->rel));
! 
! 			foreach(partition, partitions)
! 			{
! 				tmpRel = heap_open((Oid)lfirst_oid(partition), AccessShareLock);
! 
! 				scandesc = heap_beginscan(tmpRel, GetActiveSnapshot(), 0, NULL);
! 
! 				while ((tuple = heap_getnext(scandesc, ForwardScanDirection)) != NULL)
! 				{
! 					CHECK_FOR_INTERRUPTS();
  
! 					/* Deconstruct the tuple ... faster than repeated heap_getattr */
! 					heap_deform_tuple(tuple, tupDesc, values, nulls);
! 
! 					/* Format and send the data */
! 					CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls);
! 				}
! 
! 				heap_endscan(scandesc);
! 
! 				heap_close(tmpRel, AccessShareLock);
! 			}
  
  		}
+ 		else
+ 		{
+ 			scandesc = heap_beginscan(cstate->rel, GetActiveSnapshot(), 0, NULL);
+ 
+ 			while ((tuple = heap_getnext(scandesc, ForwardScanDirection)) != NULL)
+ 			{
+ 				CHECK_FOR_INTERRUPTS();
+ 
+ 				/* Deconstruct the tuple ... faster than repeated heap_getattr */
+ 				heap_deform_tuple(tuple, tupDesc, values, nulls);
  
! 				/* Format and send the data */
! 				CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls);
! 			}
! 
! 			heap_endscan(scandesc);
! 		}
  	}
  	else
  	{
***************
*** 2109,2115 ****
--- 2145,2165 ----
  			newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple);
  
  			if (newtuple == NULL)		/* "do nothing" */
+ 			{
  				skip_tuple = true;
+ 			}
+ 			else if((newtuple->t_len == -1) || (newtuple->t_len == -2))
+ 			{
+ 				/* If this is partitioned table we are operating on and we receive 
+ 				a dummy row signalling that row has been inserted into appropriate partition
+ 				after constraints evaluation, mark it done and do nothing. */
+ 				if(GetPartitionsCount(RelationGetRelid(cstate->rel)) > 0)
+ 				{
+ 					heap_freetuple(tuple);
+ 					cstate->processed++;
+ 					skip_tuple = true;
+ 				}
+ 			}
  			else if (newtuple != tuple) /* modified by Trigger(s) */
  			{
  				heap_freetuple(tuple);
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/commands/tablecmds.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.2
diff -c -r1.1.1.3 -r1.1.1.3.2.2
*** src/backend/commands/tablecmds.c	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/commands/tablecmds.c	26 May 2009 10:29:59 -0000	1.1.1.3.2.2
***************
*** 50,55 ****
--- 50,56 ----
  #include "nodes/makefuncs.h"
  #include "nodes/nodeFuncs.h"
  #include "nodes/parsenodes.h"
+ #include "nodes/pg_list.h"
  #include "optimizer/clauses.h"
  #include "parser/gramparse.h"
  #include "parser/parse_clause.h"
***************
*** 75,81 ****
--- 76,97 ----
  #include "utils/snapmgr.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
+ #include "tcop/tcopprot.h"
+ #include "utils/numeric.h"
  
+ /* For partitions */
+ #include "catalog/pg_partition.h"
+ #include "catalog/pg_operator.h"
+ #include "postgres.h"
+ #include "executor/spi.h"
+ #include "commands/trigger.h"
+ #include "utils/rel.h"
+ #include "commands/alter.h"
+ #include "tcop/utility.h"
+ 
+ extern Datum trigf(PG_FUNCTION_ARGS);
+ 
+ PG_FUNCTION_INFO_V1(trigf);
  
  /*
   * ON COMMIT action list
***************
*** 96,101 ****
--- 112,124 ----
  	SubTransactionId deleting_subid;
  } OnCommitItem;
  
+ 
+ typedef struct PartitionRowInfo
+ {
+     ItemPointerData tid;
+     Oid             partRelOid;
+ }PartitionRowInfo;
+ 
  static List *on_commits = NIL;
  
  
***************
*** 113,129 ****
   * a pass determined by subcommand type.
   */
  
! #define AT_PASS_DROP			0		/* DROP (all flavors) */
! #define AT_PASS_ALTER_TYPE		1		/* ALTER COLUMN TYPE */
! #define AT_PASS_OLD_INDEX		2		/* re-add existing indexes */
! #define AT_PASS_OLD_CONSTR		3		/* re-add existing constraints */
! #define AT_PASS_COL_ATTRS		4		/* set other column attributes */
  /* We could support a RENAME COLUMN pass here, but not currently used */
! #define AT_PASS_ADD_COL			5		/* ADD COLUMN */
! #define AT_PASS_ADD_INDEX		6		/* ADD indexes */
! #define AT_PASS_ADD_CONSTR		7		/* ADD constraints, defaults */
! #define AT_PASS_MISC			8		/* other stuff */
! #define AT_NUM_PASSES			9
  
  typedef struct AlteredTableInfo
  {
--- 136,161 ----
   * a pass determined by subcommand type.
   */
  
! #define AT_PASS_DROP					0		/* DROP (all flavors) */
! #define AT_PASS_ALTER_TYPE				1		/* ALTER COLUMN TYPE */
! #define AT_PASS_OLD_INDEX				2		/* re-add existing indexes */
! #define AT_PASS_OLD_CONSTR				3		/* re-add existing constraints */
! #define AT_PASS_COL_ATTRS				4		/* set other column attributes */
  /* We could support a RENAME COLUMN pass here, but not currently used */
! #define AT_PASS_ADD_COL					5		/* ADD COLUMN */
! #define AT_PASS_ADD_INDEX				6		/* ADD indexes */
! #define AT_PASS_ADD_CONSTR				7		/* ADD constraints, defaults */
! #define AT_PASS_ADD_PARTITION   		8		/* ADD partition to an existing table. */
! #define AT_PASS_DROP_PARTITION_NAME 	9   	/* DROP partition(By name) of an existing table */
! #define AT_PASS_DROP_PARTITION_RANGE 	10		/* DROP partition(By range) of an existing table */
! #define AT_PASS_UPDATE_PARTITION		11		/* UPDATE range partition. */
! #define AT_PASS_SPLIT_PARTITION			12		/* SPLIT range partition. */
! #define AT_PASS_MERGE_PARTITION			13		/* MERGE range partitions. */
! #define AT_PASS_UPDATE_HASH_PARTITION	14		/* UPDATE hash partitions. */
! #define AT_PASS_EXCHANGE_PARTITION		15		/* Exchange partition with a table.*/
! #define AT_PASS_RENAME_PARTITION		16		/* Rename partition. */
! #define AT_PASS_MISC					17		/* other stuff */
! #define AT_NUM_PASSES					18
  
  typedef struct AlteredTableInfo
  {
***************
*** 325,330 ****
--- 357,423 ----
  static void ATExecDropInherit(Relation rel, RangeVar *parent);
  static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
  							   ForkNumber forkNum, bool istemp);
+ static void CreatePartitions(CreateStmt *stmt, Oid parentRelOid, Oid *partitionRelOids);
+ static void MutateColumnRefs(Node *node, char *reference);
+ Oid OperatorGet(const char *operatorName,
+             Oid operatorNamespace,
+             Oid leftObjectId,
+             Oid rightObjectId,
+             bool *defined);
+ static char *ATExecAddPartition(AlteredTableInfo *tab, Relation rel,
+ 				Partition *part, bool dummyEntry); /* Adding partition to an existing table. */
+ static void ATExecDropPartitionByName(AlteredTableInfo *tab, Relation rel,
+ 				Partition *part); /* Deleting partition of an existing table by name. */
+ static void ATExecDropPartitionByRange(AlteredTableInfo *tab, Relation rel,
+ 				Partition *part); /* Deleting partition of an existing table by Range. */
+ static void ATExecUpdatePartition(AlteredTableInfo *tab, Relation rel,
+ 				Partition *part); /* Deleting partition of an existing table by Range. */
+ static void ATExecSplitPartition(AlteredTableInfo *tab, Relation rel,
+ 				SplitPartitionStmt *part); /* Splitting partition of an existing table. */
+ static void ATExecExchangePartition(AlteredTableInfo *tab, Relation rel,
+ 				ExchangePartitionStmt *part); /* Exchange a partition with an existing table. */
+ static void ATExecRenamePartition(AlteredTableInfo *tab, Relation rel,
+ 				RenamePartitionStmt *part); /* Rename a partition. */
+ static void ATExecMergePartition(AlteredTableInfo *tab, Relation rel,
+ 				MergePartitionStmt *part); /* Merge existing partitions. */
+ static void ATExecUpdateHashPartition(AlteredTableInfo *tab, Relation rel,
+ 				A_Const *part); /* Deleting partition of an existing table by Range. */
+ static Oid CreateInheritedTable(Oid relId, char *name, char *tablespace);
+ char* DisplayDatum(Datum datum, Oid type);
+ Datum GetDatum(Relation rel, Oid type, HeapTuple tuple, int column);
+ Oid get_relevant_partition(HeapTuple tuple, Relation rel);
+ Oid get_relevant_hash_partition(HeapTuple tuple, Relation rel);
+ bool IsPartition(Oid partOid);
+ bool IsOverflowPartition(Oid parentOid);
+ int GetPartitionType(Oid partOid);
+ int GetPartitionsCount(Oid parentOid);
+ int GetPartitionsCountAtt(Oid parentOid, Oid attNum);
+ List* GetPartitions(Oid parentOid);
+ void DeletePartitionEntries(Oid parentOid);
+ void DeletePartitionEntry(Oid partOid);
+ void RemoveOverflowPartition(Oid parentOid);
+ bool GotConstraints(Oid relId);
+ Node* makeColumnRef(char *colname, List *indirection, int location);
+ void AddLessThanCheckConstraint(Oid typ_oid, Datum max_datum, char *tableName, char *partitionColumn);
+ void AddGreaterThanCheckConstraint(Oid typ_oid, Datum max_datum, char *tableName, char *partitionColumn);
+ bool IsMinValue(Node *value);
+ bool IsMaxValue(Node *value);
+ int GetPartitionedTableType(Oid parentOid);
+ List *GetMaxValues(Oid parentOid);
+ List *GetMinValues(Oid parentOid);
+ List *GetPartitionAttributes(Oid parentOid);
+ List *GetPartitionAttributeTypes(Oid parentOid);
+ List *GetPartitionNames(Oid parentOid);
+ char *GetPartitionedTableFromOverflow(Oid parentOid);
+ bool GotTriggers(Oid relId);
+ void InsertTuple(HeapTuple newtuple, Oid targetId);
+ Oid  GetOverflowPartition(Relation rel);
+ void MoveValidRowsFromOverflow(Oid relId, Oid partId);
+ void RemoveConstraintsAttr(Oid relId, int attNumber);
+ Oid  GetOverflowIndexId(Oid relId);
+ void GetPartitionValues(Oid partOid, List **minValues, List **maxValues, List **attrs, int *nKeys);
+ Oid  GetProcId(Oid operOid);
+ 
  
  
  /* ----------------------------------------------------------------
***************
*** 685,690 ****
--- 778,806 ----
  			continue;
  		}
  
+ 		if(relOid != InvalidOid)
+ 		{
+ 			/* If partitioned-table is being dropped then delete entries from catalog table. */
+ 			if(GetPartitionsCount(relOid) > 0)
+ 			{
+ 				DeletePartitionEntries(relOid);
+ 				RemoveOverflowPartition(relOid);
+ 			}
+ 			/* Check if it is a partition. */
+ 			else if(IsPartition(relOid) == true)
+ 			{
+ 				if(GetPartitionType(relOid) == PART_RANGE)
+ 					elog(ERROR, "Can not drop partition. Use ALTER TABLE ... DROP PARTITION instead.");
+ 				else
+ 					elog(ERROR, "Can not drop partition. Use ALTER TABLE ... UPDATE PARTITIONS instead.");
+ 			}
+ 			/* Check if it an overflow partition. */
+ 			else if(IsOverflowPartition(relOid) == true)
+ 			{
+ 				elog(ERROR, "Can not drop overflow partition.");
+ 			}
+ 		}
+ 
  		/*
  		 * In DROP INDEX, attempt to acquire lock on the parent table before
  		 * locking the index.  index_drop() will need this anyway, and since
***************
*** 2200,2205 ****
--- 2316,2962 ----
  }
  
  /*
+  * GetPartitionedTableType: If it is hash/list/range. 
+  */
+ int GetPartitionedTableType(Oid parentOid)
+ {
+ 	ScanKeyData skey;
+ 	Relation    pg_partrel;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 	int			partitionType;
+ 
+ 	partitionType = 0;
+ 	
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		/* Every partition will have only one entry for keyorder == 1 */	
+ 		if(pg_part->keyorder == 1)
+ 		{
+ 			partitionType = pg_part->parttype;
+ 			break;
+ 		}
+ 	}
+ 
+ 	systable_endscan(pg_partscan);
+ 	heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return partitionType;
+ } 
+ 
+ 
+ /*
+  * GetPartitionType: If it is hash/list/range. 
+  */
+ int GetPartitionType(Oid partOid)
+ {
+ 	ScanKeyData skey;
+ 	Relation    pg_partrel;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 	int			partitionType;
+ 
+ 	partitionType = 0;
+ 	
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_partrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(partOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		/* Every partition will have only one entry for keyorder == 1 */	
+ 		if(pg_part->keyorder == 1)
+ 		{
+ 			partitionType = pg_part->parttype;
+ 			break;
+ 		}
+ 	}
+ 
+ 	systable_endscan(pg_partscan);
+ 	heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return partitionType;
+ } 
+ 
+ /*
+  * IsPartition : Check if given table is a partition. 
+  */
+ bool IsPartition(Oid partOid)
+ {
+ 	ScanKeyData skey;
+ 	Relation    pg_partrel;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 	int			partitions;
+ 
+ 	partitions = 0;
+ 	
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_partrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(partOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		/* Every partition will have only one entry for keyorder == 1 */	
+ 		if(pg_part->keyorder == 1)
+ 			partitions++;
+ 	}
+ 
+ 	systable_endscan(pg_partscan);
+ 	heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return partitions > 0 ? true : false;
+ } 
+ 
+ 
+ /*
+  * GetPartitions : Check if given table is a partitioned table and return the list of
+  * partitions. 
+  */
+ List * 
+ GetPartitions(Oid parentOid)
+ {
+ 	ScanKeyData skey;
+ 	Relation    pg_partrel;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 	List		*partitions = NULL;
+ 	Relation	rel;
+ 	Oid			overflow;
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		/* Every partition will have only one entry for keyorder == 1 */	
+ 		if(pg_part->keyorder == 1)
+ 		{
+ 			partitions = lappend_oid(partitions, pg_part->partrelid);
+ 		}
+ 	}
+ 
+ 	/* Also add overflow partition(if any) for this partitinoed table. */
+ 	rel = RelationIdGetRelation(parentOid);
+ 	overflow = GetOverflowPartition(rel);
+ 	
+ 	if(overflow != InvalidOid)
+ 	{
+ 		partitions = lappend_oid(partitions, overflow);
+ 	}
+ 	
+ 	RelationClose(rel);
+ 
+ 	systable_endscan(pg_partscan);
+ 	heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return partitions;
+ }
+ 
+ List *
+ GetMaxValues(Oid parentOid)
+ {
+     ScanKeyData skey;
+     Relation    pg_partrel;
+     SysScanDesc pg_partscan;
+     HeapTuple   pg_parttup;
+     List        *maxValues = NULL;
+ 	char		*max = "MAXVALUE";
+ 	Datum 		values[Natts_pg_partition];
+ 	char  		nulls [Natts_pg_partition];	
+ 	
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+         /* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
+         heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
+ 
+ 		if(nulls[Anum_pg_partition_maxval-1] == 'n')
+ 		{
+ 			maxValues = lappend(maxValues, max);
+ 		}
+ 		else
+ 		{
+ 			maxValues = lappend(maxValues, DisplayDatum(GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval), pg_part->keytype));
+ 		}
+ 	}
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return maxValues;
+ }
+ 
+ List *
+ GetMinValues(Oid parentOid)
+ {
+     ScanKeyData skey;
+     Relation    pg_partrel;
+     SysScanDesc pg_partscan;
+     HeapTuple   pg_parttup;
+     List        *minValues = NULL;
+ 	char		*min = "MINVALUE";
+ 	Datum 		values[Natts_pg_partition];
+ 	char  		nulls [Natts_pg_partition];	
+ 	
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+         /* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
+         heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
+ 
+ 		if(nulls[Anum_pg_partition_minval-1] == 'n')
+ 		{
+ 			minValues = lappend(minValues, min);
+ 		}
+ 		else
+ 		{
+ 			minValues = lappend(minValues, DisplayDatum(GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval), pg_part->keytype));
+ 		}
+ 	}
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return minValues;
+ }
+ 
+ List *
+ GetPartitionAttributes(Oid parentOid)
+ {
+     List    *partitionAttrs = NULL;
+ 	List	*partitionAttrNumbers = NULL;
+ 
+     ScanKeyData skey;
+     Relation    pg_partrel;
+     SysScanDesc pg_partscan;
+     HeapTuple   pg_parttup;
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		if(!list_member_int(partitionAttrNumbers, pg_part->partkey))
+ 		{
+ 			partitionAttrNumbers = lappend_int(partitionAttrNumbers, pg_part->partkey);
+ 			partitionAttrs = lappend(partitionAttrs, get_attname(pg_part->partrelid, pg_part->partkey));
+ 		}
+     }
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return partitionAttrs;
+ }
+ 
+ List *
+ GetPartitionAttributeTypes(Oid parentOid)
+ {
+     List    *partitionAttrTypes = NULL;
+ 	List	*partitionAttrNumbers = NULL;
+ 
+     ScanKeyData skey;
+     Relation    pg_partrel;
+     SysScanDesc pg_partscan;
+     HeapTuple   pg_parttup;
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		if(!list_member_int(partitionAttrNumbers, pg_part->partkey))
+ 		{
+ 			partitionAttrNumbers = lappend_int(partitionAttrNumbers, pg_part->partkey);
+ 			partitionAttrTypes = lappend_int(partitionAttrTypes, pg_part->keytype);
+ 		}
+     }
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return partitionAttrTypes;
+ } 
+ 
+ List *
+ GetPartitionNames(Oid parentOid)
+ {
+ 	List		*partitions = NULL;
+ 	List		*partitionNames = NULL;
+ 	ListCell	*partition;
+ 
+ 	partitions = GetPartitions(parentOid);
+ 
+ 	foreach(partition, partitions)
+ 	{
+ 		if(IsOverflowPartition(lfirst_oid(partition))==false)
+ 		{
+ 			Relation rel = RelationIdGetRelation((Oid)lfirst_oid(partition));
+ 			partitionNames = lappend(partitionNames, RelationGetRelationName(rel));
+ 			RelationClose(rel);
+ 		}
+ 	}
+ 	
+ 	return partitionNames;
+ }
+ 
+ char *
+ GetPartitionedTableFromOverflow(Oid parentOid)
+ {
+     Relation    rel;
+     Oid         oid = 0;
+     int         length;
+     int         i;
+     int         offset = 0;
+ 	int			size;
+ 	char		*relName;
+ 
+     rel = RelationIdGetRelation(parentOid);
+ 
+ 	if(rel == NULL)
+ 		return NULL;
+ 
+     length = strlen(RelationGetRelationName(rel));
+ 
+     if(strncmp(RelationGetRelationName(rel), "of_", 3) == 0)
+     {
+         for(i=3; i<length; i++)
+         {
+             if(RelationGetRelationName(rel)[i] == '_')
+             {
+                 offset = i + 1;
+                 continue;
+             }
+         }
+ 
+ 		size = offset - 3;
+ 		relName = palloc(size);
+ 		strncpy(relName, RelationGetRelationName(rel)+3, size);
+ 		relName[size-1] = '\0';
+ 
+         sscanf(RelationGetRelationName(rel) + offset, "%u", &oid);
+         relation_close(rel, 0);
+ 
+         if(GetPartitionsCount(oid) > 0)
+ 		{
+ 			Relation tmpRel = RelationIdGetRelation(oid);
+ 		
+ 			if(tmpRel == NULL)
+ 				return NULL;
+ 
+ 			if(strncmp(RelationGetRelationName(tmpRel), relName, strlen(RelationGetRelationName(tmpRel))) == 0)
+ 			{
+         		relation_close(tmpRel, 0);
+ 			    return relName;
+ 			}
+ 		}
+     }
+ 
+     relation_close(rel, 0);
+     return NULL;
+ }
+ 
+ 
+ bool IsOverflowPartition(Oid parentOid)
+ {
+     Relation    rel;
+ 	Oid			oid = 0;
+ 	int			length;
+ 	int			i;
+ 	int			offset = 0;
+ 
+     rel = RelationIdGetRelation(parentOid);
+ 	length = strlen(RelationGetRelationName(rel));
+ 	
+ 	if(strncmp(RelationGetRelationName(rel), "of_", 3) == 0)
+ 	{
+ 		for(i=3; i<length; i++)
+ 		{
+ 			if(RelationGetRelationName(rel)[i] == '_')
+ 			{
+ 				offset = i + 1;
+ 				continue;
+ 			}			
+ 		}
+ 
+ 		sscanf(RelationGetRelationName(rel) + offset, "%u", &oid);
+ 		relation_close(rel, 0);
+ 
+ 		if(GetPartitionsCount(oid) > 0)
+ 			return true;
+ 		else
+ 			return false;
+ 	}
+ 	else
+ 	{
+ 		relation_close(rel, 0);
+ 		return false;
+ 	}
+ }
+ 
+ /*
+  * RemoveOverflowPartition : Remove the overflow partition for a given partitioned-table.
+  */
+ void RemoveOverflowPartition(Oid parentOid)
+ {
+ 	Relation 	rel;
+ 	StringInfo	query = makeStringInfo();
+ 	StringInfo	tableName = makeStringInfo();
+ 	List		*queryList;
+ 	Node		*parseTree;	
+ 
+ 	rel = RelationIdGetRelation(parentOid);
+ 	appendStringInfo(tableName, "of_%s_%u", RelationGetRelationName(rel), RelationGetRelid(rel));
+ 	relation_close(rel, 0);
+ 
+ 	if(RelnameGetRelid(tableName->data) != InvalidOid)
+ 	{
+ 		appendStringInfo(query, "DROP TABLE %s CASCADE;", tableName->data);
+ 
+ 		queryList = pg_parse_query(query->data);
+ 		parseTree = (Node *)lfirst(list_head(queryList));
+ 		RemoveRelations((DropStmt *)parseTree);
+ 	}
+ }
+ 
+ /*
+  * DeletePartitionEntry: Remove entries from partition catalog for a given relid. 
+  */
+ void DeletePartitionEntry(Oid partOid)
+ {
+ 	ScanKeyData skey;
+ 	Relation    pg_partrel;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_partrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(partOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		if(pg_part->parttype == PART_RANGE)
+ 		{
+ 	        simple_heap_delete(pg_partrel, &pg_parttup->t_self);
+     	    CommandCounterIncrement();
+ 		}
+ 		else
+ 		{
+ 			elog(ERROR, "Can not drop hash partition using ALTER TABLE ... DROP PARTITION. Use ALTER TABLE ... UPDATE PARTITIONS instead.");
+ 		}
+ 	}
+ 
+ 	systable_endscan(pg_partscan);
+ 	heap_close(pg_partrel, AccessShareLock);
+ } 
+ 
+ /*
+  * DeletePartitionEntries: Remove entries from partition catalog for a given relid. 
+  */
+ void DeletePartitionEntries(Oid parentOid)
+ {
+ 	ScanKeyData skey;
+ 	Relation    pg_partrel;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+ 	{
+         simple_heap_delete(pg_partrel, &pg_parttup->t_self);
+         CommandCounterIncrement();
+ 	}
+ 
+ 	systable_endscan(pg_partscan);
+ 	heap_close(pg_partrel, AccessShareLock);
+ } 
+ 
+ /*
+  * GetPartitionsCount: Check if given table is a partitioned table and return count of partitions. 
+  */
+ int GetPartitionsCount(Oid parentOid)
+ {
+ 	ScanKeyData skey;
+ 	Relation    pg_partrel;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 	int			partitions;
+ 
+ 	partitions = 0;
+ 	
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		/* Every partition will have only one entry for keyorder == 1 */	
+ 		if(pg_part->keyorder == 1)
+ 			partitions++;
+ 	}
+ 
+ 	systable_endscan(pg_partscan);
+ 	heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return partitions;
+ } 
+ 
+ /*
+  * GetPartitionsCountAtt : Check if given table is a partitioned table and there 
+  * exists atleast one partition(s) for specified partition key column.
+  */
+ int GetPartitionsCountAtt(Oid parentOid, Oid attNum)
+ {
+ 	ScanKeyData skey;
+ 	Relation    pg_partrel;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 	int			partitions;
+ 
+ 	partitions = 0;
+ 	
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		if(pg_part->partkey == attNum)
+ 			partitions++;
+ 	}
+ 
+ 	systable_endscan(pg_partscan);
+ 	heap_close(pg_partrel, AccessShareLock);
+ 
+ 	return partitions;
+ } 
+ 
+ 
+ /*
   * AlterTable
   *		Execute ALTER TABLE, which can be a list of subcommands
   *
***************
*** 2357,2362 ****
--- 3114,3123 ----
  	 */
  	switch (cmd->subtype)
  	{
+ 		case AT_AddPartition:	/* Add partition to an existing table. */
+ 			ATSimplePermissions(rel, false);
+ 			pass = AT_PASS_ADD_PARTITION;	
+ 			break;
  		case AT_AddColumn:		/* ADD COLUMN */
  			ATSimplePermissions(rel, false);
  			/* Performs own recursion */
***************
*** 2382,2404 ****
  			/* No command-specific prep needed */
  			pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP;
  			break;
! 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
  			ATSimplePermissions(rel, false);
! 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
! 			/* No command-specific prep needed */
! 			pass = AT_PASS_DROP;
  			break;
! 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
  			ATSimplePermissions(rel, false);
! 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
! 			/* No command-specific prep needed */
! 			pass = AT_PASS_ADD_CONSTR;
  			break;
! 		case AT_SetStatistics:	/* ALTER COLUMN STATISTICS */
! 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
! 			/* Performs own permission checks */
! 			ATPrepSetStatistics(rel, cmd->name, cmd->def);
! 			pass = AT_PASS_COL_ATTRS;
  			break;
  		case AT_SetStorage:		/* ALTER COLUMN STORAGE */
  			ATSimplePermissions(rel, false);
--- 3143,3197 ----
  			/* No command-specific prep needed */
  			pass = cmd->def ? AT_PASS_ADD_CONSTR : AT_PASS_DROP;
  			break;
! 		case AT_DropPartitionByName: /* Drop partition by Name.*/
  			ATSimplePermissions(rel, false);
! 			pass = AT_PASS_DROP_PARTITION_NAME;	
  			break;
! 		case AT_DropPartitionByRange: /* Drop partition by Range*/
  			ATSimplePermissions(rel, false);
! 			pass = AT_PASS_DROP_PARTITION_RANGE;	
  			break;
! 		case AT_ExchangePartition: /* Drop partition by Range*/
! 			ATSimplePermissions(rel, false);
! 			pass = AT_PASS_EXCHANGE_PARTITION;	
! 			break;
! 		case AT_RenamePartition: /* Drop partition by Range*/
! 			ATSimplePermissions(rel, false);
! 			pass = AT_PASS_RENAME_PARTITION;	
! 			break;
! 		case AT_UpdatePartition: /* Update the range partition.*/
! 			ATSimplePermissions(rel, false);
! 			pass = AT_PASS_UPDATE_PARTITION;
! 			break;
! 		case AT_UpdateHashPartition: /* Update the hash partition. */
! 			ATSimplePermissions(rel, false);
! 			pass = AT_PASS_UPDATE_HASH_PARTITION;
! 			break;
! 		case AT_SplitPartition: /* Split partition. */
! 			ATSimplePermissions(rel, false);
! 			pass = AT_PASS_SPLIT_PARTITION;
! 			break;
! 		case AT_MergePartition: /* Merge partitions. */
! 			ATSimplePermissions(rel, false);
! 			pass = AT_PASS_MERGE_PARTITION;
! 			break;
! 		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
! 			ATSimplePermissions(rel, false);
! 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
! 			/* No command-specific prep needed */
! 			pass = AT_PASS_DROP;
! 			break;
! 		case AT_SetNotNull:		/* ALTER COLUMN SET NOT NULL */
! 			ATSimplePermissions(rel, false);
! 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
! 			/* No command-specific prep needed */
! 			pass = AT_PASS_ADD_CONSTR;
! 			break;
! 		case AT_SetStatistics:	/* ALTER COLUMN STATISTICS */
! 			ATSimpleRecursion(wqueue, rel, cmd, recurse);
! 			/* Performs own permission checks */
! 			ATPrepSetStatistics(rel, cmd->name, cmd->def);
! 			pass = AT_PASS_COL_ATTRS;
  			break;
  		case AT_SetStorage:		/* ALTER COLUMN STORAGE */
  			ATSimplePermissions(rel, false);
***************
*** 2596,2601 ****
--- 3389,3397 ----
  {
  	switch (cmd->subtype)
  	{
+ 		case AT_AddPartition:   /* Add partition to an existing table. */
+ 			ATExecAddPartition(tab, rel, (Partition *)cmd->def, false);
+ 			break;
  		case AT_AddColumn:		/* ADD COLUMN */
  		case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
  			ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def, false);
***************
*** 2603,2608 ****
--- 3399,3428 ----
  		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
  			ATExecColumnDefault(rel, cmd->name, cmd->def);
  			break;
+ 		case AT_DropPartitionByName:	/* DROP partition(by name) of an existing table.*/
+ 			ATExecDropPartitionByName(tab, rel, (Partition *)cmd->def);
+ 			break;
+ 		case AT_DropPartitionByRange:	/* DROP partition(by range) of an existing table.*/
+ 			ATExecDropPartitionByRange(tab, rel, (Partition *)cmd->def);
+ 			break;
+ 		case AT_ExchangePartition:	/* Exchange partition with a table.*/
+ 			ATExecExchangePartition(tab, rel, (ExchangePartitionStmt *)cmd->def);
+ 			break;
+ 		case AT_RenamePartition:	/* Rename a partition.*/
+ 			ATExecRenamePartition(tab, rel, (RenamePartitionStmt *)cmd->def);
+ 			break;
+ 		case AT_UpdatePartition: /* Update Range partition.*/
+ 			ATExecUpdatePartition(tab, rel, (Partition *)cmd->def);
+ 			break;
+ 		case AT_UpdateHashPartition: /* Update Range partition.*/
+ 			ATExecUpdateHashPartition(tab, rel, (A_Const *)cmd->def);
+ 			break;
+ 		case AT_SplitPartition: /* Update Range partition.*/
+ 			ATExecSplitPartition(tab, rel, (SplitPartitionStmt *)cmd->def);
+ 			break;
+ 		case AT_MergePartition: /* Update Range partition.*/
+ 			ATExecMergePartition(tab, rel, (MergePartitionStmt *)cmd->def);
+ 			break;
  		case AT_DropNotNull:	/* ALTER COLUMN DROP NOT NULL */
  			ATExecDropNotNull(rel, cmd->name);
  			break;
***************
*** 3431,3496 ****
  											 origTblName, origTypeName);
  		}
  
! 		relation_close(rel, AccessShareLock);
! 	}
  
! 	systable_endscan(depScan);
  
! 	relation_close(depRel, AccessShareLock);
  
! 	/*
! 	 * If there's an array type for the rowtype, must check for uses of it,
! 	 * too.
! 	 */
! 	arrayOid = get_array_type(typeOid);
! 	if (OidIsValid(arrayOid))
! 		find_composite_type_dependencies(arrayOid, origTblName, origTypeName);
! }
  
  
! /*
!  * ALTER TABLE ADD COLUMN
!  *
!  * Adds an additional attribute to a relation making the assumption that
!  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
!  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
!  * AlterTableCmd's.
!  */
! static void
! ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
! 				AlterTableCmd *cmd)
! {
! 	/*
! 	 * Recurse to add the column to child classes, if requested.
! 	 *
! 	 * We must recurse one level at a time, so that multiply-inheriting
! 	 * children are visited the right number of times and end up with the
! 	 * right attinhcount.
! 	 */
! 	if (recurse)
! 	{
! 		AlterTableCmd *childCmd = copyObject(cmd);
! 		ColumnDef  *colDefChild = (ColumnDef *) childCmd->def;
  
! 		/* Child should see column as singly inherited */
! 		colDefChild->inhcount = 1;
! 		colDefChild->is_local = false;
  
! 		ATOneLevelRecursion(wqueue, rel, childCmd);
  	}
! 	else
  	{
! 		/*
! 		 * If we are told not to recurse, there had better not be any child
! 		 * tables; else the addition would put them out of step.
! 		 */
! 		if (find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
! 					 errmsg("column must be added to child tables too")));
  	}
  }
  
  static void
  ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
  				ColumnDef *colDef, bool isOid)
--- 4251,7481 ----
  											 origTblName, origTypeName);
  		}
  
! 		relation_close(rel, AccessShareLock);
! 	}
! 
! 	systable_endscan(depScan);
! 
! 	relation_close(depRel, AccessShareLock);
! 
! 	/*
! 	 * If there's an array type for the rowtype, must check for uses of it,
! 	 * too.
! 	 */
! 	arrayOid = get_array_type(typeOid);
! 	if (OidIsValid(arrayOid))
! 		find_composite_type_dependencies(arrayOid, origTblName, origTypeName);
! }
! 
! 
! /*
!  * ALTER TABLE ADD COLUMN
!  *
!  * Adds an additional attribute to a relation making the assumption that
!  * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
!  * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
!  * AlterTableCmd's.
!  */
! static void
! ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
! 				AlterTableCmd *cmd)
! {
! 	/*
! 	 * Recurse to add the column to child classes, if requested.
! 	 *
! 	 * We must recurse one level at a time, so that multiply-inheriting
! 	 * children are visited the right number of times and end up with the
! 	 * right attinhcount.
! 	 */
! 	if (recurse)
! 	{
! 		AlterTableCmd *childCmd = copyObject(cmd);
! 		ColumnDef  *colDefChild = (ColumnDef *) childCmd->def;
! 
! 		/* Child should see column as singly inherited */
! 		colDefChild->inhcount = 1;
! 		colDefChild->is_local = false;
! 
! 		ATOneLevelRecursion(wqueue, rel, childCmd);
! 	}
! 	else
! 	{
! 		/*
! 		 * If we are told not to recurse, there had better not be any child
! 		 * tables; else the addition would put them out of step.
! 		 */
! 		if (find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
! 					 errmsg("column must be added to child tables too")));
! 	}
! }
! 
! /*
!  * IsValidRange : Check if the given range has values of valid types and 
!  *	min value is less than max value.
!  */
! static bool 
! IsValidRange(ListCell *minIndex, ListCell *maxIndex, Oid parentRelOid, char *partitionColumn, char *tableName)
! {
! 
! 	Oid 		typ_oid;
! 	int16		len;
! 	bool		typbyval;
! 	Node		*expr;
! 	Datum		min_datum;
! 	Datum		max_datum;
! 	Oid			keycmp_oid;
! 	bool		isdef;
! 	Oid			keycmp_proc;
! 	bool		lt_max;
! 	bool		isMinVal = false;
! 
! 	/* Get the attribute type. */
! 	typ_oid = get_atttype(parentRelOid, get_attnum(parentRelOid, partitionColumn));
! 
! 	/* Get the attribute length*/
! 	get_typlenbyval(typ_oid, &len, &typbyval);
! 
! 	if(minIndex == NULL || maxIndex == NULL)
! 		elog(ERROR, "Please specify the values for '%s' attribute of '%s' partition.", partitionColumn, tableName);
! 
! 	if(IsA(lfirst(minIndex), ColumnRef))
! 	{
! 		ColumnRef	*colRef = lfirst(minIndex);		
! 		
! 		if(list_length(colRef->fields) == 1)
! 		{
! 			if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "minvalue") == 0)
! 			{
! 				isMinVal = true;
! 			}
! 			else
! 			{
! 				elog(ERROR, "Please specify valid value for '%s' of '%s' partition.", partitionColumn, tableName);
! 			}
! 		}
! 	}
! 	else
! 	{
! 		/* Transform the expression from "A_Expr" type to "OpExpr" type. This is needed
! 		as expression evaluation does not happen at parser level. */
! 		expr = transformExpr(NULL, (Node *)lfirst(minIndex));
! 	}
! 
! 	if(isMinVal == false)
! 	{
! 		/* Solve the expression. */
! 		lfirst(minIndex) = eval_const_expressions(NULL, expr);
! 
! 		/* Convert the value to column's datatype. */
! 		lfirst(minIndex) = coerce_to_specific_type(NULL, lfirst(minIndex), typ_oid, partitionColumn);
! 
! 
! 		/* If it's a FuncExpr then execute the conversion function. */
! 		if IsA((Node *)lfirst(minIndex), FuncExpr)
! 		{
! 			min_datum = OidFunctionCall1(((FuncExpr *)lfirst(minIndex))->funcid,
! 							((Const *)lfirst(list_head(((FuncExpr *)lfirst(minIndex))->args)))->constvalue);
! 			/* Store the datums back. */
! 			((Const *)lfirst(minIndex))->constvalue = min_datum;
! 		}
! 		else
! 		{
! 			min_datum = ((Const *)lfirst(minIndex))->constvalue;
! 		}
! 	}
! 
! 	if(IsA(lfirst(maxIndex), ColumnRef))
! 	{
! 		ColumnRef	*colRef = lfirst(maxIndex);		
! 		
! 		if(list_length(colRef->fields) == 1)
! 		{
! 			if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "maxvalue") == 0)
! 			{
! 				if(isMinVal == true )		
! 					elog(ERROR, "Please specify valid range for '%s' of '%s'.", partitionColumn, tableName);
! 				else
! 					return true;
! 			}
! 			else
! 			{
! 				elog(ERROR, "Please specify valid value for '%s' of '%s' partition.", partitionColumn, tableName);
! 			}
! 		}
! 	}
! 	else
! 	{
! 		/* Transform the expression from "A_Expr" type to "OpExpr" type. This is needed
! 		as expression evaluation does not happen at parser level. */
! 		expr = transformExpr(NULL, (Node *)lfirst(maxIndex));
! 	}
! 
! 	/* Solve the expression. */
! 	lfirst(maxIndex) = eval_const_expressions(NULL, expr);
! 
! 	/* Convert the value to column's datatype. */
! 	lfirst(maxIndex) = coerce_to_specific_type(NULL, lfirst(maxIndex), typ_oid, partitionColumn);
! 
! 
! 	/* If it's a FuncExpr then execute the conversion function. */
! 	if IsA((Node *)lfirst(maxIndex), FuncExpr)
! 	{
! 		max_datum = OidFunctionCall1(((FuncExpr *)lfirst(maxIndex))->funcid,
! 						((Const *)lfirst(list_head(((FuncExpr *)lfirst(maxIndex))->args)))->constvalue);
! 		/* Store the datums back. */
! 		((Const *)lfirst(maxIndex))->constvalue = max_datum;
! 	}
! 	else
! 	{
! 		max_datum = ((Const *)lfirst(maxIndex))->constvalue;
! 	}
! 	
! 	if(isMinVal == true)
! 		return true;
! 
! 	keycmp_oid = OperatorGet("<", PG_CATALOG_NAMESPACE , typ_oid, typ_oid, &isdef);
! 
! 	if(isdef == FALSE)
! 		elog(ERROR, "'<' operator is not defined for this type.");
! 
! 	keycmp_proc = get_opcode(keycmp_oid);
! 	lt_max = DatumGetBool(OidFunctionCall2(keycmp_proc, min_datum, max_datum));
! 
! 	if(lt_max == 0)
! 	{
! 		if(tableName)
! 		{
! 			elog(ERROR, "First value should be less then second value for '%s' attribute of partition '%s'.",
! 					partitionColumn, tableName);
! 		}
! 		else
! 		{
! 			elog(ERROR, "First value should be less then second value for '%s' attribute.",
! 					partitionColumn);
! 		}
! 	}
! 
! 	return lt_max;
! }
! 
! static void
! ApplyHashPartitionTriggers(Oid relId)
! {
! 	Relation 	rel;
! 	List		*queryList;
! 	Node		*parseTree;
! 	StringInfo	createTrigger = makeStringInfo();
! 	
! 
! 	/* Add triggers on hash partitions. */	
! 	rel = RelationIdGetRelation(relId);
! 	resetStringInfo(createTrigger);
! 	appendStringInfo(createTrigger, "CREATE TRIGGER partition_update_%u BEFORE UPDATE ON %s ", RelationGetRelid(rel), RelationGetRelationName(rel));
! 	appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_update_trigger();");
! 
! 	/* Parse the above SQL string and use this parsetree to create trigger on parent table. */
! 	queryList = pg_parse_query(createTrigger->data);
! 	parseTree = (Node *)lfirst(list_head(queryList));
! 	CreateTrigger((CreateTrigStmt * )parseTree, 0, false);
! 
! 	/* To avoid tuple being updated by the current transaction, after the current scan started */
! 	CommandCounterIncrement();
! 
! 	/* We can not create constraints for hash partitions directly. Instead, we will monitor inserts using insert triggers.*/
! 	resetStringInfo(createTrigger);
! 	appendStringInfo(createTrigger, "CREATE TRIGGER partition_constraints_%u BEFORE INSERT ON %s ",RelationGetRelid(rel),  RelationGetRelationName(rel));
! 	appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_constraints_hash();");
! 	relation_close(rel, 0);
! 
! 	/* Parse the above SQL string and use this parsetree to create trigger on parent table. */
! 	queryList = pg_parse_query(createTrigger->data);
! 	parseTree = (Node *)lfirst(list_head(queryList));
! 	CreateTrigger((CreateTrigStmt * )parseTree, 0, false);
! }
! 
! /*
!  * WriteHashPartitionToCatalog : Write the partition information for a given attribute
!  * to pg_partition.
!  */ 
! static bool
! WriteHashPartitionToCatalog(Oid	partRelOid,
! 								Oid parentRelOid,
! 								int	attNum,
! 								Oid typ_oid,
! 								int keyOrder,
! 								int hashValue)
! {
! 
! 	Datum 			values[Natts_pg_partition];
! 	bool  			nulls [Natts_pg_partition];
! 	int				i;
! 	Relation        r;
! 	TupleDesc       tupDesc;
! 	HeapTuple       tup;
! 
! 	/* initialize nulls and values */
! 	for (i = 0; i < Natts_pg_partition; i++)
! 	{
! 		nulls[i] = false;
! 		values[i] = (Datum) NULL;
! 	}
! 
! 	values[Anum_pg_partition_minval        -1] = Int8GetDatum(NULL);
! 	nulls[Anum_pg_partition_minval        -1] = true;
! 	values[Anum_pg_partition_maxval        -1] = Int8GetDatum(NULL);
! 	nulls[Anum_pg_partition_maxval        -1] = true;
! 	values[Anum_pg_partition_parentrelid -1]= ObjectIdGetDatum(parentRelOid);
! 	values[Anum_pg_partition_partrelid  -1] = ObjectIdGetDatum(partRelOid);
! 	values[Anum_pg_partition_parttype   -1] = Int8GetDatum(PART_HASH);
! 	values[Anum_pg_partition_partkey    -1] = ObjectIdGetDatum(attNum);
! 	values[Anum_pg_partition_listval    -1] = Int8GetDatum(NULL);
! 	nulls[Anum_pg_partition_listval     -1] = true;
! 	values[Anum_pg_partition_hashval    -1] = Int8GetDatum(hashValue);
! 	values[Anum_pg_partition_keytype    -1] = ObjectIdGetDatum(typ_oid);
! 	values[Anum_pg_partition_keyorder   -1] = Int8GetDatum(keyOrder);
! 
! 	r = heap_open(PartitionRelationId, RowExclusiveLock);
! 	tupDesc = r->rd_att;
! 	tup = heap_form_tuple(tupDesc, values, nulls);
! 	simple_heap_insert(r, tup);
! 	CatalogUpdateIndexes(r, tup); 
!     heap_close(r, RowExclusiveLock);
! 	
! 	/* To avoid tuple being updated by the current transaction, after the current scan started */
! 	CommandCounterIncrement();
! 	
! 	return true;
! }
! 
! /*
!  * WriteRangePartitionToCatalog : Write the partition information for a given attribute
!  * to pg_partition.
!  */ 
! static bool
! WriteRangePartitionToCatalog(Datum min_datum,
! 								Datum max_datum,
! 								int16 len,
! 								bool typbyval,
! 								Oid parentRelOid,
! 								Oid	partRelOid,
! 								int	attNum,
! 								Oid typ_oid,
! 								int keyOrder,
! 								int	rangeVal)
! {
! 
! 	bytea 			*min_ba, *max_ba;
! 	Datum 			values[Natts_pg_partition];
! 	bool  			nulls [Natts_pg_partition];
! 	int				i;
!     Relation        r;
!     TupleDesc       tupDesc;
!     HeapTuple       tup;
! 
! 	/* initialize nulls and values */
! 	for (i = 0; i < Natts_pg_partition; i++)
! 	{
! 		nulls[i] = false;
! 		values[i] = (Datum) NULL;
! 	}
! 
! 	/* There are 3 cases here
! 	 * 1. types with length = -1
! 	 * 2. types with fixed length but passed by value (len < 4)
! 	 * 3. types with fixed length but *not* passed by value (len > 4)
! 	 */
! 	if(len > 0)
! 	{
! 		min_ba = (bytea *) palloc(len+1+VARHDRSZ);
! 		max_ba = (bytea *) palloc(len+1+VARHDRSZ);
! 
! 		if(typbyval)
! 		{
! 			memcpy(VARDATA(min_ba), &min_datum, len);
! 			memcpy(VARDATA(max_ba), &max_datum, len);
! 		}
! 		else
! 		{
! 			memcpy(VARDATA(min_ba), (char *)min_datum, len);
! 			memcpy(VARDATA(max_ba), (char *)max_datum, len);
! 		}
! 
! 		SET_VARSIZE(min_ba, len+VARHDRSZ);
! 		VARDATA(min_ba)[len] = '\0';
! 		values[Anum_pg_partition_minval        -1]= (Datum)min_ba ;
! 
! 		SET_VARSIZE(max_ba, len+VARHDRSZ);
! 		VARDATA(max_ba)[len] = '\0';
! 		values[Anum_pg_partition_maxval        -1]=(Datum)max_ba;
! 	}
! 	else
! 	{
! 		values[Anum_pg_partition_minval        -1]=min_datum;
! 		values[Anum_pg_partition_maxval        -1]=max_datum;
! 	}
! 	
! 	if(rangeVal == MINVALRANGE)
! 	{
! 		nulls[Anum_pg_partition_minval        -1] = true;		
! 	}
! 	else if(rangeVal == MAXVALRANGE)
! 	{
! 		nulls[Anum_pg_partition_maxval        -1] = true;		
! 	}
! 
! 	values[Anum_pg_partition_parentrelid -1]= ObjectIdGetDatum(parentRelOid);
! 	values[Anum_pg_partition_partrelid  -1] = ObjectIdGetDatum(partRelOid);
! 	values[Anum_pg_partition_parttype   -1] = Int8GetDatum(PART_RANGE);
! 	values[Anum_pg_partition_partkey    -1] = ObjectIdGetDatum(attNum);
! 	values[Anum_pg_partition_listval    -1] = Int8GetDatum(NULL);
! 	nulls[Anum_pg_partition_listval     -1] = true;
! 	values[Anum_pg_partition_hashval    -1] = Int8GetDatum(NULL);
! 	nulls[Anum_pg_partition_hashval     -1] = true;
! 	values[Anum_pg_partition_keytype    -1] = ObjectIdGetDatum(typ_oid);
! 	values[Anum_pg_partition_keyorder   -1] = Int8GetDatum(keyOrder);
! 
! 	r = heap_open(PartitionRelationId, RowExclusiveLock);
! 	tupDesc = r->rd_att;
! 	tup = heap_form_tuple(tupDesc, values, nulls);
! 	simple_heap_insert(r, tup);
! 	CatalogUpdateIndexes(r, tup); 
!     heap_close(r, RowExclusiveLock);
! 	
! 	/* To avoid tuple being updated by the current transaction, after the current scan started */
! 	CommandCounterIncrement();
! 	
! 	return true;
! }
! 
! char* 
! DisplayDatum(Datum datum, Oid type)
! {
! 	Oid		typeOut;
! 	bool	isVariableLength;
! 
! 	getTypeOutputInfo(type, &typeOut, &isVariableLength);
! 	return (DatumGetCString(OidFunctionCall1(typeOut, datum)));
! }
! 
! static void 
! DropCheckConstraint(char *tableName, char *partitionColumn)
! {
! 	StringInfo 	constraint = makeStringInfo();
! 	List		*query_list;
! 	Node		*parsetree;
! 
! 	appendStringInfo(constraint, "ALTER TABLE %s DROP CONSTRAINT %s_%s_check; ", 
! 		tableName, 
! 		tableName, 
! 		partitionColumn);		
! 
! 	/* Parse the above SQL string and use this parsetree to create check constraint on child tables. */
! 	query_list  = pg_parse_query(constraint->data);
! 	parsetree = (Node *)lfirst(list_head(query_list));
! 	AlterTable(( AlterTableStmt * )parsetree);		
! }
! 
! 
! static char *
! FormCheckConstraint(Oid typ_oid, Datum min_datum, Datum max_datum, char *tableName, char *partitionColumn)
! {
! 	char		*expr_string;
! 	StringInfo	func_constraint = makeStringInfo();
! 	Oid			typoutput;
! 	bool		isVariableLength;
! 
! 	resetStringInfo(func_constraint);
! 
! 	getTypeOutputInfo(typ_oid, &typoutput, &isVariableLength);
! 	expr_string = DatumGetCString(OidFunctionCall1(typoutput, min_datum));
! 
! 	/* Form the check constraint for child table. */
! 	appendStringInfo(func_constraint, "ALTER TABLE %s ADD CHECK ( %s >= '%s' ",
! 		tableName,
! 		partitionColumn,
! 		expr_string);
! 
! 	expr_string = DatumGetCString(OidFunctionCall1(typoutput, max_datum));
! 	appendStringInfo(func_constraint, " AND %s < '%s' ); ",
! 	partitionColumn,
! 	expr_string);
! 
! 	return func_constraint->data;
! }
! 
! static void 
! AddCheckConstraint(Oid typ_oid, Datum min_datum, Datum max_datum, char *tableName, char *partitionColumn)
! {
! 	StringInfo	constraint = makeStringInfo();
! 	List		*query_list;
! 	Node		*parsetree;
! 
! 	/* Form the check constraint for child table. */
! 	appendStringInfo(constraint, "%s", FormCheckConstraint(typ_oid, min_datum, max_datum, tableName, partitionColumn));
! 		
! 	/* Parse the above SQL string and use this parsetree to create check constraint on child tables. */
! 	query_list  = pg_parse_query(constraint->data);
! 	parsetree = (Node *)lfirst(list_head(query_list));
! 	AlterTable(( AlterTableStmt * )parsetree);			
! 
! }
! 
! Datum 
! GetDatum(Relation rel, Oid type, HeapTuple tuple, int column)
! {
! 	Datum		datum;
! 	int16 		len;
! 	bool		typeByVal;
! 	bool		isNull;
! 	Datum		resultantDatum;
! 
! 	/* Get len and typbyval from pg_type */
! 	get_typlenbyval(type, &len, &typeByVal);
! 
! 	/* Get min attribute from catalog */
! 	datum = heap_getattr (tuple, column, rel->rd_att, &isNull);
! 
! 	/* Three cases 
! 	 * a. datatypes with typbyval true and fix length.
! 	 * b. datatypes with byval false and fix length.
! 	 * c. extendible datatypes where length -1.
! 	 */
! 	if (typeByVal)
! 	{
! 		memcpy(&resultantDatum, VARDATA_ANY(datum), len);
! 	}
! 	else if (len != -1)
! 	{
! 		resultantDatum = (Datum)VARDATA_ANY(datum);
! 	}	
! 	
! 	return resultantDatum;
! }
! 
! static Datum 
! EvalExpr(ListCell *node, Oid type, char *colName)
! {
! 	Node 	*expr;
! 	Datum 	datum;
! 
! 	/* Transform the expression from "A_Expr" type to "OpExpr" type. This is needed
! 	as expression evaluation does not happen at parser level. */
! 	expr = transformExpr(NULL, (Node *)lfirst(node));
! 
! 	/* Solve the expression. */
! 	lfirst(node) = eval_const_expressions(NULL, expr);
! 
! 	/* Convert the value to column's datatype. */
! 	lfirst(node) = coerce_to_specific_type(NULL, lfirst(node), type, colName);
! 
! 	/* If it's a FuncExpr then execute the conversion function. */
! 	if IsA((Node *)lfirst(node), FuncExpr)
! 	{
! 		datum = OidFunctionCall1(((FuncExpr *)lfirst(node))->funcid,
! 						((Const *)lfirst(list_head(((FuncExpr *)lfirst(node))->args)))->constvalue);
! 		/* Store the datums back. */
! 		((Const *)lfirst(node))->constvalue = datum;
! 	}
! 	else
! 	{
! 		datum = ((Const *)lfirst(node))->constvalue;
! 	}
! 
! 	return datum;
! }
! 
! static bool 
! OperateDatums(char *operatorName, Oid type, Datum datum1, Datum datum2)
! {
! 	bool 			isDef;
! 	bool 			result;
! 	Oid  			operator;
! 	Oid	 			opcode;
! 
! 	operator = OperatorGet(operatorName, PG_CATALOG_NAMESPACE , type, type, &isDef);
! 
! 	if(isDef == FALSE)
! 		elog(ERROR, "'%s' operator is not defined for this type.", operatorName);
! 
! 	opcode = get_opcode(operator);
! 	result = DatumGetBool(OidFunctionCall2(opcode, datum1, datum2));
! 
! 	return result;
! }
! 
! static void 
! AddCheckConstraints(char *constraints)
! {
! 	List		*queryList;
! 	Node		*parseTree;
! 	int			i;
! 	StringInfo  tmp = makeStringInfo();
! 	int 		len = strlen(constraints);
! 
! 	/* Parse the above SQL string and use this parsetree to create check constraint on child tables. */
! 	for(i=0; i<len; i++)
! 	{
! 		if(constraints[i] == ';')
! 		{
! 			queryList  = pg_parse_query(tmp->data);
! 			parseTree  = (Node *)lfirst(list_head(queryList));
! 			AlterTable(( AlterTableStmt * )parseTree);
! 
! 			resetStringInfo(tmp);
! 		}
! 		else
! 		{
! 			appendStringInfo(tmp, "%c", constraints[i]);
! 		}
! 	}
! }
! 
! static void
! MigrateTuplesHash(Oid relId, Relation rel)
! {
! 	Snapshot		snap;
! 	Relation 		tmpRel;
! 	Relation		child_table_relation;
! 	HeapScanDesc	scanDesc;
! 	HeapTuple		tuple;
! 	HeapTuple		newTuple;
! 	int				nAttr;
! 	Datum			*values;
! 	char			*nulls;
! 	bool			*bNulls;
! 	int 			i;
! 
!     snap = GetActiveSnapshot();
!     tmpRel  = heap_open(relId, RowExclusiveLock);
!     scanDesc = heap_beginscan(tmpRel, snap, 0, NULL);
! 
!     while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, ForwardScanDirection)))
!     {
!         Oid relationOid = get_relevant_hash_partition(tuple, rel);
! 
!         if(relationOid == InvalidOid)
!             elog(ERROR, "Could not find valid partition.");
! 
!         nAttr = HeapTupleHeaderGetNatts(tuple->t_data);
! 
!         values = palloc(sizeof(Datum) * nAttr);
!         nulls  = palloc(sizeof(char) * nAttr);
!         bNulls = palloc(sizeof(bool) * nAttr);
! 
!         heap_deformtuple(tuple, rel->rd_att, values, nulls);
! 
!         for(i=0; i<nAttr; i++)
!         {
!             if(nulls[i] == 'n')
!                 bNulls[i] = true;
!             else
!                 bNulls[i] = false;
!         }
! 
!         child_table_relation = heap_open(relationOid, RowExclusiveLock);
!         newTuple = heap_form_tuple(child_table_relation->rd_att, values, bNulls);
!         simple_heap_insert(child_table_relation, newTuple);
!         CatalogUpdateIndexes(child_table_relation, newTuple);
!         heap_close(child_table_relation, RowExclusiveLock);
! 
!         simple_heap_delete(tmpRel, &tuple->t_self);
!         CommandCounterIncrement();
! 
!         pfree(values);
!         pfree(nulls);
!         pfree(bNulls);
! 
!     }
! 
!     heap_endscan(scanDesc);
!     heap_close(tmpRel, RowExclusiveLock);
! }
! 
! static void
! DropPartition(Oid relId)
! {
! 	Relation 		tmpRel;
! 	StringInfo		query = makeStringInfo();
! 	List			*queryList;
! 	Node			*parseTree;
! 
! 	tmpRel = RelationIdGetRelation(relId);
! 	appendStringInfo(query, "DROP TABLE %s CASCADE;", RelationGetRelationName(tmpRel));
! 	relation_close(tmpRel, 0);
! 
! 	queryList = pg_parse_query(query->data);
! 	parseTree = (Node *)lfirst(list_head(queryList));
! 	RemoveRelations((DropStmt *)parseTree);
! }
! 
! static void 
! RemovePartitionMetadata(Relation rel, List *rows_to_be_deleted_list)
! {
! 	ListCell	*row_to_be_deleted;
! 
! 	foreach(row_to_be_deleted, rows_to_be_deleted_list)
! 	{
! 		PartitionRowInfo *tmp = (PartitionRowInfo *)lfirst(row_to_be_deleted);
! 		simple_heap_delete(rel, &tmp->tid);
! 		CommandCounterIncrement();
! 	}
! 
! 	list_free(rows_to_be_deleted_list);
! 	rows_to_be_deleted_list = NULL;
! }
! 
! static Oid 
! CreateInheritedTable(Oid relId, char *name, char *tablespace)
! {
! 	Oid			child;
! 	int 		j;
! 	List 		*queryList = NULL;
! 	Node		*parseTree;
! 	StringInfo	tableName = makeStringInfo();
! 	StringInfo	query = makeStringInfo();
! 	Relation	rel;
! 
! 	/* Get relation for given ID. */
! 	rel = RelationIdGetRelation(relId);
! 
! 	if(name)
! 	{
! 		appendStringInfo(tableName, "%s", name);
! 	}
! 	else
! 	{
! 		j = GetPartitionsCount(RelationGetRelid(rel));
! 		do
! 		{
! 			resetStringInfo(tableName);
! 			appendStringInfo(tableName, "%s_%d", RelationGetRelationName(rel), j++);	
! 			child = RelnameGetRelid(tableName->data);	
! 		}while(child != InvalidOid);
! 	}
! 
! 	if(tablespace)
! 	{
! 		appendStringInfo(query, "CREATE TABLE %s () INHERITS (%s) TABLESPACE %s;", tableName->data, 
! 			RelationGetRelationName(rel), tablespace);
! 	}
! 	else
! 	{	
! 		appendStringInfo(query, "CREATE TABLE %s () INHERITS (%s) ;", tableName->data, RelationGetRelationName(rel));
! 	}
! 
! 	/* Close the relation. */
! 	relation_close(rel, 0);
! 
! 	queryList = pg_parse_query(query->data);
! 	parseTree = (Node *)lfirst(list_head(queryList));
! 	child = DefineRelation((CreateStmt *)parseTree, RELKIND_RELATION);
! 		
! 	/* To avoid tuple being updated by the current transaction, after the current scan started */
! 	CommandCounterIncrement();
! 	
! 	return child;
! }
! 
! static void 
! ATExecUpdateHashPartition(AlteredTableInfo *tab, Relation rel,
! 	A_Const *part)
! {
! 	int				totalPartitions;
! 	int				resultantPartitions;
! 	int				count = 0;
! 	bool			flag = false;
! 	List			*relIdsToBeDropped = NULL;
! 	ListCell		*relIdToBeDropped;
! 	List			*relIdsNotToBeDropped = NULL;
! 	ListCell		*relIdNotToBeDropped;
! 	List			*relIdsToBeAdded = NULL;
! 	ListCell		*relIdToBeAdded;
! 	Oid				relId;
! 	ScanKeyData 	skey;
! 	Relation		pg_partrel;
! 	SysScanDesc		pg_partscan;
! 	HeapTuple		pg_parttup;
! 	Oid				childId;
! 
! 	totalPartitions 	= GetPartitionsCount(RelationGetRelid(rel));
! 	resultantPartitions = part->val.val.ival;
! 	
! 	/* If the last partition is being asked to be dropped then throw the msg. */
! 	if(part->val.val.ival < 1)
! 		elog(ERROR, "Can not drop the last partition. Drop the partitioned-table instead.");
! 
! 	/* If no. of partitions is same then do nothing.*/
! 	if(totalPartitions == resultantPartitions)
! 		return;
! 
!    	ScanKeyInit(&skey,
! 		Anum_pg_partition_parentrelid,
! 		BTEqualStrategyNumber, F_OIDEQ,
! 		ObjectIdGetDatum(RelationGetRelid(rel)));
! 
! 	pg_partrel = heap_open(PartitionRelationId, RowExclusiveLock);
! 	pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
! 					SnapshotNow, 1, &skey);
! 
!    	while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
!    	    /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!        	Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
!         if(pg_part->keyorder == 1)
! 		{
! 			if(totalPartitions > resultantPartitions)
! 			{	
! 				if(++count > resultantPartitions) 
! 				{
! 					flag = true;
! 					/* Store the Relids of partitions to be dropped after row-migrations. */
! 					if(!list_member_oid(relIdsToBeDropped, pg_part->partrelid))
! 						relIdsToBeDropped = lappend_oid(relIdsToBeDropped, pg_part->partrelid);
! 				}
! 				else
! 				{
! 					/* Store the Relids of partitions not to be dropped after row-migrations. */
! 					if(!list_member_oid(relIdsNotToBeDropped, pg_part->partrelid))
! 						relIdsNotToBeDropped = lappend_oid(relIdsNotToBeDropped, pg_part->partrelid);
! 				}	
! 			}
! 			else
! 			{
! 				count++;
! 
! 				if(count == 1)
! 				{
! 					int index = 0;
! 					while(++index <= (resultantPartitions - totalPartitions))
! 					{
! 						/* Create hash partitions and add apply triggers. */
! 						childId = CreateInheritedTable(RelationGetRelid(rel), NULL, NULL);
! 						ApplyHashPartitionTriggers(childId);
! 
! 						relIdsToBeAdded = lappend_int(relIdsToBeAdded, childId);
! 					}
! 				}
! 
! 				/* Store the Relids of partitions to be dropped after row-migrations. */
! 				if(!list_member_oid(relIdsNotToBeDropped, pg_part->partrelid))
! 					relIdsNotToBeDropped = lappend_oid(relIdsNotToBeDropped, pg_part->partrelid);
! 			}
! 		}
! 
! 		if(totalPartitions < resultantPartitions)
! 		{
! 			if(count == 1)
! 			{
! 				int index = 0;
! 				relIdToBeAdded = list_head(relIdsToBeAdded);
! 				while(++index <= (resultantPartitions - totalPartitions))
! 				{
! 					if(index != 1)
! 					{
! 						relIdToBeAdded = lnext(relIdToBeAdded);
! 					}
! 					WriteHashPartitionToCatalog(lfirst_int(relIdToBeAdded),
! 						pg_part->parentrelid,
! 						pg_part->partkey,
! 						pg_part->keytype,
! 						pg_part->keyorder,
! 						totalPartitions + index - 1);
! 				}
! 			}
! 		}
! 		
! 		if(flag == true)
! 		{
! 			/* Delete the metadata from system catalog for partitions. (pg_partition)*/
! 			simple_heap_delete(pg_partrel, &pg_parttup->t_self);
! 			CommandCounterIncrement();
! 		}
! 	}
! 		
! 	systable_endscan(pg_partscan);
! 	heap_close(pg_partrel, RowExclusiveLock);
! 
! 	foreach(relIdToBeDropped, relIdsToBeDropped)
! 	{
! 		relId = (Oid)lfirst_oid(relIdToBeDropped);
! 		MigrateTuplesHash(relId, rel);
! 		DropPartition(relId);
! 	}
! 
! 	foreach(relIdNotToBeDropped, relIdsNotToBeDropped)
! 	{
! 		relId = (Oid)lfirst_oid(relIdNotToBeDropped);
! 		MigrateTuplesHash(relId, rel);
! 	}
! }
! 
! static void CopyTable(Oid from, Oid to)
! {
! 	Relation 		tmpRel;
! 	HeapScanDesc	scanDesc;
! 	HeapTuple		tuple;
! 	Snapshot		snap;
! 	Datum 			*values;
! 	char			*nulls;
! 	bool			*bNulls;
! 	int				nAttr;
! 	int				i;
! 	Relation		child_table_relation;
! 	HeapTuple		newTuple; 
! 
! 	/* If source and target tables are same then do nothing*/
! 	if(from == to)
! 		return;
! 
! 	snap = GetActiveSnapshot();
! 	tmpRel 	= heap_open(from, RowExclusiveLock);
! 	scanDesc = heap_beginscan(tmpRel, snap, 0, NULL);		
! 
!    	while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, ForwardScanDirection)))
! 	{
! 		nAttr = HeapTupleHeaderGetNatts(tuple->t_data);
! 				
! 		values = palloc(sizeof(Datum) * nAttr);
! 		nulls  = palloc(sizeof(char) * nAttr);
! 		bNulls = palloc(sizeof(bool) * nAttr);			
! 
! 		heap_deformtuple(tuple, tmpRel->rd_att, values, nulls);
! 
! 		for(i=0; i<nAttr; i++)
! 		{
! 			if(nulls[i] == 'n')
! 				bNulls[i] = true;
! 			else
! 				bNulls[i] = false;
! 		}
! 
! 		child_table_relation = heap_open(to, RowExclusiveLock);	
! 		newTuple = heap_form_tuple(child_table_relation->rd_att, values, bNulls);
! 		simple_heap_insert(child_table_relation, newTuple);
! 		CatalogUpdateIndexes(child_table_relation, newTuple);
! 		heap_close(child_table_relation, RowExclusiveLock);		
! 
! 		pfree(values);
! 		pfree(nulls);
! 		pfree(bNulls);
! 	}
! 
! 	heap_endscan(scanDesc);
! 	heap_close(tmpRel, RowExclusiveLock);
! }
! 
! void
! InsertTuple(HeapTuple newtuple, Oid targetId)
! {
! 	Relation 		targetRel;
!     ResultRelInfo 	*resultRelInfo;
!     TupleTableSlot 	*slot;
! 	EState 			*estate;
! 
! 	targetRel = RelationIdGetRelation(targetId);
! 	estate = CreateExecutorState();
! 
! 	resultRelInfo = makeNode(ResultRelInfo);
! 	resultRelInfo->ri_RangeTableIndex = 1;
! 	resultRelInfo->ri_RelationDesc = targetRel;
! 
! 	estate->es_result_relations = resultRelInfo;
! 	estate->es_num_result_relations = 1;
! 	estate->es_result_relation_info = resultRelInfo;
! 
! 	/* Set up a tuple slot too */
! 	slot = MakeSingleTupleTableSlot(targetRel->rd_att);
! 	ExecStoreTuple(newtuple, slot, InvalidBuffer, false);
! 
! 	/* If there are any constraints then execute. */
! 	if(resultRelInfo->ri_RelationDesc->rd_att->constr != NULL)
! 		ExecConstraints(resultRelInfo, slot, estate);
! 
! 	simple_heap_insert(targetRel, newtuple);
! 	CatalogUpdateIndexes(targetRel, newtuple);
! 	RelationClose(targetRel);
! 	ExecDropSingleTupleTableSlot(slot);
! 	FreeExecutorState (estate);
! }
! 
! Oid 
! GetOverflowPartition(Relation rel)
! {
! 	StringInfo 	tableName = makeStringInfo();
! 
! 	/* Get overflow partition. */
! 	appendStringInfo(tableName, "of_%s_%u", RelationGetRelationName(rel), RelationGetRelid(rel));
! 	return (RelnameGetRelid(tableName->data));
! }
! 
! /* Check indexes on overflow tables and return overflow-index id. 
! when a partition is modified then overflow table would be checked 
! for any rows corresponding to modified partition and with index 
! on overflow table, we can scan the table faster to find mapping rows. */
! 
! Oid
! GetOverflowIndexId(Oid relId)
! {
! 	List		*indexes = NULL;
! 	ListCell	*index;
! 	Relation 	rel;
! 
! 	rel = RelationIdGetRelation(relId);
! 	indexes = RelationGetIndexList(rel);
! 	RelationClose(rel);
! 
! 	foreach(index, indexes)
! 	{
! 		rel = index_open(lfirst_oid(index), AccessShareLock);
! 
! 		/* overflow indices are named as 'of_index_OVERFLOWTABLEID'*/		
! 		if(strncmp(RelationGetRelationName(rel), "of_index_", strlen("of_index_")) == 0)
! 		{
! 			Oid	oid = 0;
! 			sscanf(RelationGetRelationName(rel)+strlen("of_index_"), "%u", &oid);
! 
! 			if(oid == relId)
! 			{
! 				index_close(rel, NoLock);
! 				return lfirst_oid(index);
! 			}
! 		}
! 		index_close(rel, NoLock);
! 	}
! 	return 0;
! }
! 
! void GetPartitionValues(Oid partOid, List **minValues, List **maxValues, List **attrs, int *nKeys)
! {
! 	ScanKeyData skey;
! 	Relation    pg_partrel;
! 	SysScanDesc pg_partscan;
! 	HeapTuple   pg_parttup;
! 	Datum 		values[Natts_pg_partition];
! 	char  		nulls [Natts_pg_partition];	
! 
! 	*nKeys = 0;
! 	
!     /*Scan key to scan pg_partition table on parentrelid*/
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_partrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(partOid));
! 
!     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
! 		int16	len;
! 		bool	typbyval;
! 
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
! 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
! 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);		
! 
! 		*attrs = lappend(*attrs, (void *)pg_part->partkey);
! 
! 		/* Get the attribute length*/
! 		get_typlenbyval(pg_part->keytype, &len, &typbyval);
! 
!         if(pg_part->parttype == PART_RANGE)
!         {
! 			if(nulls[Anum_pg_partition_minval-1] == 'n')
! 			{
! 				Node *tmpNode = makeColumnRef("minvalue", NULL, -1);
! 				*minValues = lappend(*minValues, tmpNode);
! 			}
! 			else
! 			{
! 				Const *tmpConst = makeConst(pg_part->keytype,
! 					-1,
! 					len,
! 					GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval),
! 					false,
! 					typbyval				
! 				);
! 				*minValues = lappend(*minValues, tmpConst);
! 				*nKeys = *nKeys + 1;
! 			}
! 			
! 			if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 			{
! 				Node *tmpNode = makeColumnRef("maxvalue", NULL, -1);
! 				*maxValues = lappend(*maxValues, tmpNode);
! 			}
! 			else
! 			{
! 				Const *tmpConst = makeConst(pg_part->keytype,
! 					-1,
! 					len,
! 					GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval),
! 					false,
! 					typbyval
! 				);
! 				*maxValues = lappend(*maxValues, tmpConst);
! 				*nKeys = *nKeys + 1;
! 			}
! 		}
! 	}
! 
! 	systable_endscan(pg_partscan);
! 	heap_close(pg_partrel, AccessShareLock);	
! }
! 
! Oid
! GetProcId(Oid operOid)
! {
!     Relation    		relation;
!     HeapTuple   		tup;
! 	Form_pg_operator	pg_op;
! 	Oid					procId;
! 
!     relation = heap_open(OperatorRelationId, AccessShareLock);
! 
!     tup = SearchSysCache(OPEROID,
!                          ObjectIdGetDatum(operOid),
!                          0, 0, 0);
!     if (!HeapTupleIsValid(tup)) /* should not happen */
!         elog(ERROR, "cache lookup failed for operator %u", operOid);
! 
! 	pg_op  = (Form_pg_operator) GETSTRUCT(tup);
! 	procId = pg_op->oprcode;
! 
!     ReleaseSysCache(tup);
! 
!     heap_close(relation, AccessShareLock);
! 	
! 	return procId;			
! 
! }
! void 
! MoveValidRowsFromOverflow(Oid relId, Oid partId)
! {
! 	char			*parent = NULL;
! 	Oid				parentId;
! 	Relation		rel, tmpRel;
! 	Relation		child_table_relation;
! 	Datum			*values;
! 	char			*nulls;
! 	bool			*bNulls;
! 	int				nAttr; 
! 	int				i;
! 	ScanKeyData 	*skeys;
! 	SysScanDesc		scanDesc;
! 	HeapTuple		tuple;
! 	HeapTuple 		newTuple;
! 	List			*minValues = NULL;
! 	List			*maxValues = NULL;
! 	List			*attrs = NULL;
! 	ListCell		*attr;
! 	ListCell		*maxValue;
! 	ListCell		*minValue;
! 	Oid				indexId;
! 	int				nKeys;
! 	
! 	parent 		= GetPartitionedTableFromOverflow(relId);
! 	parentId	= RelnameGetRelid(parent);
! 	rel = RelationIdGetRelation(parentId);
! 
! 	indexId = GetOverflowIndexId(relId);
! 	GetPartitionValues(partId, &minValues, &maxValues, &attrs, &nKeys);
! 
! 	skeys = palloc(nKeys * sizeof(ScanKeyData));
! 
! 	/* Initialize scankey with min and max values for partition attributes. */
! 	minValue = list_head(minValues);
! 	maxValue = list_head(maxValues);
! 	i = 0;
! 
! 	foreach(attr, attrs)
! 	{
! 		bool	isDef;
! 		Oid		type; 
! 		Oid		operator; 
! 		Oid		func;
! 		
! 		type = get_atttype(partId, lfirst_int(attr));
! 
! 		if(IsA(lfirst(minValue), Const))
! 		{
! 			operator = OperatorGet(">=", PG_CATALOG_NAMESPACE , type, type, &isDef);
! 			func = GetProcId(operator); 
! 
! 			ScanKeyInit(&skeys[i++],
! 				lfirst_int(attr),
! 				BTGreaterEqualStrategyNumber,
! 				func,
! 				((Const *)lfirst(minValue))->constvalue	
! 			);
! 		}
! 
! 		if(IsA(lfirst(maxValue), Const))
! 		{
! 			operator = OperatorGet("<", PG_CATALOG_NAMESPACE , type, type, &isDef);
! 			func = GetProcId(operator); 
! 	
! 			ScanKeyInit(&skeys[i++],
! 				lfirst_int(attr),
! 				BTLessStrategyNumber,
! 				func,
! 				((Const *)lfirst(maxValue))->constvalue
! 			);
! 		}
! 
! 		minValue = lnext(minValue);
! 		maxValue = lnext(maxValue);
! 	}
! 
! 	list_free(attrs);
! 	list_free(minValues);
! 	list_free(maxValues);
! 	
! 	if(parentId != InvalidOid)
! 	{
! 		tmpRel 	 = heap_open(relId, RowExclusiveLock);
! 		scanDesc = systable_beginscan(tmpRel, indexId, true, SnapshotNow, nKeys, skeys);
! 
! 		while (HeapTupleIsValid(tuple = systable_getnext(scanDesc)))
! 		{
! 			nAttr = HeapTupleHeaderGetNatts(tuple->t_data);
! 			/* Allocate space */
! 			values = palloc(sizeof(Datum) * nAttr);
! 			nulls  = palloc(sizeof(char) * nAttr);
! 			bNulls = palloc(sizeof(bool) * nAttr);
! 			
! 			heap_deformtuple(tuple, rel->rd_att, values, nulls);
! 
! 			for(i=0; i<nAttr; i++)
! 			{
! 				if(nulls[i] == 'n')
! 					bNulls[i] = true;
! 				else
! 					bNulls[i] = false;
! 			}
! 
! 			child_table_relation = heap_open(partId, RowExclusiveLock);	
! 			newTuple = heap_form_tuple(child_table_relation->rd_att, values, bNulls);
! 			simple_heap_insert(child_table_relation, newTuple);
! 			CatalogUpdateIndexes(child_table_relation, newTuple);
! 			heap_close(child_table_relation, RowExclusiveLock);
! 
! 			simple_heap_delete(tmpRel, &tuple->t_self);
! 			CommandCounterIncrement();
! 
! 			pfree(values);
! 			pfree(nulls);
! 			pfree(bNulls);
! 		}
! 	    
! 		systable_endscan(scanDesc);
!     	heap_close(tmpRel, RowExclusiveLock);
! 	}
! 	RelationClose(rel);
! }
! 
! static void 
! ATExecMergePartition(AlteredTableInfo *tab, Relation rel,
! 	MergePartitionStmt *part)
! {
! 	Oid				merge1;
! 	Oid				merge2;
!     ScanKeyData 	skey;
!     SysScanDesc 	pg_partscan;
!     HeapTuple   	pg_parttup;
!     Relation    	pg_partrel;
! 	Partition		*newPart;
! 	List			*datum1Min = NULL, *datum1Max = NULL;
! 	Datum			datum2Min, datum2Max;
! 	bool 			isDef;
! 	Oid 			opLt;
! 	Oid				opLtProc;
! 	bool			ltMax;
! 	int16			len;
! 	bool			typbyval;
! 	ListCell		*minIndex;
! 	ListCell		*maxIndex;
! 	PartitionAttrs	*partition_attr;
! 	Oid				*childOids;
! 	List			*distinct_part_rel_oid_list = NULL;
! 	int				j = 0;
! 	Partition		*tmp;
! 	Alias 			*colName;
! 	Oid				child;
! 	ListCell		*partColumn;
! 	char			*partitionColumn;
! 	StringInfo		createTrigger = makeStringInfo();
! 	List			*query_list;
! 	Node			*parsetree;
! 	bool			isExistingTable;	
! 	Datum 			values[Natts_pg_partition];
! 	char  			nulls [Natts_pg_partition];	
! 	Node			*nodeMin, *nodeMax;
! 
!     /* Get the relId from the tablename. */
!     if(list_head(part->partNames))
!     {
!         merge1  = RelnameGetRelid(((RangeVar *)linitial(part->partNames))->relname);
!         if (merge1 == InvalidOid)
!             elog(ERROR, "'%s' is not a valid partition.", ((RangeVar *)linitial(part->partNames))->relname);		
!     }
!     else
!     {
!         elog(ERROR, "Please specify valid 1st partition to be merged.");
!     }	
! 
!     /* Get the relId from the tablename. */
!     if(lnext(list_head(part->partNames)))
!     {
!         merge2  = RelnameGetRelid(((RangeVar *)lsecond(part->partNames))->relname);
!         if (merge1 == InvalidOid)
!             elog(ERROR, "'%s' is not a valid partition.", ((RangeVar *)linitial(part->partNames))->relname);
! 		if(merge1 == merge2)
! 			elog(ERROR, "Can not merge same partitions.");
!     }
!     else
!     {
!         elog(ERROR, "Please specify valid 2nd partition to be merged.");
!     }
! 
! 	/* Check whether resultant partition already exists.*/
!     if(lnext(lnext(list_head(part->partNames))))
!     {
!         child  = RelnameGetRelid(((RangeVar *)lthird(part->partNames))->relname);
! 		if(child == InvalidOid)
! 		{
! 			isExistingTable = false;
! 		}
! 		else
! 		{
! 			if((child == merge1) || (child == merge2))
! 			{
! 				isExistingTable = true;
! 			}
! 			else
! 			{
! 				elog(ERROR, "Resultant partition can be either any one of the partitions to be merged or a new partition.");
! 			}			
! 		}
! 	}
! 	
! 
! 	/* Create partition attribute node. */
! 	partition_attr = makeNode(PartitionAttrs);
! 
! 	/* Create a new partition*/
! 	newPart = makeNode(Partition);
! 	newPart->partName 		= makeNode(RangeVar);
! 	newPart->partitionCheck	= makeNode(Constraint);
! 	newPart->partName->relname = ((RangeVar *)lthird(part->partNames))->relname; 
! 
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_partrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(merge1));
! 
!     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
!         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
! 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
! 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
! 
!         if(pg_part->parttype == PART_RANGE)
!         {
! 			if(nulls[Anum_pg_partition_minval-1] == 'n')
! 			{				
! 				Node 	*tmpNode = makeColumnRef("minvalue", NULL, -1);
! 				datum1Min = lappend(datum1Min, tmpNode);
! 			}			
! 			else
! 			{
! 				Datum datum = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval);
! 
! 				Const *tmpConst = makeConst(pg_part->keytype,	/* Const type */
! 										-1,
! 										len,
! 										datum,
! 										false,
! 										typbyval);
! 				
! 				datum1Min = lappend(datum1Min, tmpConst);	
! 			}
! 
! 			if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 			{				
! 				Node 	*tmpNode = makeColumnRef("maxvalue", NULL, -1);
! 				datum1Max = lappend(datum1Max, tmpNode);
! 			}			
! 			else
! 			{
! 				Datum datum = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval);
! 
! 				Const *tmpConst = makeConst(pg_part->keytype,	/* Const type */
! 										-1,
! 										len,
! 										datum,
! 										false,
! 										typbyval);
! 				
! 				datum1Max = lappend(datum1Max, tmpConst);	
! 			}
! 
! 			/* Add the partition key columns. */
! 			colName = makeAlias(get_attname (rel->rd_id, pg_part->partkey), NULL);
! 			partition_attr->colName = lappend(partition_attr->colName, colName);			
! 		}
! 	}
! 
!     systable_endscan(pg_partscan);
!     heap_close(pg_partrel, AccessShareLock);	
! 
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_partrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(merge2));
! 
!     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
! 	minIndex = list_head(datum1Min);
! 	maxIndex = list_head(datum1Max);
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
!         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
! 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
! 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
! 
!         if(pg_part->parttype == PART_RANGE)
!         {
! 	        /* Get len and typbyval from pg_type */
!    	        get_typlenbyval(pg_part->keytype, &len, &typbyval);
! 
! 			if(nulls[Anum_pg_partition_minval-1] == 'n')
! 			{				
! 				nodeMin = makeColumnRef("minvalue", NULL, -1);
! 				ltMax = false;
! 			}
! 			else
! 			{
! 				datum2Min = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval);
! 
! 				nodeMin = (Node *)makeConst(pg_part->keytype,	/* Const type */
! 										-1,
! 										len,
! 										datum2Min,
! 										false,
! 										typbyval);
! 			}
! 
! 			if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 			{				
! 				nodeMax = makeColumnRef("maxvalue", NULL, -1);
! 				ltMax = true;
! 			}
! 			else
! 			{
! 				datum2Max = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval);
! 
! 				nodeMax = (Node *)makeConst(pg_part->keytype,	/* Const type */
! 										-1,
! 										len,
! 										datum2Max,
! 										false,
! 										typbyval);
! 			}
! 
! 			if(IsA((Node *)lfirst(minIndex), Const) && IsA(nodeMin, Const) && IsA(nodeMax, Const))
! 			{
! 				Datum datum1, datum2;
! 			
! 				datum1 = ((Const *)lfirst(minIndex))->constvalue;
! 				datum2 = ((Const *)nodeMin)->constvalue;
! 
! 				opLt = OperatorGet("<", PG_CATALOG_NAMESPACE, pg_part->keytype, pg_part->keytype, &isDef);
! 			
! 				if(isDef == FALSE)
! 					elog(ERROR, "'<' operator is not defined for this type.");
! 
! 				opLtProc = get_opcode(opLt);
! 				ltMax = DatumGetBool(OidFunctionCall2(opLtProc, datum1, datum2));
! 			}
! 
! 			if(ltMax)
! 			{
! 				/* Add min and max. value to newly created partition. */
! 				newPart->partitionCheck->min_value = lappend(newPart->partitionCheck->min_value, lfirst(minIndex));
! 				newPart->partitionCheck->max_value = lappend(newPart->partitionCheck->max_value, nodeMax);
! 			}
! 			else
! 			{
! 				/* Add min and max. value to newly created partition. */
! 				newPart->partitionCheck->min_value = lappend(newPart->partitionCheck->min_value, nodeMin);
! 				newPart->partitionCheck->max_value = lappend(newPart->partitionCheck->max_value, lfirst(maxIndex));					
! 			}
! 		
!            	minIndex = minIndex->next;
!             maxIndex = maxIndex->next;
! 
! 		}
! 	}
! 
!     systable_endscan(pg_partscan);
!     heap_close(pg_partrel, AccessShareLock);
! 
! 	/* To store the partition relids*/
! 	childOids = malloc(GetPartitionsCount(RelationGetRelid(rel)));
! 
!     /*Scan key to scan pg_partition table on parentrelid*/
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_parentrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(RelationGetRelid(rel)));
! 
!     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
! 		Node	*node;
! 		Relation tmp_rel;
! 
!         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
!         /* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
!         heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
! 
!         if(pg_part->parttype == PART_RANGE)
!         {
! 			if(pg_part->partrelid != merge1 && pg_part->partrelid != merge2)
! 			{
! 				if (!list_member_oid(distinct_part_rel_oid_list, pg_part->partrelid))
! 				{
! 					distinct_part_rel_oid_list = lappend_oid(distinct_part_rel_oid_list, pg_part->partrelid);
! 					childOids[j++] = pg_part->partrelid;
! 				
! 					tmp = makeNode(Partition);
! 					tmp->partName 		= makeNode(RangeVar);
! 					tmp->partitionCheck	= makeNode(Constraint);
! 
! 					/* Add this partition to partition attributes. */
! 					partition_attr->partitions = lappend(partition_attr->partitions, tmp);
! 				}
! 
! 				tmp_rel = RelationIdGetRelation(pg_part->partrelid);
! 				tmp->partName->relname = RelationGetRelationName(tmp_rel);
! 				relation_close(tmp_rel, 0);
! 
! 				if(nulls[Anum_pg_partition_minval-1] == 'n')
! 				{
! 					node = makeColumnRef("minvalue", NULL, -1);
! 				}
! 				else
! 				{
! 	                node = (Node *)makeConst(pg_part->keytype,
!                                 -1,
!                                 len,
!                                 GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval),
!                                 false,
!                                 typbyval);
! 					
! 				}
! 
! 				/* Add this to new partition. */
! 				tmp->partitionCheck->min_value = lappend(tmp->partitionCheck->min_value, node);
! 
!                 if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 				{
! 					node = makeColumnRef("maxvalue", NULL, -1);
! 				}
! 				else
! 				{
! 					node = (Node *)makeConst(pg_part->keytype,
!     	                            -1,
!         	                        len,
! 									GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval),
!                         	        false,
!                             	    typbyval);
! 				}
! 
! 				/* Add this to new partition. */
! 				tmp->partitionCheck->max_value = lappend(tmp->partitionCheck->max_value, node);
! 			}
! 		}		
! 	}	
! 
! 	partition_attr->partitions = lappend(partition_attr->partitions, newPart);
! 
! 	ValidateRanges(partition_attr, RelationGetRelid(rel), childOids);
! 
! 	DeletePartitionEntry(merge1);
! 	DeletePartitionEntry(merge2);
! 
! 	/* Create a new table. */
! 	if(isExistingTable == false)
! 		child = CreateInheritedTable(RelationGetRelid(rel), ((RangeVar *)lthird(part->partNames))->relname, NULL);
! 
! 	minIndex = newPart->partitionCheck->min_value->head;
! 	maxIndex = newPart->partitionCheck->max_value->head;
! 
! 	j = 0;
! 
! 	foreach(partColumn, partition_attr->colName)
! 	{
! 		Oid		typ_oid;
! 		int		rangeVal;
! 
! 		/* Get the name of partition key column. */
! 		partitionColumn = ((Alias *)lfirst(partColumn))->aliasname;
! 
!         /* If an existing table, drop earlier contraints. */
!         if(isExistingTable == true)
!         {
!             DropCheckConstraint(((RangeVar *)lthird(part->partNames))->relname, partitionColumn);
!         }
! 
!         /* Get the attribute type. */
!         typ_oid = get_atttype(RelationGetRelid(rel), get_attnum(RelationGetRelid(rel), partitionColumn) );
! 
!         /* Get the attribute length*/
!         get_typlenbyval(typ_oid, &len, &typbyval);
! 
! 		if(IsA(lfirst(minIndex), ColumnRef))
! 		{
! 			ColumnRef	*colRef = lfirst(minIndex);		
! 
! 			if(list_length(colRef->fields) == 1)
! 			{
! 				if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "minvalue") == 0)
! 				{
! 					rangeVal = MINVALRANGE;
! 					AddLessThanCheckConstraint(typ_oid, 
! 						((Const *)lfirst(maxIndex))->constvalue, 
! 						 ((RangeVar *)lthird(part->partNames))->relname, 
! 						partitionColumn);	
! 				}
! 				else
! 				{
! 					elog(ERROR, "Not a valid value.");
! 				}
! 			}
! 		} 
! 		else if(IsA(lfirst(maxIndex), ColumnRef))
! 		{
! 			ColumnRef	*colRef = lfirst(maxIndex);		
! 
! 			if(list_length(colRef->fields) == 1)
! 			{
! 				if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "maxvalue") == 0)
! 				{
! 					rangeVal = MAXVALRANGE;
! 					AddGreaterThanCheckConstraint(typ_oid, 
! 						((Const *)lfirst(minIndex))->constvalue, 
! 						 ((RangeVar *)lthird(part->partNames))->relname, 
! 						partitionColumn);	
! 				}
! 				else
! 				{
! 					elog(ERROR, "Not a valid value.");
! 				}
! 			}
! 		}
! 		else
! 		{
! 			rangeVal = OTHER;
! 			AddCheckConstraint(typ_oid, 
! 				((Const *)lfirst(minIndex))->constvalue, 
! 				((Const *)lfirst(maxIndex))->constvalue, 
! 				 ((RangeVar *)lthird(part->partNames))->relname, 
! 				partitionColumn);	
! 		}
! 
! 		WriteRangePartitionToCatalog(((Const *)lfirst(minIndex))->constvalue, 
! 										((Const *)lfirst(maxIndex))->constvalue,
! 										len,
! 										typbyval,
! 										RelationGetRelid(rel),
! 										child,
! 										get_attnum(RelationGetRelid(rel), partitionColumn),
! 										typ_oid,
! 										++j,
! 										rangeVal);
! 
!        	minIndex = minIndex->next;
!         maxIndex = maxIndex->next;
! 	}
! 
! 	if(isExistingTable == false)
! 	{
! 	    resetStringInfo(createTrigger);
!    		appendStringInfo(createTrigger, "CREATE TRIGGER partition_update_%u BEFORE UPDATE ON %s ", child,  newPart->partName->relname);
! 	    appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_update_trigger ();");
! 
!    		/* Parse the above SQL string and use this parsetree to create trigger on parent table. */
! 	    query_list  = pg_parse_query(createTrigger->data);
!    		parsetree = (Node *)lfirst(list_head(query_list));
! 	    CreateTrigger((CreateTrigStmt * )parsetree, 0, false);
! 
! 		/* To avoid tuple being updated by the current transaction, after the current scan started */
! 		CommandCounterIncrement();
! 	}
! 
! 	/* Copy rows from partitions to be merged. */
! 	CopyTable(merge1, child);
! 	CopyTable(merge2, child);
! 
! 	/* Drop the merged partitions. */
! 	if(child != merge1)
! 		DropPartition(merge1);
! 	if(child != merge2)
! 		DropPartition(merge2);
! 
!     systable_endscan(pg_partscan);
!     heap_close(pg_partrel, AccessShareLock);
! 
! 	/* If there are any rows in overflow partition which can satisfy partition constraints 
! 	of latest partition, then move them out of overflow.*/
! 	MoveValidRowsFromOverflow(GetOverflowPartition(rel), child);
! }
! 
! bool GotConstraints(Oid relId)
! {
!     SysScanDesc conscan;
!     ScanKeyData skey;
!     HeapTuple   htup;	
! 	Relation	conrel;
! 	int			count = 0;
! 
!     ScanKeyInit(&skey,
!                 Anum_pg_constraint_conrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(relId));
! 
!     conrel = heap_open(ConstraintRelationId, AccessShareLock);
!     conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
!                                  SnapshotNow, 1, &skey);
! 
!     while (HeapTupleIsValid(htup = systable_getnext(conscan)))
!     {
! 		count++;
! 	}
! 
!     systable_endscan(conscan);
!     heap_close(conrel, AccessShareLock);
! 
! 	if(count)
! 		return true;
! 	else
! 		return false;
! }
! 
! bool GotTriggers(Oid relId)
! {
! 	Relation rel = RelationIdGetRelation(relId);
! 	
! 	if(rel->trigdesc)
! 	{
! 		relation_close(rel, 0);
! 		return true;
! 	}
! 	else
! 	{
! 		relation_close(rel, 0);
! 		return false;
! 	}
! }
! 	
! /*
!  */
! static void 
! ATExecRenamePartition(AlteredTableInfo *tab, Relation rel,
! 	RenamePartitionStmt *part)
! {
!     StringInfo  query = makeStringInfo();
!     List        *queryList;
!     Node        *parseTree;
! 
! 	appendStringInfo(query, "ALTER TABLE %s RENAME TO %s;", 
! 		((RangeVar *)linitial(part->partNames))->relname,
! 		((RangeVar *)lsecond(part->partNames))->relname);
! 
! 	queryList = pg_parse_query(query->data);
! 	parseTree = (Node *)lfirst(list_head(queryList));
! 	ExecRenameStmt((RenameStmt *)parseTree);
! }	
! 
! static void 
! RemovePartitionTrigger(Oid oid)
! {
!     Relation    rel;
! 	List		*queryList;
! 	Node		*parseTree;
! 	StringInfo	trigger = makeStringInfo();
! 	DropPropertyStmt *stmt;
! 
! 	
! 	rel = RelationIdGetRelation(oid);
! 	appendStringInfo(trigger, "DROP TRIGGER partition_update_%u on %s",
! 		oid,
! 		RelationGetRelationName(rel)
! 	);
! 	RelationClose(rel);
! 		
! 	queryList  = pg_parse_query(trigger->data);
! 	parseTree  = (Node *)lfirst(list_head(queryList));
! 	stmt = (DropPropertyStmt *)parseTree;
! 
! 	DropTrigger(oid, stmt->property, stmt->behavior, stmt->missing_ok);	
! }
! 
! void 
! RemoveConstraintsAttr(Oid relId, int attNumber)
! {
!     SysScanDesc conscan;
!     ScanKeyData skey;
!     HeapTuple   tuple;
!     Relation    conrel;
! 
!     conrel = heap_open(ConstraintRelationId, AccessShareLock);
!     
! 	ScanKeyInit(&skey,
!                 Anum_pg_constraint_conrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(relId));
! 
!     conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
!                                  SnapshotNow, 1, &skey);
! 	
!     while (HeapTupleIsValid(tuple = systable_getnext(conscan)))
!     {
! 		int 		count;
! 		bool		isNull;
! 		ArrayType  	*arr;
! 		Datum		*attrs;
! 		int			i;
! 
!         Form_pg_constraint  conForm = (Form_pg_constraint) GETSTRUCT(tuple);
! 		
! 		arr = DatumGetArrayTypeP(SysCacheGetAttr(CONSTROID, tuple, Anum_pg_constraint_conkey, &isNull));
! 
! 		count = ARR_DIMS(arr)[0];	
! 
! 		deconstruct_array(arr, INT2OID, 2, true, 's', &attrs, NULL, &count);
! 
! 		for(i=0; i<count; i++)
! 		{
! 			if(attrs[i] == attNumber)
! 			{
! 				List		*queryList;
! 				Node		*parseTree;
! 				Relation 	rel = RelationIdGetRelation(relId);
! 				StringInfo	query = makeStringInfo();
! 	
! 				appendStringInfo(query, "ALTER TABLE %s DROP CONSTRAINT %s", RelationGetRelationName(rel), conForm->conname.data);
! 				RelationClose(rel);
! 				queryList  = pg_parse_query(query->data);
! 				parseTree = (Node *)lfirst(list_head(queryList));
! 				AlterTable((AlterTableStmt *)parseTree);					
! 			}
! 		}
! 	}
! 
!     systable_endscan(conscan);
!     heap_close(conrel, AccessShareLock);
! }
! 
! /*
!  * ATExecExchangePartition: Exchange a partition with an existing table.
!  */
! static void 
! ATExecExchangePartition(AlteredTableInfo *tab, Relation rel,
! 	ExchangePartitionStmt *part)
! {
! 	Oid			tableId;
! 	Oid			partitionId;
! 	ScanKeyData skey;
! 	Relation    pg_partrel;
! 	SysScanDesc pg_partscan;
! 	HeapTuple   pg_parttup;
! 	Datum		minDatum;
! 	Datum		maxDatum;
! 	char		*partitionColumn;
! 	StringInfo	query = makeStringInfo();
! 	List		*queryList;
! 	Node		*parseTree;		
! 	Relation 	relation;
! 	StringInfo	createTrigger = makeStringInfo();
! 	Datum 			values[Natts_pg_partition];
! 	char  			nulls [Natts_pg_partition];
! 
! 	/* Get the relId from the tablename. */
! 	partitionId = RelnameGetRelid(((RangeVar *)linitial(part->partNames))->relname);
! 	if(!((partitionId != InvalidOid) && IsPartition(partitionId)))
! 		elog(ERROR, "Please specify a valid partition name.");
! 
! 	tableId	= RelnameGetRelid(((RangeVar *)lsecond(part->partNames))->relname);	
! 	if(tableId == InvalidOid)
! 		elog(ERROR, "Please specify a valid table name.");
! 		
! 	if(GotConstraints(tableId))
! 		elog(ERROR, "Can not exchange the partition '%s' with table '%s'. Please make sure that there are no constraints on table '%s' before proceeding.", 
! 			((RangeVar *)linitial(part->partNames))->relname,
! 			((RangeVar *)lsecond(part->partNames))->relname,
! 			((RangeVar *)lsecond(part->partNames))->relname);
! 
! 	if(GotTriggers(tableId))
! 		elog(ERROR, "Can not exchange the partition '%s' with table '%s'. Please make sure that there are no triggers on table '%s' before proceeding.", 
! 			((RangeVar *)linitial(part->partNames))->relname,
! 			((RangeVar *)lsecond(part->partNames))->relname,
! 			((RangeVar *)lsecond(part->partNames))->relname);
! 
!     /* Inherit the table from the partitioned-table. */
!     resetStringInfo(query);
!     appendStringInfo(query, "ALTER TABLE %s INHERIT %s", ((RangeVar *)lsecond(part->partNames))->relname, RelationGetRelationName(rel));
!     queryList  = pg_parse_query(query->data);
!     parseTree  = (Node *)lfirst(list_head(queryList));
!     AlterTable(( AlterTableStmt * )parseTree);
!     CommandCounterIncrement();
! 
!     /* Rename the existing partition to a temp. name so that incoming table can have that name.*/
!     resetStringInfo(query);
!     appendStringInfo(query, "ALTER TABLE %s RENAME TO tmp_%u", ((RangeVar *)linitial(part->partNames))->relname, RelationGetRelid(rel));
!     queryList  = pg_parse_query(query->data);
!     parseTree  = (Node *)lfirst(list_head(queryList));
!     ExecRenameStmt(( RenameStmt * )parseTree);
!     CommandCounterIncrement();
! 
!     /* Rename the incoming table as partition. */
!     resetStringInfo(query);
!     appendStringInfo(query, "ALTER TABLE %s RENAME TO %s", ((RangeVar *)lsecond(part->partNames))->relname, ((RangeVar *)linitial(part->partNames))->relname);
!     queryList  = pg_parse_query(query->data);
!     parseTree  = (Node *)lfirst(list_head(queryList));
!     ExecRenameStmt(( RenameStmt * )parseTree);
!     CommandCounterIncrement();
! 
!     /* Rename the incoming table as partition. */
!     resetStringInfo(query);
!     appendStringInfo(query, "ALTER TABLE tmp_%u RENAME TO %s", RelationGetRelid(rel), ((RangeVar *)lsecond(part->partNames))->relname);
!     queryList  = pg_parse_query(query->data);
!     parseTree  = (Node *)lfirst(list_head(queryList));
!     ExecRenameStmt(( RenameStmt * )parseTree);
!     CommandCounterIncrement();
! 
!     /* Inherit the table from the partitioned-table. */
!     resetStringInfo(query);
!     appendStringInfo(query, "ALTER TABLE %s NO INHERIT %s", ((RangeVar *)lsecond(part->partNames))->relname, RelationGetRelationName(rel));
!     queryList  = pg_parse_query(query->data);
!     parseTree  = (Node *)lfirst(list_head(queryList));
!     AlterTable(( AlterTableStmt * )parseTree);
!     CommandCounterIncrement();
! 
!     /*Scan key to scan pg_partition table on parentrelid*/
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_partrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(partitionId));
! 
!     pg_partrel = heap_open(PartitionRelationId, RowExclusiveLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
! 		HeapTuple copyTuple = heap_copytuple(pg_parttup);
! 
!         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(copyTuple);
! 
! 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
! 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
! 
! 		/* Get the name of partition key column */
! 		partitionColumn = get_attname (partitionId, pg_part->partkey);
! 
! 		/* Remove the constraint on partition-to-be-normal-table*/
! 		RemoveConstraintsAttr(partitionId, pg_part->partkey);
! 
! 		if(nulls[Anum_pg_partition_minval-1] == 'n')
! 		{
! 			maxDatum = GetDatum(pg_partrel, pg_part->keytype, copyTuple, Anum_pg_partition_maxval);
! 
! 			AddLessThanCheckConstraint(pg_part->keytype, 
! 									maxDatum,
! 									((RangeVar *)linitial(part->partNames))->relname, 
! 									partitionColumn);				
! 		}
! 		else if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 		{
! 			minDatum = GetDatum(pg_partrel, pg_part->keytype, copyTuple, Anum_pg_partition_minval);
! 
! 			AddGreaterThanCheckConstraint(pg_part->keytype, 
! 									minDatum, 
! 									((RangeVar *)linitial(part->partNames))->relname, 
! 									partitionColumn);	
! 		}
! 		else
! 		{
! 			minDatum = GetDatum(pg_partrel, pg_part->keytype, copyTuple, Anum_pg_partition_minval);
! 			maxDatum = GetDatum(pg_partrel, pg_part->keytype, copyTuple, Anum_pg_partition_maxval);
! 
! 			AddCheckConstraint(pg_part->keytype, minDatum, maxDatum, ((RangeVar *)linitial(part->partNames))->relname, partitionColumn); 
! 		}
! 
! 		/* Change the partition to */
! 		pg_part->partrelid = tableId;
! 
! 		simple_heap_update(pg_partrel, &copyTuple->t_self, copyTuple);
! 		CatalogUpdateIndexes(pg_partrel, copyTuple);
! 		heap_freetuple(copyTuple);
! 	}
! 
! 	systable_endscan(pg_partscan);
! 	heap_close(pg_partrel, RowExclusiveLock);	
! 
! 	relation = RelationIdGetRelation(tableId);
! 	resetStringInfo(createTrigger);
! 	appendStringInfo(createTrigger, "CREATE TRIGGER partition_update_%u BEFORE UPDATE ON %s ", RelationGetRelid(relation), RelationGetRelationName(relation));
! 	appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_update_trigger();");
! 	relation_close(relation, 0);
! 	CommandCounterIncrement();
! 
! 	queryList = pg_parse_query(createTrigger->data);
! 	parseTree = (Node *)lfirst(list_head(queryList));
! 	CreateTrigger((CreateTrigStmt * )parseTree, 0, false);
! 
! 	/* Remove the partition trigger as table is not a partition anymore.*/
! 	RemovePartitionTrigger(partitionId);
! 
! 	/* To avoid tuple being updated by the current transaction, after the current scan started */
! 	CommandCounterIncrement();
! }	
! /*
!  * ATExecSplitPartition : Split existing partition by specifying a valid split-point.
!  */
! static void 
! ATExecSplitPartition(AlteredTableInfo *tab, Relation rel,
! 	SplitPartitionStmt *part)
! {
! 	Oid 			relId;
! 	ScanKeyData		skey;
! 	Relation		pg_partrel;
! 	SysScanDesc		pg_partscan;
! 	HeapTuple		pg_parttup;
! 	Datum 			minDatum;
! 	Datum			maxDatum;
! 	ListCell		*node;
! 	char			*columnName;
! 	Partition		*partition2 = NULL;
! 	Partition		*partition1 = NULL;
! 	Const			*cnst;
! 	int16			len;
! 	bool			typeByVal;
! 	StringInfo		query = makeStringInfo();
! 	List			*queryList;
! 	Node			*parseTree;
! 	Oid				splitTable;
! 	bool			flag = false;
! 	Snapshot		snap;
! 	Relation 		tmpRel;
! 	HeapScanDesc	scanDesc;
! 	HeapTuple		tuple;
! 	Oid				relation_id;
! 	Relation		child_table_relation;
! 	Datum			*values;
! 	char			*nulls;
! 	bool			*bNulls;
! 	int				nAttr; 
! 	HeapTuple 		newTuple;
! 	int				i;
! 	char			*constraint1 = NULL;
! 	char			*constraint2 = NULL;
! 	PartitionRowInfo	*partRowInfo;
! 	List			*distinct_part_key_list = NULL;
! 	List			*rows_to_be_deleted_list = NULL;
! 	bool			dummyEntry;
! 	int				partitionCount;
! 	
! 	/* Get the relId from the tablename. */
! 	if(list_head(part->partNames))
! 	{
! 		relId  = RelnameGetRelid(((RangeVar *)linitial(part->partNames))->relname);
! 		if (relId == InvalidOid)
! 			elog(ERROR, "'%s' is not a valid partition.", ((RangeVar *)linitial(part->partNames))->relname);
! 	}
! 	else
! 	{
! 		elog(ERROR, "Please specify valid partition to be splitted.");
! 	}
! 
! 	/*Check if new partitions have same name. */
! 	if(lnext(list_head(part->partNames)) && lnext(lnext(list_head(part->partNames))))
! 	{
! 		if(strcmp(((RangeVar *)lsecond(part->partNames))->relname, ((RangeVar *)lthird(part->partNames))->relname) == 0)
! 		{
! 			elog(ERROR, "Resultant partitions can not have same name.");	
! 		}
! 		
! 		if(strcmp(((RangeVar *)linitial(part->partNames))->relname, ((RangeVar *)lsecond(part->partNames))->relname) == 0)
! 		{
! 			elog(ERROR, "Resultant partition can not have same name as the name of partition to be splitted");
! 		}
! 		
! 		if(strcmp(((RangeVar *)linitial(part->partNames))->relname, ((RangeVar *)lthird(part->partNames))->relname) == 0)
! 		{
! 			elog(ERROR, "Resultant partition can not have same name as the name of partition to be splitted");
! 		}
! 	}
! 	else
! 	{
! 		elog(ERROR, "Please specify resultant partitions to be updated.");
! 	}
! 
! 	/* Check number of partitions present on a given table. */
! 	partitionCount = GetPartitionsCount(RelationGetRelid(rel));
! 
! 	/* If there is only one partition present for a given partitioned-table, then it would be treated as special case for splitting. */
! 	if(partitionCount > 1)
! 		dummyEntry = false;
! 	else
! 		dummyEntry = true;
! 
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_partrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(relId));
! 
!     pg_partrel = heap_open(PartitionRelationId, RowExclusiveLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
! 	values = palloc(sizeof(Datum) * Natts_pg_partition);
! 	nulls  = palloc(sizeof(char) * Natts_pg_partition);
! 	bNulls = palloc(sizeof(bool) * Natts_pg_partition);
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
!         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
! 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
! 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
! 
!         if(pg_part->parttype == PART_RANGE)
!         {
! 			if (!list_member_int(distinct_part_key_list, pg_part->partkey))
! 			{
! 				distinct_part_key_list = lappend_int(distinct_part_key_list, pg_part->partkey);				
! 			}	
! 
!             /* Get len and typbyval from pg_type */
!             get_typlenbyval(pg_part->keytype, &len, &typeByVal);
! 
!             if(pg_part->keyorder == 1)
!             {
!                 /* Delete the entries for partition to be splitted, only if we can still have partition metadata.*/
!                 if(dummyEntry == false)
!                     RemovePartitionMetadata(pg_partrel, rows_to_be_deleted_list);
! 
!                 /* Form resultant partitions. */
!                 partition1                  = makeNode(Partition);
!                 partition1->partName        = makeNode(RangeVar);
!                 partition1->partitionCheck  = makeNode(Constraint);
! 
!                 partition2                  = makeNode(Partition);
!                 partition2->partName        = makeNode(RangeVar);
!                 partition2->partitionCheck  = makeNode(Constraint);
! 
!                 partition1->partName        = (RangeVar *)lsecond(part->partNames);
!                 partition1->partitionCheck->max_value = part->splitValues;
! 
!                 partition2->partName        = (RangeVar *)lthird(part->partNames);
!                 partition2->partitionCheck->min_value = part->splitValues;
! 
!                 node = list_head(part->splitValues);
!             }
! 
! 			if(nulls[Anum_pg_partition_minval-1] == 'n')
! 			{				
! 				Node 	*tmpNode = makeColumnRef("minvalue", NULL, -1);
! 				partition1->partitionCheck->min_value = lappend(partition1->partitionCheck->min_value, tmpNode);
! 			}
! 			else
! 			{
! 				/* Fetch the min and max value for given attribute of partition. */
! 				minDatum = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval);
!         	    /* Form the const node out of datums. */
!             	cnst = makeConst(pg_part->keytype,
!                 	        -1,
!                     	    len,
!                         	minDatum,
! 	                        false,
!     	                    typeByVal);
! 
!         	    cnst->location = -1;
! 
!             	partition1->partitionCheck->min_value = lappend(partition1->partitionCheck->min_value, cnst);
! 			}
! 
! 			if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 			{
! 				Node 	*tmpNode = makeColumnRef("maxvalue", NULL, -1);
! 				partition2->partitionCheck->max_value = lappend(partition2->partitionCheck->max_value, tmpNode);
! 			}
! 			else
! 			{
! 				maxDatum = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval);
! 
! 	            /* Form the const node out of datums. */
!     	        cnst = makeConst(pg_part->keytype,
!         	                -1,
!             	            len,
!                 	        maxDatum,
!                     	    false,
!                         	typeByVal);
! 
! 	            cnst->location = -1;
! 
!     	        partition2->partitionCheck->max_value = lappend(partition2->partitionCheck->max_value, cnst);
! 			}
! 	
! 			/* Get the column name. */
! 			columnName = get_attname (relId, pg_part->partkey);
! 		
! 			EvalExpr(node, pg_part->keytype, columnName);
! 			DisplayDatum(((Const *)lfirst(node))->constvalue, pg_part->keytype);
! 
! 			if((OperateDatums(">", pg_part->keytype, ((Const *)lfirst(node))->constvalue, minDatum) == false) ||
! 				(OperateDatums("<", pg_part->keytype, ((Const *)lfirst(node))->constvalue, maxDatum) == false))
! 			{
! 				elog(ERROR, "Split-point is not valid. Value for '%s' attribute should be in-between and excluding '%s' and '%s'.", columnName, 
! 					DisplayDatum(minDatum, pg_part->keytype), DisplayDatum(maxDatum, pg_part->keytype));
! 			}
! 		
! 			/* Get len and typbyval from pg_type */
! 			get_typlenbyval(pg_part->keytype, &len, &typeByVal);
! 
! 			node = lnext(node);
! 
! 
! 			partRowInfo = palloc(sizeof(PartitionRowInfo));
! 			memcpy(&partRowInfo->tid, &pg_parttup->t_self, sizeof(ItemPointerData));
! 			partRowInfo->partRelOid = pg_part->partrelid;
! 			rows_to_be_deleted_list = lappend(rows_to_be_deleted_list, partRowInfo);			
! 		}
! 	}
! 
! 	pfree(values);
! 	pfree(nulls);
! 	pfree(bNulls);
! 
! 	if(dummyEntry == false)
! 		RemovePartitionMetadata(pg_partrel, rows_to_be_deleted_list);
! 
! 	/* Add the resultant partitions and collect any check constraints to be added 
!  		(if resultant partition is same as parent table) */
! 	if(dummyEntry == true)
! 	{
! 		constraint1 = ATExecAddPartition(tab, rel, partition1, true);
! 		RemovePartitionMetadata(pg_partrel, rows_to_be_deleted_list);
! 	}
! 	else
! 	{
! 		constraint1 = ATExecAddPartition(tab, rel, partition1, false);
! 	}
! 
!     systable_endscan(pg_partscan);
! 	heap_close(pg_partrel, RowExclusiveLock);
! 
! 	constraint2 = ATExecAddPartition(tab, rel, partition2, false);
! 
! 	splitTable = RelnameGetRelid(((RangeVar *)linitial(part->partNames))->relname);
! 
! 	if((partition1 != NULL) && (partition2 != NULL))
! 	{
! 		snap = GetActiveSnapshot();
! 		tmpRel 	= heap_open(relId, RowExclusiveLock);
! 		scanDesc = heap_beginscan(tmpRel, snap, 0, NULL);
! 
!     	while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, ForwardScanDirection)))
! 		{
! 
! 			relation_id = get_relevant_partition(tuple, rel);
! 			
! 			/* form a new tuple with the existing tuple and insert into resultant partition.*/
! 			if( relation_id!= splitTable)
! 			{
! 				if (relation_id == InvalidOid)
! 					elog(ERROR, "Could not find valid partition.");
! 
! 				nAttr = HeapTupleHeaderGetNatts(tuple->t_data);
! 
! 		        values = palloc(sizeof(Datum) * nAttr);
!         		nulls  = palloc(sizeof(char) * nAttr);
! 		        bNulls = palloc(sizeof(bool) * nAttr);
! 				
! 				heap_deformtuple(tuple, rel->rd_att, values, nulls);
! 
! 				for(i=0; i<nAttr; i++)
! 				{
! 					if(nulls[i] == 'n')
! 						bNulls[i] = true;
! 					else
! 						bNulls[i] = false;
! 				}
! 
! 				child_table_relation = heap_open(relation_id, RowExclusiveLock);	
! 				newTuple = heap_form_tuple(child_table_relation->rd_att, values, bNulls);
! 				simple_heap_insert(child_table_relation, newTuple);
! 				CatalogUpdateIndexes(child_table_relation, newTuple);
! 				heap_close(child_table_relation, RowExclusiveLock);
! 
! 				simple_heap_delete(tmpRel, &tuple->t_self);
! 				CommandCounterIncrement();
! 
! 		        pfree(values);
!         		pfree(nulls);
! 		        pfree(bNulls);				
! 			}
! 			else
! 			{
! 				/* If one of the halves is parent then dont drop it.*/
! 				flag = true;
! 			}
! 		}
! 		
! 		heap_endscan(scanDesc);
! 		heap_close(tmpRel, RowExclusiveLock);
! 
! 		/* clear the buffer. */
! 		resetStringInfo(query);
! 
! 		/* Add check constraints, if any.*/
! 		AddCheckConstraints(constraint1);
! 		AddCheckConstraints(constraint2);
! 	
! 		if(flag != true)
! 		{
! 			appendStringInfo(query, "DROP TABLE %s CASCADE;", ((RangeVar *)linitial(part->partNames))->relname);
! 			queryList = pg_parse_query(query->data);
! 			parseTree = (Node *)lfirst(list_head(queryList));
! 			RemoveRelations((DropStmt *)parseTree);
! 		}
! 	}
! }
! 
! /*
!  * ATExecUpdatePartition : Update the existing range partition to extend ranges.
!  * NOTE : If you want to trim any range then split the partition and drop 
!  * un-wanted range partition.
!  */
! static void 
! ATExecUpdatePartition(AlteredTableInfo *tab, Relation rel,
! 	Partition *part)
! {
! 	Oid				relId;
! 	ScanKeyData 	skey;
! 	Relation		pg_partrel;
! 	SysScanDesc		pg_partscan;
! 	HeapTuple		pg_parttup;
! 	ListCell		*minIndexAfter;
! 	ListCell		*maxIndexAfter;
! 	char			*partitionColumn;
! 	Oid				keycmp_oid;
! 	bool			isdef;
! 	Oid				keycmp_proc;
! 	bool			gte_max, lte_min;
! 	List			*distinct_part_rel_oid_list = NULL;
! 	List			*distinct_part_key_list = NULL;
! 	Oid				*childOids;
! 	int				j = 0;
! 	Partition		*tmp;	
! 	PartitionAttrs	*partition_attr;
! 	int16			len;
! 	bool			typbyval;
! 	Datum			part_attr;
! 	Const			*tmp_const;
! 	int				keyorder;
! 	Oid				typ_oid;
! 	Datum			minDatum;
! 	Datum			maxDatum;
! 	Datum 			values[Natts_pg_partition];
! 	char  			nulls [Natts_pg_partition];
! 
! 	/* Get the relId from the tablename. */
! 	if(part->partName)
! 	{
! 		relId  = RelnameGetRelid(part->partName->relname);
! 		if (relId == InvalidOid)
! 			elog(ERROR, "Specified partition '%s' does not exist.", part->partName->relname);
! 	}
! 	else
! 	{
! 		elog(ERROR, "Please specify valid partition to be updated.");
! 	}
! 
! 	childOids = malloc(sizeof(Oid)*GetPartitionsCount(RelationGetRelid(rel))); 
! 
! 	ScanKeyInit(&skey,
! 		Anum_pg_partition_parentrelid,
! 		BTEqualStrategyNumber, F_OIDEQ,
! 		ObjectIdGetDatum(RelationGetRelid(rel)));
! 
! 	pg_partrel = heap_open(PartitionRelationId, RowExclusiveLock);
! 	pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
! 					SnapshotNow, 1, &skey);
! 
! 	/* Create partition attribute node. */
! 	partition_attr = makeNode(PartitionAttrs);
!  
! 	while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
! 		Relation tmp_rel;
! 
! 		/* Instead of pg_part Use heap_getattr for accessing bytea coluns */
! 		Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
! 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
! 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
! 
! 		if(pg_part->parttype == PART_RANGE)
! 		{
! 
! 			if (!list_member_int(distinct_part_key_list, pg_part->partkey))
! 			{
! 				Alias *colName;
! 
! 				distinct_part_key_list = lappend_int(distinct_part_key_list, pg_part->partkey);
! 
! 				/* Get the name of partition key column */
! 				partitionColumn = get_attname (rel->rd_id, pg_part->partkey);
! 
! 				/* Add the partition key columns. */
! 				colName = makeAlias(partitionColumn, NULL);
! 				partition_attr->colName = lappend(partition_attr->colName, colName);								
! 			}
! 
! 			if(relId == pg_part->partrelid)
! 			{
! 				if((nulls[Anum_pg_partition_minval-1] == 'n') || (nulls[Anum_pg_partition_minval-1] == 'n'))
! 					elog(ERROR, "Ranges can only be extended. Try considering SPLIT.");
! 
! 				if(pg_part->keyorder == 1)
! 				{
! 					keyorder = 0;
! 
! 					/* Set the ptr to first value. */
! 					minIndexAfter = part->partitionCheck->min_value->head;
! 					maxIndexAfter = part->partitionCheck->max_value->head;
! 				}
! 		
! 				/* Get the name of partition key column */
! 				partitionColumn = get_attname (rel->rd_id, pg_part->partkey);	
! 
! 				/* Get len and typbyval from pg_type */
! 				get_typlenbyval(pg_part->keytype, &len, &typbyval);
! 
! 				typ_oid = pg_part->keytype;
! 
! 				/* Is this a valid range? */	
! 				IsValidRange(minIndexAfter, maxIndexAfter, RelationGetRelid(rel), partitionColumn, part->partName->relname);			
! 
! 				/* Drop the earlier constraint. */
! 				DropCheckConstraint(part->partName->relname, partitionColumn);
! 
! 				keycmp_oid = OperatorGet(">=", PG_CATALOG_NAMESPACE , pg_part->keytype, pg_part->keytype, &isdef);
! 
! 				if(isdef == FALSE)
! 					elog(ERROR, "'>=' operator is not defined for this type.");
! 
! 				keycmp_proc = get_opcode(keycmp_oid);				
! 				maxDatum = GetDatum(pg_partrel, typ_oid, pg_parttup, Anum_pg_partition_maxval);
! 				gte_max = DatumGetBool(OidFunctionCall2(keycmp_proc, ((Const *)lfirst(maxIndexAfter))->constvalue, maxDatum));
! 
! 				if(gte_max == false)
! 					elog(ERROR, "Range of partition can only be extended.");
! 
! 				keycmp_oid = OperatorGet("<=", PG_CATALOG_NAMESPACE , pg_part->keytype, pg_part->keytype, &isdef);
! 
! 				if(isdef == FALSE)
! 					elog(ERROR, "'<=' operator is not defined for this type.");
! 
! 				keycmp_proc = get_opcode(keycmp_oid);
! 				minDatum = GetDatum(pg_partrel, typ_oid, pg_parttup, Anum_pg_partition_minval);
! 				lte_min = DatumGetBool(OidFunctionCall2(keycmp_proc, ((Const *)lfirst(minIndexAfter))->constvalue, maxDatum));
! 
! 				if(lte_min == false)
! 					elog(ERROR, "Range of partition can only be extended.");
! 
! 				/* Delete the row. */
! 				simple_heap_delete(pg_partrel, &pg_parttup->t_self);
! 
! 				/* Insert the new updated row. */
! 				WriteRangePartitionToCatalog(((Const *)lfirst(minIndexAfter))->constvalue,
! 					((Const *)lfirst(maxIndexAfter))->constvalue,
! 					len,
! 					typbyval,
! 					RelationGetRelid(rel),
! 					relId,
! 					get_attnum(RelationGetRelid(rel), partitionColumn),
! 					typ_oid,
! 					++keyorder,
! 					OTHER);					
! 
! 				/* Add the new constraint. */
! 				AddCheckConstraint(typ_oid, 
! 					((Const *)lfirst(minIndexAfter))->constvalue, 
! 					((Const *)lfirst(maxIndexAfter))->constvalue, 
! 					part->partName->relname, 
! 					partitionColumn);  
! 
! 				minIndexAfter = minIndexAfter->next;
! 				maxIndexAfter = maxIndexAfter->next;
! 			}
! 			else
! 			{
! 				if (!list_member_oid(distinct_part_rel_oid_list, pg_part->partrelid))
! 				{
! 					distinct_part_rel_oid_list = lappend_oid(distinct_part_rel_oid_list, pg_part->partrelid);
! 					childOids[j++] = pg_part->partrelid;
! 			
! 					tmp = makeNode(Partition);
! 					tmp->partName 		= makeNode(RangeVar);
! 					tmp->partitionCheck	= makeNode(Constraint);
! 
! 					/* Add this partition to partition attributes. */
! 					partition_attr->partitions = lappend(partition_attr->partitions, tmp);
! 				}
! 
! 				tmp_rel = RelationIdGetRelation(pg_part->partrelid);
! 				tmp->partName->relname = RelationGetRelationName(tmp_rel);
! 				relation_close(tmp_rel, 0);
! 
! 				/* Get the name of partition key column */
! 				partitionColumn = get_attname (rel->rd_id, pg_part->partkey);	
! 
! 				/* Get len and typbyval from pg_type */
! 				get_typlenbyval(pg_part->keytype, &len, &typbyval);
! 
! 				if(nulls[Anum_pg_partition_minval-1] == 'n')
! 				{				
! 					Node 	*tmpNode = makeColumnRef("minvalue", NULL, -1);
! 
! 					/* Add this to new partition. */
! 					tmp->partitionCheck->min_value = lappend(tmp->partitionCheck->min_value, tmpNode);				
! 				}
! 				else
! 				{		
! 
! 					part_attr = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval);
! 
! 					/* Create const. */		
! 					tmp_const = makeConst(pg_part->keytype,	/* Const type */
! 											-1,
! 											len,
! 											part_attr,
! 											false,
! 											typbyval);
! 
! 					tmp_const->location = -1;
! 
! 					/* Add this to new partition. */
! 					tmp->partitionCheck->min_value = lappend(tmp->partitionCheck->min_value, tmp_const);
! 				}
! 
! 
! 				if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 				{
! 					Node 	*tmpNode = makeColumnRef("maxvalue", NULL, -1);
! 
! 					/* Add this to new partition. */
! 					tmp->partitionCheck->max_value = lappend(tmp->partitionCheck->max_value, tmpNode);				
! 				}
! 				else
! 				{			
! 					part_attr = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval);
! 	
! 					/* Create const. */		
! 					tmp_const = makeConst(pg_part->keytype,	/* Const type */
! 											-1,
! 											len,
! 											part_attr,
! 											false,
! 											typbyval);
! 
! 					tmp_const->location = -1;
! 
! 					/* Add this to new partition. */
! 					tmp->partitionCheck->max_value = lappend(tmp->partitionCheck->max_value, tmp_const);
! 				}
! 			}
! 		}
! 	}
! 
! 	childOids[j++] = relId;
! 	partition_attr->partitions = lappend(partition_attr->partitions, part);
! 
! 	ValidateRanges(partition_attr, RelationGetRelid(rel), childOids);
! 
! 	systable_endscan(pg_partscan);
! 	heap_close(pg_partrel, RowExclusiveLock);
! 
! 	/* If there are any rows in overflow partition which can satisfy partition constraints 
! 	of latest partition, then move them out of overflow.*/
! 	MoveValidRowsFromOverflow(GetOverflowPartition(rel), relId);
! }
! 
! /* 
!  * ATExecDropPartitionByRange : Drop the partition by specified range.
!  */
! static void
! ATExecDropPartitionByRange(AlteredTableInfo *tab, Relation rel,
!     Partition *part)
! {
! 	List		*rows_to_be_deleted_list = NULL;
! 	List		*distinct_part_key_list= NULL;
!     ScanKeyData	skey;
!     SysScanDesc	pg_partscan;
!     HeapTuple  	pg_parttup;
!     Relation   	pg_partrel;
! 	char		*partitionColumn;
! 	int16		len;
! 	ListCell	*minIndex;
! 	ListCell	*maxIndex;
! 	bool		typbyval;
! 	Datum		min_datum;
! 	Datum		max_datum;
! 	Oid			keycmp_oid;
! 	bool		isdef;
! 	Oid			keycmp_proc;
! 	bool		lte_min;
! 	bool		gte_max;
! 	Node		*nodeMin, *nodeMax;
! 	Datum		values[Natts_pg_partition];
! 	char 		nulls [Natts_pg_partition];
! 	PartitionRowInfo	*partRowInfo;
! 
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_parentrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(RelationGetRelid(rel)));
! 
!     pg_partrel = heap_open(PartitionRelationId, RowExclusiveLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
!         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
! 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
! 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
! 
! 		if(pg_part->parttype == PART_RANGE)
! 		{
! 			if (!list_member_int(distinct_part_key_list, pg_part->partkey))
! 			{
! 				distinct_part_key_list = lappend_int(distinct_part_key_list, pg_part->partkey);				
! 			}	
! 
! 			if(pg_part->keyorder == 1)
! 			{
! 				/* Set the ptr to first value. */
! 				minIndex = part->partitionCheck->min_value->head;
! 				maxIndex = part->partitionCheck->max_value->head;
! 
! 				if(list_length(distinct_part_key_list)== list_length(rows_to_be_deleted_list))
! 				{
! 					PartitionRowInfo *tmp = linitial(rows_to_be_deleted_list);
! 
! 					/* If the last partition is being asked to be dropped then throw the msg. */
! 					if(GetPartitionsCount(RelationGetRelid(rel)) == 1)
! 						elog(ERROR, "Can not drop the last partition. Drop the partitioned-table instead.");
! 
! 					RemovePartitionMetadata(pg_partrel, rows_to_be_deleted_list);
! 					DropPartition(tmp->partRelOid);
! 				}
! 				rows_to_be_deleted_list = NULL;
! 			}
! 			
! 			/* Get the name of partition key column */
! 			partitionColumn = get_attname (rel->rd_id, pg_part->partkey);	
! 
! 			/* Get len and typbyval from pg_type */
! 			get_typlenbyval(pg_part->keytype, &len, &typbyval);
! 
! 			if(nulls[Anum_pg_partition_minval-1] == 'n')
! 			{
! 				nodeMin = makeColumnRef("minvalue", NULL, -1);
! 			}
! 			else
! 			{
! 				min_datum = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval);
! 	
! 				nodeMin = (Node *)makeConst(pg_part->keytype,	/* Const type */
! 										-1,
! 										len,
! 										min_datum,
! 										false,
! 										typbyval);
! 			}
! 		
! 			if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 			{
! 				nodeMax = makeColumnRef("maxvalue", NULL, -1);			
! 			}
! 			else
! 			{
! 				max_datum = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval);
! 	
! 				nodeMax = (Node *)makeConst(pg_part->keytype,	/* Const type */
! 										-1,
! 										len,
! 										max_datum,
! 										false,
! 										typbyval);
! 			}
! 		
! 			/* Is this a valid range? */	
! 			IsValidRange(minIndex, maxIndex, RelationGetRelid(rel), partitionColumn, RelationGetRelationName(rel));
! 		
! 			if(IsMinValue(lfirst(minIndex)))
! 			{
! 				lte_min = true;
! 			}
! 
! 			if(IsMaxValue(lfirst(maxIndex)))
! 			{
! 				gte_max = true;
! 			}
! 
! 			if(IsMinValue(nodeMin) && !(IsMinValue(lfirst(minIndex))))
! 			{
! 				lte_min = false;
! 			}
! 			else if(IsMaxValue(nodeMax) && !(IsMaxValue(lfirst(maxIndex))))
! 			{
! 				gte_max = false;
! 			}
! 			else 
! 			{			
! 				if (IsA(lfirst(minIndex), Const) &&  IsA(nodeMin, Const))
! 				{
! 					keycmp_oid = OperatorGet("<=", PG_CATALOG_NAMESPACE , pg_part->keytype, pg_part->keytype, &isdef);
! 
! 					if(isdef == FALSE)
! 						elog(ERROR, "'<=' operator is not defined for this type.");
! 
! 					keycmp_proc = get_opcode(keycmp_oid);
! 					lte_min = DatumGetBool(OidFunctionCall2(keycmp_proc, ((Const *)lfirst(minIndex))->constvalue, min_datum));
! 				}
! 
! 				if(IsA(lfirst(maxIndex), Const) && IsA(nodeMax, Const))
! 				{
! 					keycmp_oid = OperatorGet(">=", PG_CATALOG_NAMESPACE , pg_part->keytype, pg_part->keytype, &isdef);
! 
! 					if(isdef == FALSE)
! 						elog(ERROR, "'>=' operator is not defined for this type.");
! 
! 					keycmp_proc = get_opcode(keycmp_oid);
! 					gte_max = DatumGetBool(OidFunctionCall2(keycmp_proc, ((Const *)lfirst(maxIndex))->constvalue, max_datum));
! 				}
! 			}
! 
! 			if(lte_min && gte_max)
! 			{
! 				partRowInfo = palloc(sizeof(PartitionRowInfo));
! 				memcpy(&partRowInfo->tid, &pg_parttup->t_self, sizeof(ItemPointerData));
! 				partRowInfo->partRelOid = pg_part->partrelid;
! 				rows_to_be_deleted_list = lappend(rows_to_be_deleted_list, partRowInfo);
! 			}
! 			else
! 			{
! 				if(rows_to_be_deleted_list)
! 					rows_to_be_deleted_list = NULL;
! 			}
! 
! 			minIndex = minIndex->next;
! 			maxIndex = maxIndex->next;
! 
! 		}
! 	}
! 
! 	if(list_length(distinct_part_key_list)== list_length(rows_to_be_deleted_list))
! 	{
! 		PartitionRowInfo *tmp = linitial(rows_to_be_deleted_list);
! 
! 		/* If the last partition is being asked to be dropped then throw the msg. */
! 		if(GetPartitionsCount(RelationGetRelid(rel)) == 1)
! 			elog(ERROR, "Can not drop the last partition. Drop the partitioned-table instead.");
! 
! 		RemovePartitionMetadata(pg_partrel, rows_to_be_deleted_list);
! 		DropPartition(tmp->partRelOid);
! 	}
! 
!     systable_endscan(pg_partscan);
!     heap_close(pg_partrel, RowExclusiveLock);
! }
! 
! /* 
!  * ATExecDropPartitionByName : Drop partition by name specified.
!  */
! static void 
! ATExecDropPartitionByName(AlteredTableInfo *tab, Relation rel,
! 	Partition *part) 
! {
! 	Oid			relId;
! 
! 	if(part->partName)
! 	{
!  		relId = RelnameGetRelid(part->partName->relname);
! 
! 		if((IsPartition(relId) == false) || (relId == InvalidOid))
! 			elog(ERROR, "'%s' is not a valid partition.", part->partName->relname);
! 	}
! 	else
! 	{
! 		elog(ERROR, "Please specify valid partition name.");
! 	}
! 
! 	/* If the last partition is being asked to be dropped then throw the msg. */
! 	if(GetPartitionsCount(RelationGetRelid(rel)) == 1)
! 		elog(ERROR, "Can not drop the last partition. Drop the partitioned-table instead.");
! 
! 	DeletePartitionEntry(relId);
! 	DropPartition(relId);
! }
! 
! bool 
! IsMinValue(Node *value)
! {
! 	if(IsA(value, ColumnRef))
! 	{
! 		ColumnRef	*colRef = (ColumnRef *)value;
! 		Assert(list_length(colRef->fields)==1);
! 
! 		if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "minvalue") == 0)
! 			return true;		
! 	}
! 	return false;
! }
! 
! bool 
! IsMaxValue(Node *value)
! {
! 	if(IsA(value, ColumnRef))
! 	{
! 		ColumnRef	*colRef = (ColumnRef *)value;
! 		Assert(list_length(colRef->fields)==1);
! 
! 		if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "maxvalue") == 0)
! 			return true;		
! 	}
! 	return false;
! }
! 
! /*
!  * ATExecAddPartition : Add partition to an existing table. Currectly only range partition
!  * is supported.
!  */
! static char * 
! ATExecAddPartition(AlteredTableInfo *tab, 
! 	Relation rel, Partition *part, bool dummyEntry)
! {
! 	StringInfo 		query = makeStringInfo();
! 	StringInfo		createTrigger = makeStringInfo();
! 	StringInfo		tableName = makeStringInfo();
! 	StringInfo		constraint = makeStringInfo();
! 	List			*query_list;
! 	Node			*parsetree;
!     ScanKeyData 	skey;
!     SysScanDesc 	pg_partscan;
!     HeapTuple   	pg_parttup;
!     Relation    	pg_partrel;
!     List        	*distinct_part_key_list = NULL;	
! 	List			*distinct_part_rel_oid_list = NULL;
! 	ListCell		*minIndex, *maxIndex;
! 	Datum 			min_datum, max_datum;
! 	Oid 			typ_oid;
! 	bool 			typbyval;
! 	int16			len;
! 	char            *partitionColumn; 
! 	Partition		*tmp;
! 	Datum 			part_attr;
! 	PartitionAttrs	*partition_attr;
! 	int				partitionCount = 0;
! 	Oid				*childOids = NULL;
! 	int				j = 0;
! 	Oid				child;
! 	Const			*tmp_const;
! 	bool			flag = false;
! 	Datum 			values[Natts_pg_partition];
! 	char  			nulls [Natts_pg_partition];
! 	int				rangeVal;
! 	bool			isMinValue, isMaxValue;
! 	ListCell 		*partColumn;
! 
! 	if(part->partName)
! 	{
! 		child = RelnameGetRelid(part->partName->relname);
! 		if(child == InvalidOid)
! 		{
! 			/* This table does not exist so we can go ahead and create new table.*/
! 			flag = true;
! 		}
! 		else
! 		{
! 			if(tab->subcmds[AT_PASS_ADD_PARTITION])
! 			{	
! 				if(((AlterTableCmd *)lfirst(list_head(tab->subcmds[AT_PASS_ADD_PARTITION])))->subtype == AT_AddPartition)
! 					elog(ERROR, "'%s' already exists.", part->partName->relname);
! 			}
! 		}
! 	}
! 	else
! 	{
! 		int count = GetPartitionsCount(RelationGetRelid(rel));
! 		do
! 		{
! 			resetStringInfo(tableName);
! 			appendStringInfo(tableName, "%s_%d", RelationGetRelationName(rel), ++count);	
! 			child = RelnameGetRelid(tableName->data);	
! 		}while(child != InvalidOid);
! 
! 		part->partName = makeRangeVar(NULL, tableName->data, -1);
! 
! 		/* This table does not exist so we can go ahead and create new table.*/
! 		flag = true;
! 	}
! 	
! 	if(flag == true)
! 	{
! 		resetStringInfo(query);
! 	
! 		if(part->tablespacename)
! 			appendStringInfo(query, "CREATE TABLE %s () INHERITS (%s) TABLESPACE %s;", part->partName->relname, RelationGetRelationName(rel), part->tablespacename);
! 		else
! 			appendStringInfo(query, "CREATE TABLE %s () INHERITS (%s) ;", part->partName->relname, RelationGetRelationName(rel));
! 	
! 		query_list  = pg_parse_query(query->data);
! 		parsetree = (Node *)lfirst(list_head(query_list));
! 		child = DefineRelation((CreateStmt *)parsetree, RELKIND_RELATION);
! 	}
! 
! 	minIndex = part->partitionCheck->min_value->head;
! 	maxIndex = part->partitionCheck->max_value->head;
! 
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_parentrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(RelationGetRelid(rel)));
! 
!     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
! 	/* Create partition attribute node. */
! 	partition_attr = makeNode(PartitionAttrs);
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
! 
!         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
! 		if(pg_part->parttype == PART_RANGE)
! 		{
! 			partitionCount++;
! 			if (!list_member_int(distinct_part_key_list, pg_part->partkey))
! 			{
! 
! 				Alias *colName = NULL;
! 
! 				distinct_part_key_list = lappend_int(distinct_part_key_list, pg_part->partkey);
! 
! 				/* Get the name of partition key column */
! 				partitionColumn = get_attname (rel->rd_id, pg_part->partkey);
! 
! 				/* Add the partition key columns. */
! 				colName = makeAlias(partitionColumn, NULL);
! 				partition_attr->colName = lappend(partition_attr->colName, colName);
! 
! 				IsValidRange(minIndex, maxIndex, RelationGetRelid(rel), partitionColumn, part->partName->relname);	
! 
! 				/* If an existing table, then delete the earlier check constraint. */
! 				if(flag == false)
! 				{
! 					DropCheckConstraint(part->partName->relname, partitionColumn);	
! 
! 					appendStringInfo(constraint, FormCheckConstraint(pg_part->keytype, 
! 						((Const *)lfirst(minIndex))->constvalue, 
! 						((Const *)lfirst(maxIndex))->constvalue, 
! 						part->partName->relname, 
! 						partitionColumn	));	
! 				}
! 				else
! 				{
! 					if(IsA(lfirst(minIndex), ColumnRef))
! 					{
! 						ColumnRef	*colRef = lfirst(minIndex);		
! 			
! 						if(list_length(colRef->fields) == 1)
! 						{
! 							if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "minvalue") == 0)
! 							{
! 								AddLessThanCheckConstraint(pg_part->keytype, 
! 									((Const *)lfirst(maxIndex))->constvalue, 
! 									 part->partName->relname, 
! 									partitionColumn);	
! 							}
! 							else
! 							{
! 								elog(ERROR, "Not a valid value.");
! 							}
! 						}
! 					} 
! 					else if(IsA(lfirst(maxIndex), ColumnRef))
! 					{
! 						ColumnRef	*colRef = lfirst(maxIndex);		
! 			
! 						if(list_length(colRef->fields) == 1)
! 						{
! 							if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "maxvalue") == 0)
! 							{
! 								AddGreaterThanCheckConstraint(pg_part->keytype, 
! 									((Const *)lfirst(minIndex))->constvalue, 
! 									 part->partName->relname, 
! 									partitionColumn);	
! 							}
! 							else
! 							{
! 								elog(ERROR, "Not a valid value.");
! 							}
! 						}
! 					}
! 					else
! 					{
! 						AddCheckConstraint(pg_part->keytype, 
! 							((Const *)lfirst(minIndex))->constvalue, 
! 							((Const *)lfirst(maxIndex))->constvalue, 
! 							part->partName->relname, 
! 							partitionColumn);	
! 					}
! 				}
! 
! 				minIndex = minIndex->next;
! 				maxIndex = maxIndex->next;
! 			}
! 		}
! 	}
! 
! 	if(partitionCount == 0)
! 		elog(ERROR, "Could not find partition attributes of '%s'.", RelationGetRelationName(rel));
! 
! 	if(minIndex != NULL || maxIndex != NULL)
!        	elog(ERROR, "Multiple values specified for partition attributes for partition '%s'.", part->partName->relname);
! 
!     systable_endscan(pg_partscan);
!     heap_close(pg_partrel, AccessShareLock);
! 
!     /*Scan key to scan pg_partition table on parentrelid*/
!     ScanKeyInit(&skey,
!                 Anum_pg_partition_parentrelid,
!                 BTEqualStrategyNumber, F_OIDEQ,
!                 ObjectIdGetDatum(RelationGetRelid(rel)));
! 
!     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
!     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
!                                 SnapshotNow, 1, &skey);
! 
! 	if((partitionCount % list_length(distinct_part_key_list))==0)
! 	{
! 		childOids = malloc(sizeof(Oid) * (1 + (partitionCount/list_length(distinct_part_key_list))));
! 	}
! 
!     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
! 	{
! 		Relation tmp_rel;
! 
!         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
!         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
! 
! 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
! 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
! 			
! 		/* If dummy entry is present in partition catalog, then dont check it for overlap. */
! 		if(dummyEntry == true)
! 			break;
! 
! 		if(pg_part->parttype == PART_RANGE)
! 		{
! 
! 			if (!list_member_oid(distinct_part_rel_oid_list, pg_part->partrelid))
! 			{
! 				distinct_part_rel_oid_list = lappend_oid(distinct_part_rel_oid_list, pg_part->partrelid);
! 				childOids[j++] = pg_part->partrelid;
! 				
! 				tmp = makeNode(Partition);
! 				tmp->partName 		= makeNode(RangeVar);
! 				tmp->partitionCheck	= makeNode(Constraint);
! 
! 				/* Add this partition to partition attributes. */
! 				partition_attr->partitions = lappend(partition_attr->partitions, tmp);
! 			}
! 
! 			tmp_rel = RelationIdGetRelation(pg_part->partrelid);
! 			tmp->partName->relname = RelationGetRelationName(tmp_rel);
! 			relation_close(tmp_rel, 0);
! 
! 			/* Get the name of partition key column */
! 			partitionColumn = get_attname (rel->rd_id, pg_part->partkey);	
! 
! 			/* Get len and typbyval from pg_type */
! 			get_typlenbyval(pg_part->keytype, &len, &typbyval);
! 		
! 			if(nulls[Anum_pg_partition_minval-1] == 'n')
! 			{				
! 				Node 	*tmpNode = makeColumnRef("minvalue", NULL, -1);
! 
! 				/* Add this to new partition. */
! 				tmp->partitionCheck->min_value = lappend(tmp->partitionCheck->min_value, tmpNode);				
! 			}
! 			else
! 			{
! 				/* Get min attribute from catalog */
! 				part_attr = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_minval); 
! 
! 				/* Create const. */		
! 				tmp_const = makeConst(pg_part->keytype,	/* Const type */
! 										-1,
! 										len,
! 										part_attr,
! 										false,
! 										typbyval);
! 
! 				/* Add this to new partition. */
! 				tmp->partitionCheck->min_value = lappend(tmp->partitionCheck->min_value, tmp_const);
! 			}
! 
! 			if(nulls[Anum_pg_partition_maxval-1] == 'n')
! 			{
! 				Node 	*tmpNode = makeColumnRef("maxvalue", NULL, -1);
! 
! 				/* Add this to new partition. */
! 				tmp->partitionCheck->max_value = lappend(tmp->partitionCheck->max_value, tmpNode);				
! 			}
! 			else
! 			{
! 				/* Get max attribute from catalog */
! 				part_attr = GetDatum(pg_partrel, pg_part->keytype, pg_parttup, Anum_pg_partition_maxval); 
! 
! 				/* Create const. */		
! 				tmp_const = makeConst(pg_part->keytype,	/* Const type */
! 										-1,
! 										len,
! 										part_attr,
! 										false,
! 										typbyval);
! 
! 				/* Add this to new partition. */
! 				tmp->partitionCheck->max_value = lappend(tmp->partitionCheck->max_value, tmp_const);
! 			}
! 		}
! 	}	
! 
! 	childOids[j++] = child;
! 	partition_attr->partitions = lappend(partition_attr->partitions, part);
! 
! 	ValidateRanges(partition_attr, RelationGetRelid(rel), childOids);
! 
!     systable_endscan(pg_partscan);
!     heap_close(pg_partrel, AccessShareLock);
! 
! 	minIndex = part->partitionCheck->min_value->head;
! 	maxIndex = part->partitionCheck->max_value->head;
! 
! 
! 	j = 0;
! 
! 	foreach(partColumn, partition_attr->colName)
! 	{
! 		rangeVal = OTHER;
  
! 		/* Get the name of partition key column. */
! 		partitionColumn = ((Alias *)lfirst(partColumn))->aliasname;
  
! 		isMinValue = IsMinValue((Node *)lfirst(minIndex));
! 		if(isMinValue == false)
! 	        min_datum = ((Const *)lfirst(minIndex))->constvalue;  
! 		else
! 			rangeVal = MINVALRANGE;
  
! 		isMaxValue = IsMaxValue((Node *)lfirst(maxIndex));
! 		if(isMaxValue == false)
!         	max_datum = ((Const *)lfirst(maxIndex))->constvalue;  
! 		else
! 			rangeVal = MAXVALRANGE;
  
+         /* Get the attribute type. */
+         typ_oid = get_atttype(RelationGetRelid(rel), get_attnum(RelationGetRelid(rel), partitionColumn) );
  
! 		/* Get the attribute length*/
! 		get_typlenbyval(typ_oid, &len, &typbyval);
  
! 		WriteRangePartitionToCatalog(min_datum, 
! 										max_datum,
! 										len,
! 										typbyval,
! 										RelationGetRelid(rel),
! 										child,
! 										get_attnum(RelationGetRelid(rel), partitionColumn),
! 										typ_oid,
! 										++j,
! 										rangeVal);
  
!        	minIndex = minIndex->next;
!         maxIndex = maxIndex->next;
  	}
! 
! 	if(flag == true)
  	{
! 	    resetStringInfo(createTrigger);
!     	appendStringInfo(createTrigger, "CREATE TRIGGER partition_update_%u BEFORE UPDATE ON %s ", child,  part->partName->relname);
! 	    appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_update_trigger ();");
! 
!     	/* Parse the above SQL string and use this parsetree to create trigger on parent table. */
! 	    query_list  = pg_parse_query(createTrigger->data);
!     	parsetree = (Node *)lfirst(list_head(query_list));
! 	    CreateTrigger((CreateTrigStmt * )parsetree, 0, false);
! 
! 		/* To avoid tuple being updated by the current transaction, after the current scan started */
! 		CommandCounterIncrement();
  	}
+ 
+ 	/* If there are any rows in overflow partition which can satisfy partition constraints 
+ 	of latest partition, then move them out of overflow.*/
+ 	MoveValidRowsFromOverflow(GetOverflowPartition(rel), child);
+ 
+ 	return constraint->data;
  }
  
+ 
  static void
  ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
  				ColumnDef *colDef, bool isOid)
***************
*** 4165,4170 ****
--- 8150,8159 ----
  	List	   *children;
  	ObjectAddress object;
  
+ 	/* Check if the column is part of any partition key. */
+ 	if( GetPartitionsCountAtt(RelationGetRelid(rel), get_attnum(RelationGetRelid(rel), colName)) > 0)
+ 		elog(ERROR, "Can not drop column '%s' as this is part of partition key of '%s' table.", colName, RelationGetRelationName(rel));
+ 
  	/* At top level, permission check was done in ATPrepCmd, else do it */
  	if (recursing)
  		ATSimplePermissions(rel, false);
***************
*** 5694,5699 ****
--- 9683,9692 ----
  	SysScanDesc scan;
  	HeapTuple	depTup;
  
+ 	/* Check if the column is part of any partition key. */
+ 	if( GetPartitionsCountAtt(RelationGetRelid(rel), get_attnum(RelationGetRelid(rel), colName)) > 0)
+ 		elog(ERROR, "Can not alter column '%s' as this is part of partition key of '%s' table.", colName, RelationGetRelationName(rel));
+ 
  	attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
  
  	/* Look up the target column */
***************
*** 7951,7954 ****
--- 11944,12780 ----
  			cur_item = lnext(prev_item);
  		}
  	}
+ }
+ 
+ 
+ /* 
+  * ------------------------------------------------------------------------------
+  *	DefinePartitions
+  *	Create new partitions. They end up inheriting from the parent
+  *	relation.
+  *	Once they have been created, triggers need to be assigned to the parent to
+  *	provide the UPDATEs/INSERTs/DELETEs to percolate down to the children
+  * 	Callers expect this function to end with CommandCounterIncrement if it
+  * 	makes any changes.
+  * ------------------------------------------------------------------------------
+  */
+ void
+ DefinePartitions(CreateStmt *stmt, Oid parentRelId)
+ {
+ 	RangeVar 		inr;
+ 	Oid 			childOid;
+ 	PartitionAttrs	*partAttr;
+ 	int 			*partKeyOrder;
+ 	List			*partColumnList;
+ 	ListCell		*partColumn;
+ 	int 			count, i, j;
+ 	List			*columnList;
+ 	ListCell		*column;
+ 	StringInfo  	childTableName = makeStringInfo();
+ 	Oid				*partitionRelOids;
+ 	bool			partitionColumnMatch;
+ 	Relation    	rel;
+ 	StringInfo  	createTrigger = makeStringInfo();
+ 	List        	*query_list;
+ 	Node        	*parsetree;
+ 	StringInfo  	tableName = makeStringInfo();
+ 	Oid				result;
+ 	bool			isOverflowReq = false;
+ 
+ 	/* If no partitions are defined then return. */
+ 	if (stmt->partAttr == NULL) 
+ 		return;
+ 
+ 	isOverflowReq = ((PartitionAttrs *)stmt->partAttr)->hasOverflowPartition;
+ 	
+ 	partColumnList = ((PartitionAttrs *)(stmt->partAttr))->colName;
+ 
+ 	i = 0;
+ 	j = 0;
+ 	partitionColumnMatch = false;
+ 
+ 	Assert(IsA(stmt->partAttr, PartitionAttrs));
+ 
+ 	partAttr = (PartitionAttrs *)(stmt->partAttr);
+ 	/* To store the partition key order */
+ 	partKeyOrder = malloc(partColumnList->length * sizeof(int));
+ 	columnList 	= stmt->tableElts;
+ 
+ 	foreach(partColumn, partColumnList)
+ 	{
+ 		/* Get the name of partition key column. */
+ 		char *colName = ((Alias *)lfirst(partColumn))->aliasname;
+ 		count = 0;
+ 
+ 		foreach(column, columnList)
+ 		{
+ 			ColumnDef *tmp = lfirst(column);
+ 			count++;
+ 			if(strcmp(tmp->colname, colName) == 0)
+ 			{
+ 				partKeyOrder[j++] = count;
+ 				partitionColumnMatch = true;
+ 				break;
+ 			}
+ 		}
+ 		if(partitionColumnMatch == false)
+ 			elog(ERROR, "'%s' attribute is not present in given table.", colName);
+ 	}
+ 
+ 	/*
+ 	 * All the partitions will inherit from the parent, set the parent in the
+ 	 * inhRelations structure
+ 	 */
+ 	inr = *stmt->relation;
+ 
+ 	/* 
+ 	 * Create the children tables. The parser has already made sure that we
+ 	 * have atleast one partition in the list
+ 	 */
+ 	if (partAttr->partFunc == PART_LIST || partAttr->partFunc == PART_RANGE)
+ 	{
+ 		List 		*partitionList = partAttr->partitions;
+ 		ListCell 	*temp_part; 
+ 		int			isSystemGeneratedName = 0;
+ 		int 		isUserGeneratedName = 0;
+ 		int			i = 0;
+ 		Relation 	tmpRel;
+ 		bool		flag = false;
+ 		IndexStmt  *statement;
+ 
+ 
+ 		Assert(list_length(partitionList) > 0);
+ 
+ 		if(isOverflowReq == true)
+ 		{
+ 			StringInfo	query = makeStringInfo();
+ 		    /* Get overflow partition. */
+     		appendStringInfo(tableName, "of_%s_%u", stmt->relation->relname, parentRelId);
+ 	    	result = RelnameGetRelid(tableName->data);
+ 	
+ 	    	if(result == InvalidOid)
+ 		    {
+     		    CreateStmt  *childStmt = (CreateStmt *)copyObject((void *)stmt);
+ 	
+     	    	childStmt->inhRelations = lappend(NULL, stmt->relation);
+ 	    	    childStmt->relation->relname = tableName->data;
+ 				childStmt->tableElts = NIL;
+ 
+ 				result = DefineRelation(childStmt, RELKIND_RELATION);
+ 
+ 	    	    if(InvalidOid == result)
+     	    	    elog(ERROR, "Could not create overflow partition.");
+ 	    	}
+ 	    	else
+ 		    {
+     		    elog(ERROR, "Overflow partition '%s' for partitioned table '%s' already exists.",
+         		        tableName->data, stmt->relation->relname);
+ 		    }
+ 			tmpRel = RelationIdGetRelation(result);
+ 			appendStringInfo(query, "CREATE INDEX of_index_%u ON %s (", result, RelationGetRelationName(tmpRel));
+ 			RelationClose(tmpRel);
+ 
+ 			foreach(partColumn, partColumnList)
+ 			{
+ 				/* Get the name of partition key column. */
+ 				char *colName = ((Alias *)lfirst(partColumn))->aliasname;
+ 				
+ 				if(flag == true)
+ 					appendStringInfo(query, ", %s", colName);
+ 				else
+ 				{
+ 					appendStringInfo(query, "%s", colName);
+ 					flag = true;
+ 				}
+ 			}
+ 
+ 			appendStringInfo(query, ")");
+ 
+ 			query_list  = pg_parse_query(query->data);
+ 			parsetree = (Node *)lfirst(list_head(query_list));
+ 			statement = (IndexStmt *) parsetree;	
+ 
+ 			CheckRelationOwnership(statement->relation, true);
+ 
+ 			/* Run parse analysis ... */
+ 			statement = transformIndexStmt(statement, query->data);
+ 
+ 			/* ... and do it */
+ 			DefineIndex(statement->relation,     /* relation */
+ 						statement->idxname,      /* index name */
+ 						InvalidOid, /* no predefined OID */
+ 						statement->accessMethod, /* am name */
+ 						statement->tableSpace,
+ 						statement->indexParams,  /* parameters */
+ 						(Expr *)statement->whereClause,
+ 						statement->options,
+ 						statement->unique,
+ 						statement->primary,
+ 						statement->isconstraint,
+ 						false,      /* is_alter_table */
+ 						true,       /* check_rights */
+ 						false,      /* skip_build */
+ 						false,      /* quiet */
+ 						statement->concurrent);  /* concurrent */			
+ 	
+ 			/* To avoid tuple being updated by the current transaction, after the current scan started */
+ 			CommandCounterIncrement();
+ 		}
+ 
+ 		rel = RelationIdGetRelation(parentRelId);
+ 		resetStringInfo(createTrigger);
+ 		appendStringInfo(createTrigger, "CREATE TRIGGER partition_insert_%u BEFORE INSERT ON %s ", RelationGetRelid(rel), RelationGetRelationName(rel));
+ 		appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_insert_trigger();");
+ 		relation_close(rel, 0);
+ 
+ 		/* Parse the above SQL string and use this parsetree to create trigger on parent table. */
+ 		query_list  = pg_parse_query(createTrigger->data);
+ 		parsetree = (Node *)lfirst(list_head(query_list));
+ 		CreateTrigger((CreateTrigStmt * )parsetree, 0, false);
+ 
+ 		/* To avoid tuple being updated by the current transaction, after the current scan started */
+ 		CommandCounterIncrement();
+ 	
+ 		/* Allocate the storage for number of partitions.*/
+ 		partitionRelOids = malloc(sizeof(Oid)*list_length(partitionList));
+ 
+ 		foreach(temp_part, partitionList)
+ 		{
+ 			Partition *temp_partition = lfirst(temp_part);
+ 
+ 			/* If partition name is not specified then generate one and apply. */
+ 			if(temp_partition->partName == NULL)
+ 			{
+ 
+ 				if(isUserGeneratedName == 1)
+ 					elog(ERROR, "Combination of user generated and system generated table names is not allowed.");				
+ 
+ 				isSystemGeneratedName = 1;
+ 				i++;
+ 
+ 				appendStringInfo(childTableName, "%s_%d", stmt->relation->relname, i);
+ 
+ 				temp_partition->partName = makeNode(RangeVar);	
+ 				temp_partition->partName->relname = childTableName->data;
+ 			}
+ 			else
+ 			{
+ 	            if(isSystemGeneratedName == 0)
+ 				{
+ 					isUserGeneratedName = 1;
+ 				}
+ 				else
+ 					elog(ERROR, "Combination of user generated and system generated table names is not allowed.");				
+ 			}
+     		
+ 			childOid = CreateInheritedTable(parentRelId, temp_partition->partName->relname, temp_partition->tablespacename);
+ 
+ 		    rel = RelationIdGetRelation(childOid);
+ 		    resetStringInfo(createTrigger);
+ 		    appendStringInfo(createTrigger, "CREATE TRIGGER partition_update_%u BEFORE UPDATE ON %s ", RelationGetRelid(rel), RelationGetRelationName(rel));
+ 		    appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_update_trigger ();");
+ 		    relation_close(rel, 0);
+ 
+ 		    /* Parse the above SQL string and use this parsetree to create trigger on parent table. */
+ 		    query_list  = pg_parse_query(createTrigger->data);
+ 		    parsetree = (Node *)lfirst(list_head(query_list));
+ 		    CreateTrigger((CreateTrigStmt * )parsetree, 0, false);
+ 
+ 			/* To avoid tuple being updated by the current transaction, after the current scan started */
+ 			CommandCounterIncrement();
+ 		
+ 			/* Store the Child table Oids for later use. */
+ 			partitionRelOids[i++] = childOid;
+ 		}
+         /*
+        	 * Make the changes carried out so far, visible
+          */
+         CreatePartitions(stmt, parentRelId, partitionRelOids);
+         CommandCounterIncrement();
+ 
+ 		/* Free the storage. */
+ 		free(partitionRelOids);		
+ 
+ 	}
+ 	else if(partAttr->partFunc == PART_HASH)
+ 	{
+ 
+ 		bool 		typbyval;
+ 	    Datum 		values[Natts_pg_partition];
+ 	    bool  		nulls [Natts_pg_partition];
+ 		int16		len, k;
+ 		Oid 		typ_oid;
+ 		Relation        r;
+ 		TupleDesc       tupDesc;
+ 		HeapTuple       tup;
+ 
+ 
+ 		if(partAttr->numberOfPartitions < 1)
+ 		{
+ 			elog(ERROR, "Atleast one partition is required to create partitioned-table.");
+ 		}
+ 
+ 		i = 0;
+ 		j = 0;
+ 			
+ 		/* Allocate the storage for number of partitions.*/
+ 		partitionRelOids = malloc(sizeof(Oid) * partAttr->numberOfPartitions);
+ 
+ 		for(i=0; i<partAttr->numberOfPartitions; i++)
+ 		{
+ 			/* Device the name of child table. */
+ 			resetStringInfo(childTableName);
+ 			appendStringInfo(childTableName, "%s_%d", stmt->relation->relname, i);
+ 
+ 			/* Use this name to create child table. */
+ 			childOid = CreateInheritedTable(parentRelId, childTableName->data, NULL);
+ 	
+ 			/* Apply the update trigger. */	
+ 			rel = RelationIdGetRelation(childOid);
+ 			resetStringInfo(createTrigger);
+ 			appendStringInfo(createTrigger, "CREATE TRIGGER partition_update_%u BEFORE UPDATE ON %s ",RelationGetRelid(rel), RelationGetRelationName(rel));
+ 			appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_update_trigger();");
+ 	
+ 	    	/* Parse the above SQL string and use this parsetree to create trigger on parent table. */
+ 	    	query_list  = pg_parse_query(createTrigger->data);
+ 		    parsetree = (Node *)lfirst(list_head(query_list));
+     		CreateTrigger((CreateTrigStmt * )parsetree, 0, false);
+ 
+ 			/* To avoid tuple being updated by the current transaction, after the current scan started */
+ 			CommandCounterIncrement();
+ 
+             /* We can not create constraints for hash partitions directly. Instead, we will monitor inserts using insert triggers.*/
+             resetStringInfo(createTrigger);
+             appendStringInfo(createTrigger, "CREATE TRIGGER partition_constraints_%u BEFORE INSERT ON %s ",RelationGetRelid(rel), RelationGetRelationName(rel));
+             appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_constraints_hash();");
+             relation_close(rel, 0);
+ 
+             /* Parse the above SQL string and use this parsetree to create trigger on parent table. */
+             query_list  = pg_parse_query(createTrigger->data);
+             parsetree = (Node *)lfirst(list_head(query_list));
+             CreateTrigger((CreateTrigStmt * )parsetree, 0, false);
+ 
+ 			k = 1;
+ 
+ 			foreach(partColumn, partColumnList)
+ 			{
+ 				/* Get the name of partition key column. */
+ 				char *colName = ((Alias *)lfirst(partColumn))->aliasname;
+ 
+ 				/* Get the attribute type. */
+ 				typ_oid = get_atttype(parentRelId, get_attnum(parentRelId, colName));
+ 			
+ 				/* Get the attribute length*/
+ 				get_typlenbyval(typ_oid, &len, &typbyval);
+ 
+ 				/* initialize nulls and values */
+ 			    for (j = 0; j < Natts_pg_partition; j++)
+ 				{
+ 					nulls[j] = false;
+ 					values[j] = (Datum) NULL;
+ 				}				
+ 
+ 			    values[Anum_pg_partition_minval     -1] = Int8GetDatum(NULL);
+ 				nulls[Anum_pg_partition_minval     -1] = true;
+ 		    	values[Anum_pg_partition_maxval     -1] = Int8GetDatum(NULL);
+ 				nulls[Anum_pg_partition_maxval     -1] = true;
+ 			    values[Anum_pg_partition_parentrelid -1]= ObjectIdGetDatum(parentRelId);
+ 			    values[Anum_pg_partition_partrelid  -1] = ObjectIdGetDatum(childOid);
+ 		    	values[Anum_pg_partition_parttype   -1] = Int8GetDatum(PART_HASH);
+ 			    values[Anum_pg_partition_partkey    -1] = ObjectIdGetDatum(get_attnum(parentRelId, colName));
+ 			    values[Anum_pg_partition_listval    -1] = Int8GetDatum(NULL);
+ 			    nulls[Anum_pg_partition_listval     -1] = true;
+ 		    	values[Anum_pg_partition_hashval    -1] = Int8GetDatum(i);
+ 			    values[Anum_pg_partition_keytype    -1] = ObjectIdGetDatum(typ_oid);
+ 				values[Anum_pg_partition_keyorder   -1] = Int8GetDatum(k);
+ 
+ 				k++;
+ 
+ 			    r = heap_open(PartitionRelationId, RowExclusiveLock);
+ 			    tupDesc = r->rd_att;
+ 	
+ 			    tup = heap_form_tuple(tupDesc, values, nulls);
+ 			    simple_heap_insert(r, tup);
+ 				CatalogUpdateIndexes(r, tup); 
+ 
+ 			    heap_close(r, RowExclusiveLock);
+ 			}
+ 		}
+ 
+ 		rel = RelationIdGetRelation(parentRelId);
+ 		resetStringInfo(createTrigger);
+ 		appendStringInfo(createTrigger, "CREATE TRIGGER partition_insert_%u BEFORE INSERT ON %s ", RelationGetRelid(rel), RelationGetRelationName(rel));
+ 		appendStringInfo(createTrigger, " FOR EACH ROW EXECUTE PROCEDURE partition_insert_trigger_hash();");
+ 		relation_close(rel, 0);
+ 	
+ 	    /* Parse the above SQL string and use this parsetree to create trigger on parent table. */
+     	query_list  = pg_parse_query(createTrigger->data);
+ 	    parsetree = (Node *)lfirst(list_head(query_list));
+     	CreateTrigger((CreateTrigStmt * )parsetree, 0, false);
+ 
+         /*
+          * Make the changes carried out so far, visible
+          */
+         CreatePartitions(stmt, parentRelId, partitionRelOids);
+         CommandCounterIncrement();
+ 		
+ 		/* Free the storage. */
+ 		free(partitionRelOids);		
+ 	}
+ 	else
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ 				 errmsg("Invalid PARTITION type specified")));
+ }
+ 
+ /*
+  * ------------------------------------------------------------------------------
+  * ValidateRanges : Check for the intersecting ranges of specified partitions.
+  * 
+  * ------------------------------------------------------------------------------
+  */
+ int ValidateRanges(PartitionAttrs *partAttr, Oid parentRelOid, Oid *partitionRelOids)
+ {
+ 	List			*partitionList;
+ 	List			*partitionColumnList;
+ 	ListCell		*p1;
+ 	ListCell		*p2;
+ 	Partition		*partition1, *partition2;
+ 	ListCell		*partitionColumn;
+ 	ListCell		*p1MinIndex, *p1MaxIndex, *p2MinIndex, *p2MaxIndex;
+ 	Datum			p1MinDatum, p1MaxDatum, p2MinDatum;
+ 	int				i, j, k;
+ 	Oid				typ_oid;
+ 	RegProcedure	procLessThan, procGreaterThan;
+ 	Oid				LessThanOid, GreaterThanOid;
+ 	bool			isDef;
+ 	bool			isP1MinValue, isP1MaxValue, isP2MinValue;
+ 	bool 			tmp1, tmp2;
+ 
+ 	i = 0;
+ 
+ 	/* Get the partition List. */
+ 	partitionList = partAttr->partitions;
+ 
+ 	/* Get the partition-key column list*/
+ 	partitionColumnList = partAttr->colName;
+ 
+ 	foreach(partitionColumn, partitionColumnList)
+ 	{		
+ 		char *colName = ((Alias *)lfirst(partitionColumn))->aliasname;
+ 		/* Get the column type. */
+ 		typ_oid = get_atttype(parentRelOid, get_attnum(parentRelOid, colName));
+ 
+ 		foreach(p1, partitionList)
+ 		{
+ 			partition1 = lfirst(p1);
+ 			j = 0;			
+ 			p1MinIndex = partition1->partitionCheck->min_value->head;
+ 			p1MaxIndex = partition1->partitionCheck->max_value->head;
+ 
+ 			while(j < i)
+ 			{
+     	        p1MinIndex = p1MinIndex->next;
+    	    	    p1MaxIndex = p1MaxIndex->next;
+ 				j++;
+ 			}
+ 
+ 			isP1MinValue = IsMinValue((Node *)lfirst(p1MinIndex));
+ 
+ 			if(isP1MinValue == false)
+ 			{	
+ 	   	        /* If it's a FuncExpr then execute the conversion function. */
+     	   	    if IsA((Node *)lfirst(p1MinIndex), FuncExpr)
+         	   	{
+             	   	p1MinDatum = OidFunctionCall1(((FuncExpr *)lfirst(p1MinIndex))->funcid,
+                 	   	            ((Const *)((FuncExpr *)lfirst(p1MinIndex))->args->head->data.ptr_value)->constvalue);
+ 	            }
+    		        else
+        		    {
+            		    p1MinDatum = ((Const *)lfirst(p1MinIndex))->constvalue;
+             	}
+ 			}
+ 
+ 			isP1MaxValue = IsMaxValue((Node *)lfirst(p1MaxIndex));
+ 
+ 			if(isP1MaxValue == false)
+ 			{
+ 
+ 	           /* If it's a FuncExpr then execute the conversion function. */
+    		        if IsA((Node *)lfirst(p1MaxIndex), FuncExpr)
+        		    {
+             	   	p1MaxDatum = OidFunctionCall1(((FuncExpr *)lfirst(p1MaxIndex))->funcid,
+            	    	                ((Const *)((FuncExpr *)lfirst(p1MaxIndex))->args->head->data.ptr_value)->constvalue);
+ 	       	    }
+    		        else
+         	    {
+            		    p1MaxDatum = ((Const *)lfirst(p1MaxIndex))->constvalue;
+ 				}
+        	    }
+ 
+ 			foreach(p2, partitionList)
+ 			{
+ 				if(p1 != p2)
+ 				{
+ 					partition2 = lfirst(p2);
+ 					k = 0;
+ 	                p2MinIndex = partition2->partitionCheck->min_value->head;
+         	        p2MaxIndex = partition2->partitionCheck->max_value->head;
+ 
+ 					while(k < i)
+ 					{
+                 	    p2MinIndex = p2MinIndex->next;
+             	        p2MaxIndex = p2MaxIndex->next;
+ 						k++;
+ 					}
+ 		
+ 					isP2MinValue = IsMinValue((Node *)lfirst(p2MinIndex));
+ 
+ 					if(isP2MinValue == false)
+ 					{
+ 			            /* If it's a FuncExpr then execute the conversion function. */
+ 		            	if IsA((Node *)lfirst(p2MinIndex), FuncExpr)
+     		    	    {
+         			        p2MinDatum = OidFunctionCall1(((FuncExpr *)lfirst(p2MinIndex))->funcid,
+     	        		                    ((Const *)((FuncExpr *)lfirst(p2MinIndex))->args->head->data.ptr_value)->constvalue);
+ 		            	}
+ 	    	        	else
+     	    		    {
+         		    	    p2MinDatum = ((Const *)lfirst(p2MinIndex))->constvalue;
+ 		    	        }
+ 					}
+ 
+ 	                tmp1 = true;
+     	            tmp2 = true;
+ 
+ 					if((isP1MinValue == false) && (isP2MinValue == false))
+ 					{
+ 			            LessThanOid = OperatorGet("<=", PG_CATALOG_NAMESPACE , typ_oid, typ_oid, &isDef);		
+ 
+ 		        	    if(isDef == FALSE)
+     			            elog(ERROR, "'<=' operator is not defined for type '%d'.", typ_oid);
+ 
+ 						procLessThan = get_opcode(LessThanOid);
+ 						tmp1 = DatumGetBool(OidFunctionCall2(procLessThan, p1MinDatum, p2MinDatum));
+ 					}
+ 					else if(isP1MinValue == true && isP2MinValue == false )
+ 					{
+ 						tmp1 = true;
+ 					}
+ 					else if(isP2MinValue == true && isP1MinValue == false)
+ 					{
+ 						tmp1 = false;
+ 					}
+ 
+ 
+ 					if((isP1MaxValue == false) && (isP2MinValue == false))	            	
+ 					{
+ 						GreaterThanOid = OperatorGet(">", PG_CATALOG_NAMESPACE , typ_oid, typ_oid, &isDef);
+ 	        	    
+ 						if(isDef == FALSE)
+     			            elog(ERROR, "'>' operator is not defined for type '%d'.", typ_oid);
+ 
+     	    	    	procGreaterThan = get_opcode(GreaterThanOid);
+ 						tmp2 = DatumGetBool(OidFunctionCall2(procGreaterThan, p1MaxDatum, p2MinDatum));
+ 					}
+ 					else if(isP1MaxValue == true)
+ 					{
+ 						tmp2 = true;
+ 					}
+ 					else if(isP2MinValue == true && isP1MinValue == false)
+ 					{
+ 						tmp2 = false;
+ 					}
+ 
+ 	    	        if(tmp1 == true && tmp2 == true )
+ 	            	{
+ 							elog(ERROR, "Partition ranges of '%s' and '%s' are overlapping for '%s' attribute.", 
+ 									partition1->partName->relname, partition2->partName->relname, colName);
+ 					}
+ 				}
+ 			}
+ 		}
+ 		i++;
+ 	}
+ 	return 0;
+ }
+ 
+ void 
+ AddLessThanCheckConstraint(Oid typ_oid, Datum max_datum, char *tableName, char *partitionColumn)
+ {
+ 	char		*expr_string;
+ 	Oid			typoutput;
+ 	bool		isVariableLength;
+ 	StringInfo	constraint = makeStringInfo();
+ 	List		*query_list;
+ 	Node		*parsetree;
+ 
+ 	getTypeOutputInfo(typ_oid, &typoutput, &isVariableLength);
+ 	expr_string = DatumGetCString(OidFunctionCall1(typoutput, max_datum));
+ 
+ 	/* Form the check constraint for child table. */
+ 	appendStringInfo(constraint, "ALTER TABLE %s ADD CHECK ( %s < '%s'); ",
+ 		tableName,
+ 		partitionColumn,
+ 		expr_string);
+ 
+ 	/* Parse the above SQL string and use this parsetree to create check constraint on child tables. */
+ 	query_list  = pg_parse_query(constraint->data);
+ 	parsetree = (Node *)lfirst(list_head(query_list));
+ 	AlterTable(( AlterTableStmt * )parsetree);
+ }
+ 
+ void 
+ AddGreaterThanCheckConstraint(Oid typ_oid, Datum min_datum, char *tableName, char *partitionColumn)
+ {
+ 	char		*expr_string;
+ 	Oid			typoutput;
+ 	bool		isVariableLength;
+ 	StringInfo	constraint = makeStringInfo();
+ 	List		*query_list;
+ 	Node		*parsetree;
+ 
+ 	getTypeOutputInfo(typ_oid, &typoutput, &isVariableLength);
+ 	expr_string = DatumGetCString(OidFunctionCall1(typoutput, min_datum));
+ 
+ 	/* Form the check constraint for child table. */
+ 	appendStringInfo(constraint, "ALTER TABLE %s ADD CHECK ( %s > '%s'); ",
+ 		tableName,
+ 		partitionColumn,
+ 		expr_string);
+ 
+ 	/* Parse the above SQL string and use this parsetree to create check constraint on child tables. */
+ 	query_list  = pg_parse_query(constraint->data);
+ 	parsetree = (Node *)lfirst(list_head(query_list));
+ 	AlterTable(( AlterTableStmt * )parsetree);
+ }
+ 
+ 
+ /*
+  * ------------------------------------------------------------------------------
+  * CreatePartitions : Add constraints on child tables as per ranges specified.
+  * Add the metadata to partition catalog table.
+  * ------------------------------------------------------------------------------
+  */
+ 
+ static void 
+ CreatePartitions(CreateStmt *stmt, Oid parentRelOid, Oid *partitionRelOids)
+ {
+ 	int				counter, numberOfPartitions;
+ 	PartitionAttrs	*partAttr;
+ 	char            *partitionColumn; 
+ 	StringInfo		func_insert = makeStringInfo();
+ 	StringInfo		func_update = makeStringInfo();
+     Partition   	*temp_partition;
+ 	List            *partitionList;
+ 	ListCell        *temp_part;
+ 	int 			partitionColumnType;
+ 	List			*partColumnList;
+ 	ListCell		*partColumn;
+ 	int 			count, i, j, l;
+ 	List			*columnList;
+ 	ListCell		*column;
+ 	int 			*partKeyOrder;
+ 	int				partitionNumber;
+ 	int				rangeVal;
+ 
+ 	partAttr = (PartitionAttrs *)(stmt->partAttr);
+ 
+     if(partAttr->partFunc == PART_HASH)
+     {
+         return ;
+     }
+ 
+     /* Reset the buffers used.  */
+     resetStringInfo(func_insert);
+     resetStringInfo(func_update);
+ 
+ 	/* Reset */
+ 	counter 			= 0;
+ 	numberOfPartitions 	= 0;
+ 	i					= 0;
+ 	j					= 0;
+ 	l					= 0;
+ 	partitionNumber		= 0;
+ 	
+ 	partitionList = partAttr->partitions;
+ 	numberOfPartitions = list_length(partitionList);
+ 	Assert(numberOfPartitions);
+ 
+ 	/* Get the list of partition key columns. */
+ 	partColumnList = partAttr->colName;
+ 
+ 	partKeyOrder = malloc(partColumnList->length * sizeof(int));
+ 
+ 	columnList 	= stmt->tableElts;
+ 
+ 	foreach(partColumn, partColumnList)
+ 	{
+ 		/* Get the name of partition key column. */
+ 		char 	*colName = ((Alias *)lfirst(partColumn))->aliasname;
+ 		bool 	found = false;
+ 		count = 0;
+ 
+ 		foreach(column, columnList)
+ 		{
+ 			ColumnDef *tmp = lfirst(column);
+ 			count++;
+ 			if(strcmp(tmp->colname, colName) == 0)
+ 			{
+ 				partKeyOrder[j++] = count;
+ 				found = true;
+ 				break;
+ 			}
+ 		}
+ 
+ 		if(found == false)
+ 			elog(ERROR, "'%s' attribute is not present in given table.", colName);
+ 
+ 	}
+ 
+ 	foreach(temp_part, partitionList)
+ 	{
+ 		ListCell 	*minIndex, *maxIndex;
+ 
+ 		temp_partition = lfirst(temp_part);
+ 
+ 		if ( partAttr->partFunc == PART_RANGE )
+ 		{
+ 			minIndex = temp_partition->partitionCheck->min_value->head;
+ 			maxIndex = temp_partition->partitionCheck->max_value->head;
+ 		}
+ 
+ 		partitionNumber++;
+ 
+ 		j = 0;
+ 	
+ 		foreach(partColumn, partColumnList)
+ 		{
+ 
+ 			/* Get the name of partition key column. */
+ 			char *colName = ((Alias *)lfirst(partColumn))->aliasname;
+ 			partitionColumn = colName;
+ 	
+ 			/* Type of partition key column */
+     		partitionColumnType = get_atttype(parentRelOid, get_attnum(parentRelOid, partitionColumn)); 
+ 
+ 	        if ( partAttr->partFunc == PART_LIST )
+ 			{
+ 				elog(ERROR, "List partitions are not yet supported.");
+ 			}
+ 			else
+ 			{		
+ 				Datum 			min_datum, max_datum;
+ 				Oid 			typ_oid;
+ 				bool 			typbyval;
+ 				int16			len;
+ 			
+ 				/* Get the attribute type. */
+ 				typ_oid = get_atttype(parentRelOid, get_attnum(parentRelOid, partitionColumn));
+ 	
+ 				IsValidRange(minIndex, maxIndex, parentRelOid, partitionColumn, temp_partition->partName->relname);	
+ 
+ 				if(IsA(lfirst(minIndex), ColumnRef))
+ 				{
+ 					ColumnRef	*colRef = lfirst(minIndex);		
+ 		
+ 					if(list_length(colRef->fields) == 1)
+ 					{
+ 						if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "minvalue") == 0)
+ 						{
+ 							rangeVal = MINVALRANGE;
+ 							AddLessThanCheckConstraint(typ_oid, 
+ 								((Const *)lfirst(maxIndex))->constvalue, 
+ 								 temp_partition->partName->relname, 
+ 								partitionColumn);	
+ 						}
+ 						else
+ 						{
+ 							elog(ERROR, "Not a valid value.");
+ 						}
+ 					}
+ 				} 
+ 				else if(IsA(lfirst(maxIndex), ColumnRef))
+ 				{
+ 					ColumnRef	*colRef = lfirst(maxIndex);		
+ 		
+ 					if(list_length(colRef->fields) == 1)
+ 					{
+ 						if(strcmp(((Alias *)linitial(colRef->fields))->aliasname, "maxvalue") == 0)
+ 						{
+ 							rangeVal = MAXVALRANGE;
+ 							AddGreaterThanCheckConstraint(typ_oid, 
+ 								((Const *)lfirst(minIndex))->constvalue, 
+ 								 temp_partition->partName->relname, 
+ 								partitionColumn);	
+ 						}
+ 						else
+ 						{
+ 							elog(ERROR, "Not a valid value.");
+ 						}
+ 					}
+ 				}
+ 				else
+ 				{
+ 					rangeVal = OTHER;
+ 					AddCheckConstraint(typ_oid, 
+ 						((Const *)lfirst(minIndex))->constvalue, 
+ 						((Const *)lfirst(maxIndex))->constvalue, 
+ 						 temp_partition->partName->relname, 
+ 						partitionColumn);	
+ 				}
+ 
+ 				/* Get the attribute length*/
+ 				get_typlenbyval(typ_oid, &len, &typbyval);
+ 
+ 				min_datum = ((Const *)lfirst(minIndex))->constvalue;
+ 				max_datum = ((Const *)lfirst(maxIndex))->constvalue;
+ 
+ 				minIndex = minIndex->next;
+ 				maxIndex = maxIndex->next;
+ 
+ 		        WriteRangePartitionToCatalog(min_datum,
+     		                                    max_datum,
+         		                                len,
+             		                            typbyval,
+                 		                        parentRelOid,
+                     		                    partitionRelOids[l],
+                         		                get_attnum(parentRelOid, partitionColumn),
+                             		            typ_oid,
+                                 		        ++j,
+ 												rangeVal);
+ 
+ 			}	
+ 		}
+ 		l = l + 1;
+ 	}
+ 	if ( partAttr->partFunc == PART_RANGE )
+ 		ValidateRanges(partAttr,parentRelOid, partitionRelOids);
+ 	return;
+ }
+ 
+ /*
+  * Pass either "*OLD*" or "*NEW*" as appropriate depending on the trigger to
+  * to be generated
+  */
+ static void 
+ MutateColumnRefs(Node *node, char *reference) 
+ {
+ 	if IsA(node, A_Expr) 
+ 	{
+ 		MutateColumnRefs( ((A_Expr *) node)->lexpr, reference );
+ 		MutateColumnRefs( ((A_Expr *) node)->rexpr, reference);
+ 	} 
+ 	else if IsA(node, ColumnRef) 
+ 	{
+ 		ColumnRef *col_ref = (ColumnRef *) node;
+ 
+ 		/* Should have at max one column in the column list */
+ 		Assert(1 == list_length(col_ref->fields));
+ 		
+ 		col_ref->fields = list_make2(makeString(reference),
+ 								lfirst(list_head(col_ref->fields)));
+ 
+ 	}
+ 	return;
  }
Index: src/backend/commands/trigger.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/commands/trigger.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/commands/trigger.c	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/commands/trigger.c	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 1690,1696 ****
--- 1690,1701 ----
  	HeapTuple	newtuple = trigtuple;
  	HeapTuple	oldtuple;
  	TriggerData LocTriggerData;
+ 	TriggerData backupLocTriggerData;
+ 	int			backuptgindx;
  	int			i;
+ 	bool		isPartitionTrigger;
+ 
+ 	isPartitionTrigger = false;
  
  	LocTriggerData.type = T_TriggerData;
  	LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
***************
*** 1718,1723 ****
--- 1723,1739 ----
  		LocTriggerData.tg_trigtuple = oldtuple = newtuple;
  		LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
  		LocTriggerData.tg_trigger = trigger;
+ 		/* If partition trigger then execute later. */
+ 		if((0 == strncmp(trigger->tgname, "partition_insert_", 17)) || (0 == strncmp(trigger->tgname, "partition_constraints_", 22)))
+ 		{
+ 			if(ntrigs > 1)
+ 			{
+ 				backupLocTriggerData = LocTriggerData;
+ 				backuptgindx =  tgindx[i];
+ 				isPartitionTrigger = true;
+ 				continue;
+ 			}
+ 		}
  		newtuple = ExecCallTriggerFunc(&LocTriggerData,
  									   tgindx[i],
  									   relinfo->ri_TrigFunctions,
***************
*** 1727,1733 ****
--- 1743,1764 ----
  			heap_freetuple(oldtuple);
  		if (newtuple == NULL)
  			break;
+ 		/* Break free from the loop is found dummy-tuple. */
+ 		if (newtuple->t_len == -1)
+ 			break;
  	}
+ 
+ 	if(isPartitionTrigger == true)
+ 	{
+ 		newtuple = ExecCallTriggerFunc(&backupLocTriggerData,
+ 									   backuptgindx,
+ 									   relinfo->ri_TrigFunctions,
+ 									   relinfo->ri_TrigInstrument,
+ 									   GetPerTupleMemoryContext(estate));
+ 		if (oldtuple != newtuple && oldtuple != trigtuple)
+ 			heap_freetuple(oldtuple);
+ 	}
+ 
  	return newtuple;
  }
  
***************
*** 1972,1977 ****
--- 2003,2013 ----
  	HeapTuple	intuple = newtuple;
  	TupleTableSlot *newSlot;
  	int			i;
+ 	TriggerData backupLocTriggerData;
+ 	int			backuptgindx;
+ 	bool		isPartitionTrigger;
+ 
+ 	isPartitionTrigger = false;
  
  	trigtuple = GetTupleForTrigger(estate, relinfo, tupleid, &newSlot);
  	if (trigtuple == NULL)
***************
*** 2010,2015 ****
--- 2046,2062 ----
  		LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
  		LocTriggerData.tg_newtuplebuf = InvalidBuffer;
  		LocTriggerData.tg_trigger = trigger;
+ 		/* If partition trigger then execute later. */
+ 		if(0 == strncmp(trigger->tgname, "partition_update_", 17))
+ 		{
+ 			if(ntrigs > 1)
+ 			{
+ 				backupLocTriggerData = LocTriggerData;
+ 				backuptgindx =  tgindx[i];
+ 				isPartitionTrigger = true;
+ 				continue;
+ 			}
+ 		}
  		newtuple = ExecCallTriggerFunc(&LocTriggerData,
  									   tgindx[i],
  									   relinfo->ri_TrigFunctions,
***************
*** 2019,2025 ****
--- 2066,2090 ----
  			heap_freetuple(oldtuple);
  		if (newtuple == NULL)
  			break;
+ 		/* Break free from the loop if found dummy-tuple. */
+ 		if (newtuple->t_len == -1)
+ 			break;
+ 	}
+ 
+ 	if(isPartitionTrigger == true)
+ 	{
+ 		backupLocTriggerData.tg_trigtuple = trigtuple;
+ 		backupLocTriggerData.tg_newtuple = oldtuple = newtuple;
+ 
+ 		newtuple = ExecCallTriggerFunc(&backupLocTriggerData,
+ 									   backuptgindx,
+ 									   relinfo->ri_TrigFunctions,
+ 									   relinfo->ri_TrigInstrument,
+ 									   GetPerTupleMemoryContext(estate));
+ 		if (oldtuple != newtuple && oldtuple != trigtuple)
+ 			heap_freetuple(oldtuple);
  	}
+ 
  	heap_freetuple(trigtuple);
  	return newtuple;
  }
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/commands/vacuum.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/commands/vacuum.c	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/commands/vacuum.c	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 254,259 ****
--- 254,260 ----
  static int	vac_cmp_vtlinks(const void *left, const void *right);
  static bool enough_space(VacPage vacpage, Size len);
  static Size PageGetFreeSpaceWithFillFactor(Relation relation, Page page);
+ List* GetPartitions(Oid parentOid);
  
  
  /****************************************************************************
***************
*** 540,545 ****
--- 541,550 ----
  	if (OidIsValid(relid))
  	{
  		oldcontext = MemoryContextSwitchTo(vac_context);
+ 
+ 		/* Get partitions if any. */
+ 		oid_list = GetPartitions(relid);
+ 
  		oid_list = lappend_oid(oid_list, relid);
  		MemoryContextSwitchTo(oldcontext);
  	}
***************
*** 549,554 ****
--- 554,562 ----
  		Oid			relid;
  
  		relid = RangeVarGetRelid(vacrel, false);
+ 
+ 		/* Get partitions if any. */
+ 		oid_list = GetPartitions(relid);
  
  		/* Make a relation list entry for this guy */
  		oldcontext = MemoryContextSwitchTo(vac_context);
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/executor/execMain.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/executor/execMain.c	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/executor/execMain.c	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 294,299 ****
--- 294,301 ----
  	 * startup tuple receiver, if we will be emitting tuples
  	 */
  	estate->es_processed = 0;
+ 	estate->es_partition_overflow_tuples = 0;
+ 
  	estate->es_lastoid = InvalidOid;
  
  	sendTuples = (operation == CMD_SELECT ||
***************
*** 1792,1797 ****
--- 1794,1817 ----
  		if (newtuple == NULL)	/* "do nothing" */
  			return;
  
+ 		/* Check for dummy tuple */
+ 		if(newtuple->t_len == -1)
+ 		{
+ 			/* Increase the count of processed rows. */
+ 			(estate->es_processed)++;
+ 			return;
+ 		}
+ 
+ 		/* Check for overflow partition tuple */
+ 		if(newtuple->t_len == -2)
+ 		{
+ 			/* Increase the count of processed rows. */
+ 			(estate->es_processed)++;
+ 			/* Increase the count of overflow partition tuples. */
+ 			(estate->es_partition_overflow_tuples)++;
+ 			return;
+ 		}
+ 
  		if (newtuple != tuple)	/* modified by Trigger(s) */
  		{
  			/*
***************
*** 2029,2034 ****
--- 2049,2074 ----
  
  		if (newtuple == NULL)	/* "do nothing" */
  			return;
+ 
+ 		/* Check for dummy tuple */
+ 		if(newtuple->t_len == -1)
+ 		{
+ 			/* Increase the count of processed rows. */
+ 			(estate->es_processed)++;
+ 			heap_freetuple(newtuple);
+ 			return;
+ 		}
+ 
+ 		/* Check for overflow partition tuple */
+ 		if(newtuple->t_len == -2)
+ 		{
+ 			/* Increase the count of processed rows. */
+ 			(estate->es_processed)++;
+ 			/* Increase the count of overflow partition tuples. */
+ 			(estate->es_partition_overflow_tuples)++;
+ 			heap_freetuple(newtuple);
+ 			return;
+ 		}
  
  		if (newtuple != tuple)	/* modified by Trigger(s) */
  		{
Index: src/backend/executor/execUtils.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/executor/execUtils.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/backend/executor/execUtils.c	19 May 2009 06:59:32 -0000	1.1.1.2
--- src/backend/executor/execUtils.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 200,205 ****
--- 200,207 ----
  	estate->es_tupleTable = NULL;
  
  	estate->es_processed = 0;
+ 	estate->es_partition_overflow_tuples = 0;	
+ 
  	estate->es_lastoid = InvalidOid;
  	estate->es_rowMarks = NIL;
  
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/nodes/copyfuncs.c	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/nodes/copyfuncs.c	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 1566,1571 ****
--- 1566,1657 ----
  	return newnode;
  }
  
+ /*
+  * _copyPartitionAttrs
+  */
+ static PartitionAttrs *
+ _copyPartitionAttrs(PartitionAttrs *from)
+ {
+ 	PartitionAttrs *newnode = makeNode(PartitionAttrs);
+ 
+ 	COPY_SCALAR_FIELD(numberOfPartitions);
+ 	COPY_NODE_FIELD(partitions);
+ 	COPY_SCALAR_FIELD(partFunc);
+ 	COPY_NODE_FIELD(colName);
+ 	COPY_SCALAR_FIELD(hasOverflowPartition);
+ 
+ 	return newnode;
+ }
+ 
+ /*
+  * _copyPartition
+  */
+ static Partition *
+ _copyPartition(Partition *from)
+ {
+ 	Partition *newnode = makeNode(Partition);
+ 
+ 	COPY_NODE_FIELD(partName);
+ 	COPY_NODE_FIELD(partitionCheck);
+ 	COPY_STRING_FIELD(tablespacename);
+ 
+ 	return newnode;
+ }
+ 
+ /*
+  * _copyPartition
+  */
+ static UpdatePartitionStmt *
+ _copyUpdatePartitionStmt(UpdatePartitionStmt *from)
+ {
+ 	UpdatePartitionStmt *newnode = makeNode(UpdatePartitionStmt);
+ 
+ 	COPY_NODE_FIELD(prev);
+ 	COPY_NODE_FIELD(after);
+ 
+ 	return newnode;
+ }
+ 
+ static SplitPartitionStmt * 
+ _copySplitPartitionStmt(SplitPartitionStmt *from)
+ {
+ 	SplitPartitionStmt *newnode = makeNode(SplitPartitionStmt);
+ 
+ 	COPY_NODE_FIELD(partNames);
+ 	COPY_NODE_FIELD(splitValues);
+ 
+ 	return newnode;
+ }
+ 
+ static ExchangePartitionStmt * 
+ _copyExchangePartitionStmt(ExchangePartitionStmt *from)
+ {
+ 	ExchangePartitionStmt *newnode = makeNode(ExchangePartitionStmt);
+ 
+ 	COPY_NODE_FIELD(partNames);
+ 
+ 	return newnode;
+ }
+ 
+ static RenamePartitionStmt * 
+ _copyRenamePartitionStmt(RenamePartitionStmt *from)
+ {
+ 	RenamePartitionStmt *newnode = makeNode(RenamePartitionStmt);
+ 
+ 	COPY_NODE_FIELD(partNames);
+ 
+ 	return newnode;
+ }
+ 
+ static MergePartitionStmt * 
+ _copyMergePartitionStmt(MergePartitionStmt *from)
+ {
+ 	MergePartitionStmt *newnode = makeNode(MergePartitionStmt);
+ 
+ 	COPY_NODE_FIELD(partNames);
+ 
+ 	return newnode;
+ }
  /* ****************************************************************
   *						relation.h copy functions
   *
***************
*** 2091,2096 ****
--- 2177,2185 ----
  	COPY_NODE_FIELD(keys);
  	COPY_NODE_FIELD(options);
  	COPY_STRING_FIELD(indexspace);
+ 	COPY_NODE_FIELD(min_value);
+ 	COPY_NODE_FIELD(max_value);
+ 	COPY_NODE_FIELD(partition_list_values);
  
  	return newnode;
  }
***************
*** 2414,2419 ****
--- 2503,2509 ----
  	COPY_NODE_FIELD(options);
  	COPY_SCALAR_FIELD(oncommit);
  	COPY_STRING_FIELD(tablespacename);
+ 	COPY_NODE_FIELD(partAttr);
  
  	return newnode;
  }
***************
*** 3670,3676 ****
  		case T_FromExpr:
  			retval = _copyFromExpr(from);
  			break;
! 
  			/*
  			 * RELATION NODES
  			 */
--- 3760,3786 ----
  		case T_FromExpr:
  			retval = _copyFromExpr(from);
  			break;
! 		case T_PartitionAttrs:
! 			retval = _copyPartitionAttrs(from);
! 			break;
! 		case T_Partition:
! 			retval = _copyPartition(from);
! 			break;
! 		case T_UpdatePartitionStmt:
! 			retval = _copyUpdatePartitionStmt(from);
! 			break;
! 		case T_SplitPartitionStmt:
! 			retval = _copySplitPartitionStmt(from);
! 			break;
! 		case T_MergePartitionStmt:
! 			retval = _copyMergePartitionStmt(from);
! 			break;
! 		case T_ExchangePartitionStmt:
! 			retval = _copyExchangePartitionStmt(from);
! 			break;
! 		case T_RenamePartitionStmt:
! 			retval = _copyRenamePartitionStmt(from);
! 			break;
  			/*
  			 * RELATION NODES
  			 */
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/nodes/equalfuncs.c	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/nodes/equalfuncs.c	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 721,726 ****
--- 721,747 ----
  	return true;
  }
  
+ static bool 
+ _equalPartitionAttrs(PartitionAttrs *a, PartitionAttrs *b)
+ {
+ 	COMPARE_SCALAR_FIELD(numberOfPartitions);
+ 	COMPARE_NODE_FIELD(partitions);
+ 	COMPARE_SCALAR_FIELD(partFunc);
+ 	COMPARE_NODE_FIELD(colName);
+ 	COMPARE_SCALAR_FIELD(hasOverflowPartition);
+ 
+ 	return true;
+ }
+ 
+ static bool 
+ _equalPartition(Partition *a, Partition *b)
+ {
+ 	COMPARE_NODE_FIELD(partName);
+ 	COMPARE_NODE_FIELD(partitionCheck);
+ 
+ 	return true;
+ }
+ 
  
  /*
   * Stuff from relation.h
***************
*** 1078,1083 ****
--- 1099,1105 ----
  	COMPARE_NODE_FIELD(options);
  	COMPARE_SCALAR_FIELD(oncommit);
  	COMPARE_STRING_FIELD(tablespacename);
+ 	COMPARE_NODE_FIELD(partAttr);
  
  	return true;
  }
***************
*** 2460,2465 ****
--- 2482,2493 ----
  			break;
  		case T_JoinExpr:
  			retval = _equalJoinExpr(a, b);
+ 			break;
+ 		case T_PartitionAttrs:
+ 			retval = _equalPartitionAttrs(a, b);
+ 			break;
+ 		case T_Partition:
+ 			retval = _equalPartition(a, b);
  			break;
  
  			/*
Index: src/backend/optimizer/plan/planner.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/optimizer/plan/planner.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/backend/optimizer/plan/planner.c	19 May 2009 06:59:32 -0000	1.1.1.2
--- src/backend/optimizer/plan/planner.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 41,46 ****
--- 41,52 ----
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
  
+ #include "catalog/pg_partition.h"
+ #include "utils/fmgroids.h"
+ #include "catalog/indexing.h"
+ #include "utils/tqual.h"
+ #include "catalog/pg_namespace.h"
+ #include "access/hash.h"
  
  /* GUC parameter */
  double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION;
***************
*** 96,101 ****
--- 102,440 ----
  									   int *ordNumCols,
  									   AttrNumber **ordColIdx,
  									   Oid **ordOperators);
+ Oid OperatorGet(const char *operatorName,
+             Oid operatorNamespace,
+             Oid leftObjectId,
+             Oid rightObjectId,
+             bool *defined);
+ extern Oid get_relevant_partition(HeapTuple tuple, Relation rel);
+ extern Oid get_relevant_hash_partition(HeapTuple tuple, Relation rel);
+ extern Oid TypenameGetTypid	(const char *typname);
+ extern Node* coerce_to_specific_type(ParseState *pstate,
+ 		Node *  	  node,
+ 		Oid  	  targetTypeId,
+ 		const char *  	  constructName
+ 	)  ;	
+ extern Oid RelnameGetRelid(	const char *relname); 
+ 
+ /*
+  * Evaluate the constraints and fine relevent table to operate on.
+  */
+ Oid
+ get_relevant_hash_partition(HeapTuple tuple, Relation rel) {
+     ScanKeyData skey;
+     SysScanDesc pg_partscan;
+     HeapTuple   pg_parttup;
+     Relation    pg_partrel;
+ 	bool		flag;
+ 	StringInfo	str_to_hash = makeStringInfo();
+ 
+    /* Lists to identify partition id to which the row should belong.
+      * irr_part_list - list of oids of irrelevent partitions.
+      * rel_part_list - list may contain irrelevent partition along
+      *                  with relevent partition
+      */
+     List        	*distinct_part_key_list=NULL;
+     List        	*rel_part_list= NULL;
+ 	int				hash_partition_entries = 0;
+ 	unsigned int	hashValue;
+ 
+ 	flag = false;
+ 	resetStringInfo(str_to_hash);	
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(rel)));
+ 
+     pg_partrel = heap_open(PartitionRelationId, RowExclusiveLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+ 		bool			isnull, typbyval;
+ 		int16 			len;
+ 		bool			isVariableLength;
+ 		Oid				typoutput;
+ 		Datum 			attr;
+ 
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		if(pg_part->parttype == PART_HASH)
+ 		{		
+ 			/* Increase the no. of hash partition entries count. */
+ 			hash_partition_entries++;
+ 
+ 			if (!list_member_int(distinct_part_key_list, pg_part->partkey))
+ 			{
+ 				distinct_part_key_list = lappend_int(distinct_part_key_list, pg_part->partkey);
+ 
+ 		        /* Get attribute from tuple */
+ 		        attr      = heap_getattr(tuple, pg_part->partkey, rel->rd_att, &isnull);
+ 
+         		/* Get len and typbyval from pg_type */
+ 	        	get_typlenbyval(pg_part->keytype, &len, &typbyval);
+ 
+ 				/* Read the list value */
+ 				getTypeOutputInfo(pg_part->keytype, &typoutput, &isVariableLength);
+ 				appendStringInfo(str_to_hash, DatumGetCString(OidFunctionCall1(typoutput, attr)));
+ 			}
+ 		}
+ 	}
+ 
+ 	hashValue = DatumGetUInt32(hash_any((unsigned char *)str_to_hash->data, strlen(str_to_hash->data))) % 
+ 				(int)(hash_partition_entries / distinct_part_key_list->length);
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, RowExclusiveLock);
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(rel)));
+ 
+     pg_partrel = heap_open(PartitionRelationId, RowExclusiveLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+         bool            isnull;
+ 
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+         if(pg_part->parttype == PART_HASH)
+         {
+ 	        /* Get min attribute from catalog */
+     	    Datum datumDashValue = heap_getattr (pg_parttup,Anum_pg_partition_hashval, 
+                                         pg_partrel->rd_att, &isnull);
+ 
+ 			if(datumDashValue == hashValue)
+ 			{
+ 				if (!list_member_oid(rel_part_list, pg_part->partrelid))		
+ 				{
+ 					rel_part_list = lappend_oid(rel_part_list, pg_part->partrelid);
+ 
+ 					if(list_length(rel_part_list) > 1)
+ 						elog(ERROR, "Found more than one matching partitions.");
+ 				}
+ 			}
+ 		}
+ 	}
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, RowExclusiveLock);
+ 
+ 	return (Oid)rel_part_list->head->data.oid_value;
+ }
+ 
+ #if 0
+ /*
+  * get CString of Datum.
+  */
+ static char*
+ DisplayDatum(Datum datum, Oid type)
+ {
+     Oid     typeOut;
+     bool    isVariableLength;
+ 
+     getTypeOutputInfo(type, &typeOut, &isVariableLength);
+     return (DatumGetCString(OidFunctionCall1(typeOut, datum)));
+ }
+ #endif
+ 
+ /* Function to get partiton id for a tuple inserted on master relation.
+  * Uses pg_partition catalog lookup to verify boundry condition.
+  * Each entry in catalog corresponds to constraint on single column.
+  */
+ 
+ Oid
+ get_relevant_partition(HeapTuple tuple, Relation rel) {
+     ScanKeyData skey;
+     SysScanDesc pg_partscan;
+     HeapTuple   pg_parttup;
+     Relation    pg_partrel;
+ 
+    /* Lists to identify partition id to which the row should belong.
+      * irr_part_list - list of oids of irrelevent partitions.
+      * rel_part_list - list may contain irrelevent partition along
+      *                  with relevent partition
+      */
+     List        *irr_part_list=NULL;
+     List        *rel_part_list= NULL;
+     ListCell    *part_oid;
+ 	Oid 		result = 0 ;
+ 	bool		isSingleAttrPartition;
+ 	int			partitionCount;
+ 	Datum 		values[Natts_pg_partition];
+ 	char  		nulls [Natts_pg_partition];	
+     bool    	isnull, isdef, gte_min, lt_max, typbyval;
+     int16   	len;
+     Datum   	short_datum;
+     Oid     	typoutput;
+     bool    	isVariableLength;
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(rel)));
+ 
+     pg_partrel = heap_open(PartitionRelationId, RowExclusiveLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+ 	isSingleAttrPartition = true;
+ 	partitionCount = 0;
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+ 		Datum attr;
+ 		RegProcedure oper_proc, oper_proc2;
+ 		Oid min_oper, max_oper;
+ 		Datum part_attr;
+ 
+ 
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		heap_deformtuple(pg_parttup, pg_partrel->rd_att, values, nulls);
+ 
+ 		if(pg_part->keyorder > 1)
+ 		{
+ 			isSingleAttrPartition = false;
+ 		}
+ 
+ 		/* Increase the partition count */
+ 		if(pg_part->keyorder == 1)
+ 			partitionCount++;
+ 
+ 		/* Get attribute from tuple */
+ 		attr      = heap_getattr(tuple, pg_part->partkey, rel->rd_att,&isnull);
+ 
+ 		getTypeOutputInfo(pg_part->keytype, &typoutput, &isVariableLength);
+ 
+ 		/* Get len and typbyval from pg_type */
+ 		get_typlenbyval(pg_part->keytype, &len, &typbyval);
+ 
+ 		if(nulls[Anum_pg_partition_minval-1] == 'n')
+ 		{
+ 			gte_min = true;
+ 		}
+ 		else
+ 		{
+ 			/* Get min attribute from catalog */
+ 			part_attr = heap_getattr (pg_parttup,Anum_pg_partition_minval,
+ 											pg_partrel->rd_att,&isnull);
+ 
+ 			/* Three cases a. datatypes with typbyval true and fix length.
+ 			 * b. datatypes with byval false and fix length.
+ 			 * c. extendible datatypes where length -1.
+ 			 */
+ 			if ( typbyval )
+ 			{
+ 				short_datum = 0;
+ 				memcpy(&short_datum, VARDATA_ANY(part_attr), len);
+ 				part_attr = short_datum;
+ 			}
+ 			else if (len != -1)
+ 			{
+ 				part_attr = (Datum)VARDATA_ANY(part_attr);
+ 			}	
+ 
+ 			/* Evaluate whether tuple value satisfies partition key cnstraint */
+ 			min_oper = OperatorGet(">=", PG_CATALOG_NAMESPACE , pg_part->keytype,
+ 											pg_part->keytype, &isdef);
+ 			oper_proc = get_opcode(min_oper);
+ 			gte_min = DatumGetBool(OidFunctionCall2(oper_proc, attr, part_attr));
+ 		}
+ 
+ 		if(nulls[Anum_pg_partition_maxval-1] == 'n')
+ 		{
+ 			lt_max = true;
+ 		}
+ 		else
+ 		{
+ 			/* Similar steps for max attribute of catalog */
+ 			part_attr = heap_getattr (pg_parttup,Anum_pg_partition_maxval,
+ 											pg_partrel->rd_att,&isnull);
+ 			if ( typbyval )
+ 			{
+ 				short_datum = 0;
+ 				memcpy(&short_datum, VARDATA_ANY(part_attr), len);
+ 				part_attr = short_datum;
+ 			}
+ 			else if (len != -1 )
+ 			{
+ 				part_attr = (Datum)VARDATA_ANY(part_attr);
+ 			}
+ 
+ 			max_oper = OperatorGet("<", PG_CATALOG_NAMESPACE , pg_part->keytype,
+ 									pg_part->keytype, &isdef);
+ 			oper_proc2 = get_opcode(max_oper);
+ 			lt_max = DatumGetBool(OidFunctionCall2(oper_proc2,attr,part_attr));
+ 		}
+ 
+ 		/* Create relevent and  irrelevent partition lists */
+ 		if ( gte_min & lt_max )
+ 		{
+ 			if((isSingleAttrPartition == true) && (partitionCount > 1))
+ 			{
+ 				systable_endscan(pg_partscan);
+ 				heap_close(pg_partrel, RowExclusiveLock);	
+ 				return pg_part->partrelid;			
+ 			}
+ 
+ 			if ( !list_member_oid(irr_part_list, pg_part->partrelid) )
+ 				rel_part_list = lappend_oid(rel_part_list, pg_part->partrelid);
+ 		}
+ 		else
+ 		{
+ 			if(!((isSingleAttrPartition == true) && (partitionCount > 1)))
+ 			{
+ 				irr_part_list = lappend_oid(irr_part_list, (pg_part->partrelid));
+ 			}
+ 		}
+     }
+ 
+     /* Scan through lists to get partition oid to which the tuple is to be inserted */
+ 	if(rel_part_list == NULL)
+ 	{
+ 		StringInfo 	tableName = makeStringInfo();
+ 	    /* Get overflow partition. */
+ 	    appendStringInfo(tableName, "of_%s_%u", RelationGetRelationName(rel), RelationGetRelid(rel));
+ 	    result = RelnameGetRelid(tableName->data);
+ 	}
+ 	else
+ 	{
+    		foreach(part_oid, rel_part_list)
+ 	    {
+     	    if ( list_member_oid(irr_part_list, part_oid->data.oid_value) )
+ 			{
+ 				StringInfo 	tableName = makeStringInfo();
+ 			    /* Get overflow partition. */
+ 			    appendStringInfo(tableName, "of_%s_%u", RelationGetRelationName(rel), RelationGetRelid(rel));
+ 			    result = RelnameGetRelid(tableName->data);
+ 			}
+ 			else
+ 			{
+ 				result = (Oid)part_oid->data.oid_value;
+ 			}
+ 	    }
+ 	}
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, RowExclusiveLock);
+ 
+ 	return result;
+ }
+ 
  
  
  /*****************************************************************************
Index: src/backend/optimizer/util/plancat.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/optimizer/util/plancat.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/backend/optimizer/util/plancat.c	19 May 2009 06:59:32 -0000	1.1.1.2
--- src/backend/optimizer/util/plancat.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 37,42 ****
--- 37,47 ----
  #include "utils/lsyscache.h"
  #include "utils/rel.h"
  #include "utils/snapmgr.h"
+ #include "catalog/pg_inherits.h"
+ #include "catalog/pg_inherits_fn.h"
+ #include "utils/fmgroids.h"
+ #include "utils/tqual.h"
+ #include "utils/syscache.h"
  
  
  /* GUC parameter */
***************
*** 50,55 ****
--- 55,61 ----
  						 Oid relationObjectId, RelOptInfo *rel,
  						 bool include_notnull);
  
+ Oid find_inheritance_parent(Oid inhrelid);
  
  /*
   * get_relation_info -
***************
*** 845,850 ****
--- 851,886 ----
  
  	return (Selectivity) result;
  }
+ 
+ /* Return parent oid for child table.
+  * Useful to find out parent in case of cross partition updates.
+  */
+ 
+ Oid
+ find_inheritance_parent(Oid inhrelid)
+ {
+     Relation    relation;
+     HeapScanDesc scan;
+     HeapTuple   inheritsTuple;
+     Oid         inhparent;
+     ScanKeyData key[1];
+ 
+ 
+     ScanKeyInit(&key[0],
+                 Anum_pg_inherits_inhrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(inhrelid));
+     relation = heap_open(InheritsRelationId, AccessShareLock);
+     scan = heap_beginscan(relation, SnapshotNow, 1, key);
+     while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+     {
+         inhparent = ((Form_pg_inherits)GETSTRUCT(inheritsTuple))->inhparent;
+     }
+     heap_endscan(scan);
+     heap_close(relation, AccessShareLock);
+     return inhparent;
+ }
+ 
  
  /*
   * has_unique_index
Index: src/backend/parser/gram.y
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/parser/gram.y,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/parser/gram.y	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/parser/gram.y	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 108,114 ****
   */
  /*#define __YYSCLASS*/
  
! static Node *makeColumnRef(char *colname, List *indirection, int location);
  static Node *makeTypeCast(Node *arg, TypeName *typename, int location);
  static Node *makeStringConst(char *str, int location);
  static Node *makeStringConstCast(char *str, int location, TypeName *typename);
--- 108,114 ----
   */
  /*#define __YYSCLASS*/
  
! Node *makeColumnRef(char *colname, List *indirection, int location);
  static Node *makeTypeCast(Node *arg, TypeName *typename, int location);
  static Node *makeStringConst(char *str, int location);
  static Node *makeStringConstCast(char *str, int location, TypeName *typename);
***************
*** 178,183 ****
--- 178,185 ----
  
  	InsertStmt			*istmt;
  	VariableSetStmt		*vsetstmt;
+ 
+ 	PartitionFunction partFunc;
  }
  
  %type <node>	stmt schema_stmt
***************
*** 417,422 ****
--- 419,429 ----
  %type <ival>	opt_frame_clause frame_extent frame_bound
  
  
+ %type <list>	ListPartitionList RangePartitions ListPartitions PartitionColumns
+ %type <node> 	PartitioningData OptPartition ListPartition RangePartition
+ %type <range>	OptPartitionName
+ 
+ 
  /*
   * If you make any token changes, update the keyword table in
   * src/include/parser/kwlist.h and add new keywords to the appropriate one of
***************
*** 445,451 ****
  	DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
  	DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
  
! 	EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT
  	EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
  
  	FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
--- 452,458 ----
  	DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
  	DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
  
! 	EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT EXCHANGE 
  	EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
  
  	FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
***************
*** 465,474 ****
  	KEY
  
  	LANCOMPILER LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
! 	LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
  	LOCATION LOCK_P LOGIN_P
  
! 	MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
  
  	NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
  	NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
--- 472,481 ----
  	KEY
  
  	LANCOMPILER LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
! 	LEAST LEFT LEVEL LIKE LIST1 LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
  	LOCATION LOCK_P LOGIN_P
  
! 	MAPPING MATCH MAXVALUE MERGE MINUTE_P MINVALUE MODE MONTH_P MOVE
  
  	NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
  	NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
***************
*** 477,483 ****
  	OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR
  	ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
  
! 	PARSER PARTIAL PARTITION PASSWORD PLACING PLANS POSITION
  	PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
  	PRIOR PRIVILEGES PROCEDURAL PROCEDURE
  
--- 484,490 ----
  	OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR
  	ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
  
! 	PARSER PARTIAL PARTITION PARTITIONS PASSWORD PLACING PLANS POSITION
  	PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
  	PRIOR PRIVILEGES PROCEDURAL PROCEDURE
  
***************
*** 489,495 ****
  
  	SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE
  	SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SHARE
! 	SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT
  	STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
  	SYMMETRIC SYSID SYSTEM_P
  
--- 496,502 ----
  
  	SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE
  	SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SHARE
! 	SHOW SIMILAR SIMPLE SMALLINT SOME SPLIT STABLE STANDALONE_P START STATEMENT
  	STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
  	SYMMETRIC SYSID SYSTEM_P
  
***************
*** 1542,1549 ****
  		;
  
  alter_table_cmd:
  			/* ALTER TABLE <name> ADD [COLUMN] <coldef> */
! 			ADD_P opt_column columnDef
  				{
  					AlterTableCmd *n = makeNode(AlterTableCmd);
  					n->subtype = AT_AddColumn;
--- 1549,1565 ----
  		;
  
  alter_table_cmd:
+ 			/* ALTER TABLE <name> ADD PARTITION BY RANGE (col, ...) (<name> START val,.... END val,....) */
+ 			ADD_P RANGE PARTITION RangePartition
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_AddPartition;
+ 					n->def = $4;
+ 					$$ = (Node *)n;
+ 				}		
+ 
  			/* ALTER TABLE <name> ADD [COLUMN] <coldef> */
! 			| ADD_P opt_column columnDef
  				{
  					AlterTableCmd *n = makeNode(AlterTableCmd);
  					n->subtype = AT_AddColumn;
***************
*** 1593,1598 ****
--- 1609,1691 ----
  					n->def = (Node *) makeString($6);
  					$$ = (Node *)n;
  				}
+ 			| RENAME PARTITION qualified_name TO qualified_name
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					RenamePartitionStmt *s = makeNode(RenamePartitionStmt);
+                     s->partNames = lappend(s->partNames, $3);
+                     s->partNames = lappend(s->partNames, $5);					
+ 					n->subtype = AT_RenamePartition;
+ 					n->def = (Node *)s;
+ 					$$ = (Node *)n;
+ 				}
+ 			| DROP PARTITION qualified_name 
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+                     Partition *partition = makeNode(Partition);
+ 
+ 					n->subtype = AT_DropPartitionByName;
+                     partition->partName = $3;
+                     partition->partitionCheck = NULL;
+ 
+ 					n->def = (Node *)partition;
+ 					$$ = (Node *)n;
+ 				}
+ 			| DROP PARTITION RangePartition
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_DropPartitionByRange;
+ 					n->def = $3;
+ 					$$ = (Node *)n;
+ 				}
+ 			| EXCHANGE qualified_name WITH TABLE qualified_name
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					ExchangePartitionStmt *s = makeNode(ExchangePartitionStmt);
+                     s->partNames = lappend(s->partNames, $2);
+                     s->partNames = lappend(s->partNames, $5);					
+ 					n->subtype = AT_ExchangePartition;
+ 					n->def = (Node *)s;
+ 					$$ = (Node *)n;
+ 				}
+ 			| UPDATE PARTITION RangePartition
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_UpdatePartition;
+ 					n->def = $3;
+ 					$$ = (Node *)n;
+ 				}
+ 			| UPDATE PARTITIONS TO ICONST 
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_UpdateHashPartition;
+ 					n->def = makeIntConst($4, -1);
+ 					$$ = (Node *)n;
+ 				}
+ 			| SPLIT PARTITION qualified_name AT VALUES '(' ListPartitionList ')' INTO qualified_name AND qualified_name
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					SplitPartitionStmt *s = makeNode(SplitPartitionStmt);
+ 					s->partNames = lappend(s->partNames, $3);
+ 					s->partNames = lappend(s->partNames, $10);
+ 					s->partNames = lappend(s->partNames, $12);
+ 					s->splitValues = $7;
+ 					n->subtype = AT_SplitPartition;
+ 					n->def = (Node *)s;
+ 					$$ = (Node *)n;
+ 				}
+ 			| MERGE PARTITIONS qualified_name AND qualified_name INTO qualified_name
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					MergePartitionStmt *s = makeNode(MergePartitionStmt);
+ 					s->partNames = lappend(s->partNames, $3);
+ 					s->partNames = lappend(s->partNames, $5);
+ 					s->partNames = lappend(s->partNames, $7);
+ 					n->subtype = AT_MergePartition; 
+ 					n->def = (Node *)s;
+ 					$$ = (Node *)n;
+ 				}
+ 
  			/* ALTER TABLE <name> DROP [COLUMN] <colname> [RESTRICT|CASCADE] */
  			| DROP opt_column ColId opt_drop_behavior
  				{
***************
*** 2035,2042 ****
   *
   *****************************************************************************/
  
! CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
! 			OptInherit OptWith OnCommitOption OptTableSpace
  				{
  					CreateStmt *n = makeNode(CreateStmt);
  					$4->istemp = $2;
--- 2128,2135 ----
   *
   *****************************************************************************/
  
! CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
! 			   OptInherit OptWith OnCommitOption OptTableSpace OptPartition 
  				{
  					CreateStmt *n = makeNode(CreateStmt);
  					$4->istemp = $2;
***************
*** 2047,2056 ****
  					n->options = $9;
  					n->oncommit = $10;
  					n->tablespacename = $11;
  					$$ = (Node *)n;
  				}
  		| CREATE OptTemp TABLE qualified_name OF qualified_name
! 			'(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace
  				{
  					/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
  					 * by our inheritance capabilities. Let's try it...
--- 2140,2150 ----
  					n->options = $9;
  					n->oncommit = $10;
  					n->tablespacename = $11;
+                     n->partAttr = $12;
  					$$ = (Node *)n;
  				}
  		| CREATE OptTemp TABLE qualified_name OF qualified_name
! 			'(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace OptPartition
  				{
  					/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
  					 * by our inheritance capabilities. Let's try it...
***************
*** 2064,2073 ****
--- 2158,2304 ----
  					n->options = $10;
  					n->oncommit = $11;
  					n->tablespacename = $12;
+                     n->partAttr =  $13;
  					$$ = (Node *)n;
  				}
  		;
  
+ OptPartition: PARTITION BY PartitioningData { $$ = $3; }  
+ 		| {$$ = NULL;}
+     	;
+ 
+ PartitionColumns: ColId 				{$$ = list_make1(makeString($1));}
+ 		| PartitionColumns ',' ColId 	{$$ = lappend($1, makeString($3));}
+ 		;
+ 
+ PartitioningData: LIST1  '(' PartitionColumns ')'  '(' ListPartitions  ')'
+ 				{
+ 					PartitionAttrs *partData = makeNode(PartitionAttrs);
+ 					partData->partFunc = PART_LIST;
+ 					partData->numberOfPartitions = 0;
+ 					partData->colName = $3;
+ 					partData->partitions = $6;
+ 					$$ = (Node *)partData;
+ 				}
+ 			
+ 		| RANGE '(' PartitionColumns ')' '(' RangePartitions ')'
+ 				{
+ 					ListCell	*partition;
+ 					bool		isOverflow = false;
+                     PartitionAttrs *partData = makeNode(PartitionAttrs);
+ 					List	*partitions = NULL;
+ 
+ 					foreach(partition, $6)
+ 					{
+ 				        if(IsA(lfirst(partition), Alias))
+ 				        {
+ 				            if(strcmp(((Alias *)lfirst(partition))->aliasname, "default") == 0)
+ 				            {
+ 								if(isOverflow == false)
+ 								{
+ 									isOverflow = true;
+ 									partData->hasOverflowPartition = true;
+ 								}
+ 								else
+ 									elog(ERROR, "There can not be more than one default partitions.");
+ 				            }
+ 				        }
+ 						else if(IsA(lfirst(partition), Partition))
+ 						{
+ 							partitions = lappend(partitions, lfirst(partition));
+ 						}
+ 					}
+ 
+                     partData->partFunc = PART_RANGE;
+                     partData->numberOfPartitions = list_length(partitions);
+                     partData->colName = $3;
+                     partData->partitions = partitions;
+                     $$ = (Node *)partData;					
+ 				}	
+ 
+ 
+ 		| ColId '(' PartitionColumns ')'  PARTITIONS ICONST 
+ 				{
+ 					PartitionAttrs *partData = makeNode(PartitionAttrs);
+ 					if(strcasecmp($1, "hash") != 0)
+ 						elog(ERROR, "Not a valid partition type.");
+ 					partData->partFunc = PART_HASH;
+ 					partData->numberOfPartitions = $6;
+ 					partData->colName = $3;
+ 					partData->partitions =  NULL;
+ 					$$ = (Node *)partData;
+ 				}
+ 		;
+ 
+ ListPartitions: ListPartition 			{ $$ = list_make1($1);}
+ 	| ListPartitions ',' ListPartition 	{ $$ = lappend($1, $3);}
+ 	;
+ 
+ RangePartitions :  RangePartition { $$ = list_make1($1); }
+         | RangePartitions ',' RangePartition { $$ = lappend($1, $3); }
+ 		| RangePartitions ',' DEFAULT	{$$ = lappend($1, makeAlias("default", NULL));}
+         ;
+ 
+ ListPartitionList: a_expr 			{ $$ = list_make1($1);}
+ 	| ListPartitionList ',' a_expr 	{ $$ = lappend($1, $3);}
+ 	;
+ 
+ 
+ OptPartitionName: /* Empty  */ {$$ = NULL;}		
+ 	| qualified_name
+ 	;
+ 
+ ListPartition :	OptPartitionName '(' ListPartitionList ')'   OptTableSpace
+ 				{
+ 
+ 					Partition *partition = makeNode(Partition);
+ 					Constraint *constraint = NULL;
+ 					
+ 					partition->partName = $1;
+ 
+ 					/* Make the constraint node */
+ 					constraint = makeNode(Constraint);
+ 	
+ 					constraint->contype = PART_LIST;
+ 					constraint->name = NULL;
+ 					constraint->raw_expr = (Node *)$3; 
+ 					constraint->cooked_expr = NULL;
+ 					constraint->keys = NULL;
+ 					constraint->indexspace = NULL;
+ 					constraint->partition_list_values = $3;
+ 
+ 					partition->partitionCheck = constraint;
+ 					partition->tablespacename = $5;
+ 					$$ = (Node *)partition;
+ 				}
+     	;
+ 
+ RangePartition : OptPartitionName '(' START ListPartitionList END_P ListPartitionList ')' OptTableSpace
+ 				{
+ 
+ 						Partition *partition = makeNode(Partition);
+ 						Constraint *constraint = NULL;
+ 
+ 						partition->partName = $1;
+ 
+ 						/* Make the constraint node */
+ 						constraint = makeNode(Constraint);
+ 						constraint->contype = PART_RANGE;
+ 						constraint->min_value = $4;
+ 						constraint->max_value = $6;
+ 						constraint->name = NULL;
+ 			
+ 						/* constraint->raw_expr = $3; */
+ 
+ 						constraint->cooked_expr = NULL;
+ 						constraint->keys = NULL;
+ 						constraint->indexspace = NULL;
+ 
+ 						partition->partitionCheck = constraint;
+ 						partition->tablespacename = $8;
+ 						$$ = (Node *)partition;
+ 				}
+         ;
  /*
   * Redundancy here is needed to avoid shift/reduce conflicts,
   * since TEMP is not a reserved word.  See also OptTempTableName.
***************
*** 10276,10282 ****
  			| OWNER
  			| PARSER
  			| PARTIAL
- 			| PARTITION
  			| PASSWORD
  			| PLANS
  			| PRECEDING
--- 10507,10512 ----
***************
*** 10288,10294 ****
  			| PROCEDURAL
  			| PROCEDURE
  			| QUOTE
- 			| RANGE
  			| READ
  			| REASSIGN
  			| RECHECK
--- 10518,10523 ----
***************
*** 10323,10328 ****
--- 10552,10558 ----
  			| SHARE
  			| SHOW
  			| SIMPLE
+ 			| SPLIT
  			| STABLE
  			| STANDALONE_P
  			| START
***************
*** 10579,10585 ****
  
  %%
  
! static Node *
  makeColumnRef(char *colname, List *indirection, int location)
  {
  	/*
--- 10809,10815 ----
  
  %%
  
! Node *
  makeColumnRef(char *colname, List *indirection, int location)
  {
  	/*
Index: src/backend/parser/parse_utilcmd.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/parser/parse_utilcmd.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/backend/parser/parse_utilcmd.c	19 May 2009 06:59:32 -0000	1.1.1.2
--- src/backend/parser/parse_utilcmd.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 75,80 ****
--- 75,81 ----
  	List	   *alist;			/* "after list" of things to do after creating
  								 * the table */
  	IndexStmt  *pkey;			/* PRIMARY KEY index, if any */
+ 	PartitionAttrs *partAttr; 	/* partitioning related info */
  } CreateStmtContext;
  
  /* State shared by transformCreateSchemaStmt and its subroutines */
***************
*** 114,119 ****
--- 115,121 ----
  static void transformConstraintAttrs(List *constraintList);
  static void transformColumnType(ParseState *pstate, ColumnDef *column);
  static void setSchemaName(char *context_schema, char **stmt_schema_name);
+ static void transformPartitionData(ParseState *pstate, CreateStmtContext *cxt);
  
  
  /*
***************
*** 177,182 ****
--- 179,185 ----
  	cxt.alist = NIL;
  	cxt.pkey = NULL;
  	cxt.hasoids = interpretOidsOption(stmt->options);
+ 	cxt.partAttr = (PartitionAttrs *)stmt->partAttr;
  
  	/*
  	 * Run through each primary element in the table creation clause. Separate
***************
*** 235,240 ****
--- 238,248 ----
  	transformFKConstraints(pstate, &cxt, true, false);
  
  	/*
+ 	 * Postprocess partition related information
+ 	 */
+ 	transformPartitionData(pstate, &cxt);
+ 
+ 	/*
  	 * Output results.
  	 */
  	stmt->tableElts = cxt.columns;
***************
*** 954,959 ****
--- 962,1062 ----
  
  	ReleaseSysCache(ht_opc);
  	return result;
+ }
+ 
+ /*
+  * transformPartitionData:
+  * If partitioning is specified, carry out checks on the supplied create stmt
+  */
+ static void
+ transformPartitionData(ParseState *pstate, CreateStmtContext *cxt)
+ {
+ 	PartitionAttrs 	*partAttr = (PartitionAttrs *)cxt->partAttr;
+ 	ListCell 		*lc, *temp_part; 
+ 	List *partitionList, *partindexlist = NIL;
+ 
+ 	if (partAttr == NULL)
+ 		return;
+ 
+ 	partitionList = partAttr->partitions;
+ 	/* Foreign key constraints not supported with partitioning */
+ 	if(cxt->fkconstraints)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ 				 errmsg("FOREIGN KEY constraints not supported with partitioning")));
+ 
+ 	/*
+ 	 * Check if the primary key column is the one on which partitioning
+ 	 * is being done
+ 	 */
+ 
+ 	foreach(lc, cxt->ixconstraints)
+ 	{
+ 		Constraint  *constraint = lfirst(lc);
+ 		ListCell *partCol;
+ 		bool 	flag;
+ 
+ 		Assert(IsA(constraint, Constraint));
+ 
+ 		if(constraint->contype == CONSTR_PRIMARY ||
+ 		   constraint->contype == CONSTR_UNIQUE) 
+ 		{
+ /*
+ 			if (constraint->keys->length > 1) 
+ 			{
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ 						 errmsg("PRIMARY/UNIQUE KEY with partitioning can specify"
+ 								" single attribute only")));
+ 			}
+ */
+ 			flag = false;
+ 
+ 			foreach(partCol, partAttr->colName)
+ 			{
+ 				Alias *partColName = lfirst(partCol);
+ 
+ 				if(strcmp(partColName->aliasname, strVal(lfirst(list_head(constraint->keys)))) == 0)
+ 					flag = true;
+ 			}
+ 
+ 			if(flag == false)			
+ 			{
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ 						 errmsg("PRIMARY/UNIQUE KEY (%s) not the same as"
+ 								" the partitioning keys", strVal(lfirst(list_head(constraint->keys))))));
+ 			}
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * cxt.alist contains index related entries, if so, we need to add entries
+ 	 * for the children tables too
+ 	 */
+ 	foreach(temp_part, partitionList)
+ 	{
+ 		Partition *temp_partition = lfirst(temp_part);
+ 
+ 		foreach(lc, cxt->alist)
+ 		{
+ 			IndexStmt  *index, *copyindex;
+ 
+ 			index = lfirst(lc);
+ 			Assert(IsA(index, IndexStmt));
+ 
+ 			copyindex = copyObject(index);
+ 			*(copyindex->relation) = *(temp_partition->partName);
+ 
+ 			partindexlist = lappend(partindexlist, copyindex);
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Append partindexlist to alist now, so that the indexes get created for
+ 	 * the children tables too
+ 	 */
+ 	cxt->alist = list_concat(cxt->alist, partindexlist);
  }
  
  
Index: src/backend/tcop/pquery.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/tcop/pquery.c,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/backend/tcop/pquery.c	19 May 2009 06:59:32 -0000	1.1.1.3
--- src/backend/tcop/pquery.c	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 212,223 ****
  					lastOid = queryDesc->estate->es_lastoid;
  				else
  					lastOid = InvalidOid;
! 				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
! 				   "INSERT %u %u", lastOid, queryDesc->estate->es_processed);
  				break;
  			case CMD_UPDATE:
! 				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
! 						 "UPDATE %u", queryDesc->estate->es_processed);
  				break;
  			case CMD_DELETE:
  				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
--- 212,244 ----
  					lastOid = queryDesc->estate->es_lastoid;
  				else
  					lastOid = InvalidOid;
! 				
! 				/* If there are any overflow partition tuple then display message to user.*/
! 				if(queryDesc->estate->es_partition_overflow_tuples > 0)
! 				{
! 					snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
! 				   	"INSERT %u %u \nNOTICE : Inserted partition key does not map to any partition. %u row(s) moved to overflow partition.", 
! 					lastOid, queryDesc->estate->es_processed, queryDesc->estate->es_partition_overflow_tuples);
! 				}
! 				else
! 				{
! 					snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
! 				   	"INSERT %u %u", lastOid, queryDesc->estate->es_processed);
! 				}
  				break;
  			case CMD_UPDATE:
! 				/* If there are any overflow partition tuple then display message to user.*/
! 				if(queryDesc->estate->es_partition_overflow_tuples > 0)
! 				{
! 					snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
! 						"UPDATE %u \nNOTICE : Latest partition key does not map to any partition. %u row(s) moved to overflow partition.", 
! 						queryDesc->estate->es_processed, queryDesc->estate->es_partition_overflow_tuples);
! 				}
! 				else
! 				{
! 					snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
! 							 "UPDATE %u", queryDesc->estate->es_processed);
! 				}
  				break;
  			case CMD_DELETE:
  				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/tcop/utility.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/backend/tcop/utility.c	19 May 2009 06:59:32 -0000	1.1.1.2
--- src/backend/tcop/utility.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 57,62 ****
--- 57,63 ----
  #include "utils/guc.h"
  #include "utils/syscache.h"
  
+ extern bool IsPartition(Oid);
  
  /*
   * Verify user has ownership of specified relation, else ereport.
***************
*** 430,440 ****
  						relOid = DefineRelation((CreateStmt *) stmt,
  												RELKIND_RELATION);
  
  						/*
  						 * Let AlterTableCreateToastTable decide if this one
  						 * needs a secondary relation too.
  						 */
- 						CommandCounterIncrement();
  
  						/* parse and validate reloptions for the toast table */
  						toast_options = transformRelOptions((Datum) 0,
--- 431,446 ----
  						relOid = DefineRelation((CreateStmt *) stmt,
  												RELKIND_RELATION);
  
+ 						CommandCounterIncrement();
+ 						/*
+ 						 * Let DefinePartitions decide if partitions need to be created
+ 						 * for this table
+ 						 */
+ 						DefinePartitions((CreateStmt *)parsetree, relOid);
  						/*
  						 * Let AlterTableCreateToastTable decide if this one
  						 * needs a secondary relation too.
  						 */
  
  						/* parse and validate reloptions for the toast table */
  						toast_options = transformRelOptions((Datum) 0,
***************
*** 452,464 ****
  					}
  					else
  					{
! 						/* Recurse for anything else */
! 						ProcessUtility(stmt,
! 									   queryString,
! 									   params,
! 									   false,
! 									   None_Receiver,
! 									   NULL);
  					}
  
  					/* Need CCI between commands */
--- 458,478 ----
  					}
  					else
  					{
! 						/* Don't propagate primary/unique index over partitions.*/
! 						if( IsA(stmt, IndexStmt) && (true == IsPartition(RangeVarGetRelid(((IndexStmt *)stmt)->relation, false))))
! 						{
! 							continue;
! 						}
! 						else
! 						{
! 							/* Recurse for anything else */
! 							ProcessUtility(stmt,
! 										   queryString,
! 										   params,
! 										   false,
! 										   None_Receiver,
! 										   NULL);
! 						}
  					}
  
  					/* Need CCI between commands */
Index: src/backend/utils/adt/numeric.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/utils/adt/numeric.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/backend/utils/adt/numeric.c	19 May 2009 06:59:33 -0000	1.1.1.2
--- src/backend/utils/adt/numeric.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 3633,3639 ****
  	char	   *endptr;
  
  	tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
! 											  NumericGetDatum(num)));
  
  	/* unlike float8in, we ignore ERANGE from strtod */
  	val = strtod(tmp, &endptr);
--- 3633,3639 ----
  	char	   *endptr;
  
  	tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
! 		 NumericGetDatum(num)));
  
  	/* unlike float8in, we ignore ERANGE from strtod */
  	val = strtod(tmp, &endptr);
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/backend/utils/adt/ruleutils.c	19 May 2009 06:59:33 -0000	1.1.1.2
--- src/backend/utils/adt/ruleutils.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 44,49 ****
--- 44,51 ----
  #include "parser/parse_func.h"
  #include "parser/parse_oper.h"
  #include "parser/parsetree.h"
+ #include "parser/parse_clause.h"
+ #include "parser/parse_expr.h"
  #include "rewrite/rewriteHandler.h"
  #include "rewrite/rewriteManip.h"
  #include "rewrite/rewriteSupport.h"
***************
*** 6503,6506 ****
--- 6505,6546 ----
  	ReleaseSysCache(tuple);
  
  	return result;
+ }
+ 
+ /*
+  * get the text corresponding to a raw expr 
+  */
+ char *
+ pg_get_expr_text(RangeVar *relation, Node *raw_expr, StringInfo buf)
+ {
+ 	deparse_context context;
+ 	Node *opex;
+ 	Node *temp;
+ 	deparse_namespace dpns;
+ 	RangeVar *old;
+ 	RangeVar *new;
+ 	ParseState *pstate = make_parsestate(NULL);
+ 
+ 	old = makeNode(RangeVar);
+ 	old->relname = relation->relname;
+ 	old->alias = makeAlias("*OLD*", NIL);
+ 
+ 	new = makeNode(RangeVar);
+ 	new->relname = relation->relname;
+ 	new->alias = makeAlias("*NEW*", NIL);
+ 
+ 	transformFromClause(pstate, list_make3(relation, old, new));
+ 	temp = transformExpr(pstate, raw_expr);
+ 
+ 	opex = (Node *)temp;
+ 	context.buf = buf;
+ 	context.namespaces = list_make1(&dpns);
+ 	context.varprefix = true;
+ 	context.prettyFlags = PRETTYFLAG_PAREN | PRETTYFLAG_INDENT ;
+ 	context.indentLevel = PRETTYINDENT_STD;
+ 	dpns.rtable = pstate->p_rtable;
+ 	dpns.outer_plan = dpns.inner_plan = NULL;
+ 
+ 	get_rule_expr(opex, &context, false);
+ 	return (context.buf)->data;
  }
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/bin/pg_dump/pg_dump.c	19 May 2009 06:59:36 -0000	1.1.1.2
--- src/bin/pg_dump/pg_dump.c	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 1364,1369 ****
--- 1364,1401 ----
  	PQExpBuffer copyBuf = createPQExpBuffer();
  	DataDumperPtr dumpFn;
  	char	   *copyStmt;
+     int ntuples;
+     PGresult   *res;
+ 	PQExpBuffer query = createPQExpBuffer();
+ 	char		*tableName;
+ 
+     /* If a partition, then do nothing. */
+ 	query = createPQExpBuffer();
+     initPQExpBuffer(query);
+     appendPQExpBuffer(query, "SELECT * from public.pg_partitions where child = '%s';", tbinfo->dobj.name);
+     res = PQexec(g_conn, query->data);
+     check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+     ntuples = PQntuples(res);
+ 
+     if(ntuples > 0)
+     {
+         PQclear(res);
+         return;
+     }
+ 
+ 	/* We dont want to dump data of overflow table. */
+ 
+ 	tableName = NULL;
+     initPQExpBuffer(query);
+     appendPQExpBuffer(query, "SELECT public.getparentfromoverflow(%u);", tbinfo->dobj.catId.oid);
+     res = PQexec(g_conn, query->data);
+     check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 	tableName = PQgetvalue(res, 0, 0);
+ 
+ 	if(strlen(tableName))
+ 	{
+ 		return;
+ 	}
  
  	if (!dump_inserts)
  	{
***************
*** 9736,9745 ****
--- 9768,9806 ----
  	}
  	else
  	{
+ 
+ 		int ntuples;
+ 	
+ 	    initPQExpBuffer(query);
+ 	    appendPQExpBuffer(query, "SELECT * from public.pg_partitions where child = '%s';", tbinfo->dobj.name);
+     	res = PQexec(g_conn, query->data);
+ 	    check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 		ntuples = PQntuples(res);
+ 
+ 		/* We dont want to dump schema of partitions. */
+ 		if(ntuples > 0)
+ 		{
+ 			PQclear(res);
+ 			return;
+ 		}
+ 
  		reltypename = "TABLE";
  		numParents = tbinfo->numParents;
  		parents = tbinfo->parents;
  
+ 	    initPQExpBuffer(query);
+ 	    appendPQExpBuffer(query, "SELECT public.isvalidoverflowpartition(%u);", tbinfo->dobj.catId.oid);
+ 		res = PQexec(g_conn, query->data);
+     	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 
+ 		/* We dont want to dump anything for overflow table except the data. */
+ 		if(atooid(PQgetvalue(res, 0, 0)))
+ 		{
+ 			PQclear(res);
+     		return;
+ 		}
+ 
+ 
  		/*
  		 * DROP must be fully qualified in case same name appears in
  		 * pg_catalog
***************
*** 9860,9865 ****
--- 9921,9935 ----
  			appendPQExpBuffer(q, ")");
  		}
  
+ 		/* Check if we are dumping partitioned table, if so then get the SQL 
+ 		for creating partitioned table. */
+ 
+ 		initPQExpBuffer(query);
+ 		appendPQExpBuffer(query, "SELECT public.dumppartitionedtableschema(%u) as schema", tbinfo->dobj.catId.oid);
+ 		res = PQexec(g_conn, query->data);
+ 		check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 		appendPQExpBuffer(q, PQgetvalue(res, 0, 0));
+ 
  		appendPQExpBuffer(q, ";\n");
  
  		/*
***************
*** 10101,10113 ****
  static void
  dumpIndex(Archive *fout, IndxInfo *indxinfo)
  {
! 	TableInfo  *tbinfo = indxinfo->indextable;
  	PQExpBuffer q;
  	PQExpBuffer delq;
  
  	if (dataOnly)
  		return;
  
  	q = createPQExpBuffer();
  	delq = createPQExpBuffer();
  
--- 10171,10198 ----
  static void
  dumpIndex(Archive *fout, IndxInfo *indxinfo)
  {
! 	TableInfo  	*tbinfo = indxinfo->indextable;
  	PQExpBuffer q;
  	PQExpBuffer delq;
+     PGresult   	*res;
+     PQExpBuffer query = createPQExpBuffer();
+ 
  
  	if (dataOnly)
  		return;
  
+ 	initPQExpBuffer(query);
+ 	appendPQExpBuffer(query, "SELECT public.isoverflowindex(%u);", indxinfo->dobj.catId.oid);
+ 	res = PQexec(g_conn, query->data);
+ 	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 
+ 	/* We dont want to dump overflow-index. */
+ 	if(atooid(PQgetvalue(res, 0, 0)))
+ 	{
+ 		PQclear(res);
+ 		return;
+ 	}
+ 
  	q = createPQExpBuffer();
  	delq = createPQExpBuffer();
  
***************
*** 10173,10183 ****
--- 10258,10297 ----
  	TableInfo  *tbinfo = coninfo->contable;
  	PQExpBuffer q;
  	PQExpBuffer delq;
+     int ntuples;
+     PGresult   *res;
+     PQExpBuffer query = createPQExpBuffer();
  
  	/* Skip if not to be dumped */
  	if (!coninfo->dobj.dump || dataOnly)
  		return;
  
+     initPQExpBuffer(query);
+     appendPQExpBuffer(query, "SELECT * from public.pg_partitions where child = '%s';", tbinfo->dobj.name);
+     res = PQexec(g_conn, query->data);
+     check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+     ntuples = PQntuples(res);
+ 
+     /* We dont want to dump constraints of partitions. */
+     if(ntuples > 0)
+     {
+         PQclear(res);
+         return;
+     }
+ 
+ 	initPQExpBuffer(query);
+ 	appendPQExpBuffer(query, "SELECT public.isvalidoverflowpartition(%u);", tbinfo->dobj.catId.oid);
+ 	res = PQexec(g_conn, query->data);
+ 	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 
+ 	/* We dont want to dump anything for overflow table except the data. */
+ 	if(atooid(PQgetvalue(res, 0, 0)))
+ 	{
+ 		PQclear(res);
+ 		return;
+ 	}
+ 
+ 
  	q = createPQExpBuffer();
  	delq = createPQExpBuffer();
  
***************
*** 10708,10720 ****
  dumpTrigger(Archive *fout, TriggerInfo *tginfo)
  {
  	TableInfo  *tbinfo = tginfo->tgtable;
! 	PQExpBuffer query;
  	PQExpBuffer delqry;
  	const char *p;
  	int			findx;
  
  	if (dataOnly)
  		return;
  
  	query = createPQExpBuffer();
  	delqry = createPQExpBuffer();
--- 10822,10878 ----
  dumpTrigger(Archive *fout, TriggerInfo *tginfo)
  {
  	TableInfo  *tbinfo = tginfo->tgtable;
! 	PQExpBuffer query = createPQExpBuffer();
  	PQExpBuffer delqry;
  	const char *p;
  	int			findx;
+ 	int 		ntuples;
+     PGresult   *res;
+ 
  
  	if (dataOnly)
  		return;
+ 
+ 	/* If a partition or partitioned table, then do nothing as triggers would 
+ 	get created automatically with the SQL generated for partitioned tbale.*/
+ 
+ 	initPQExpBuffer(query);
+ 	appendPQExpBuffer(query, "SELECT * from public.pg_partitions where parent = '%s';", tbinfo->dobj.name);
+ 	res = PQexec(g_conn, query->data);
+ 	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 	ntuples = PQntuples(res);
+ 
+ 	if(ntuples > 0)
+ 	{
+ 		PQclear(res);
+ 		return;
+ 	}
+ 
+     initPQExpBuffer(query);
+     appendPQExpBuffer(query, "SELECT * from public.pg_partitions where child = '%s';", tbinfo->dobj.name);
+     res = PQexec(g_conn, query->data);
+     check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+     ntuples = PQntuples(res);
+ 
+     /* We dont want to dump triggers of partitions. */
+     if(ntuples > 0)
+     {
+         PQclear(res);
+         return;
+     }
+ 
+     initPQExpBuffer(query);
+     appendPQExpBuffer(query, "SELECT public.isvalidoverflowpartition(%u);", tbinfo->dobj.catId.oid);
+     res = PQexec(g_conn, query->data);
+     check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 
+     /* We dont want to dump anything for overflow table except the data. */
+     if(atooid(PQgetvalue(res, 0, 0)))
+     {
+         PQclear(res);
+         return;
+     }
+ 
  
  	query = createPQExpBuffer();
  	delqry = createPQExpBuffer();
Index: src/include/catalog/indexing.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/catalog/indexing.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/include/catalog/indexing.h	19 May 2009 06:59:37 -0000	1.1.1.2
--- src/include/catalog/indexing.h	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 57,62 ****
--- 57,68 ----
   * index name (much less the numeric OID).
   */
  
+ DECLARE_INDEX(pg_partition_primary_index, 2337, on pg_partition using btree(parentrelid oid_ops, partrelid oid_ops, keyorder int2_ops));
+ #define PartitionParentIndexId 2337
+ 
+ DECLARE_UNIQUE_INDEX(pg_partition_oid_index, 2338, on pg_partition using btree(oid oid_ops));
+ #define PartitionOidIndexId 2338
+ 
  DECLARE_UNIQUE_INDEX(pg_aggregate_fnoid_index, 2650, on pg_aggregate using btree(aggfnoid oid_ops));
  #define AggregateFnoidIndexId  2650
  
Index: src/include/catalog/pg_inherits_fn.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/catalog/pg_inherits_fn.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -c -r1.1.1.1 -r1.1.1.1.2.1
*** src/include/catalog/pg_inherits_fn.h	19 May 2009 06:59:37 -0000	1.1.1.1
--- src/include/catalog/pg_inherits_fn.h	8 Jun 2009 08:28:51 -0000	1.1.1.1.2.1
***************
*** 21,25 ****
--- 21,27 ----
  extern List *find_all_inheritors(Oid parentrelId, LOCKMODE lockmode);
  extern bool has_subclass(Oid relationId);
  extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
+ extern List *find_inheritance_parents(Oid inhchild);
+ extern List *find_all_ancestors(Oid childrel);
  
  #endif   /* PG_INHERITS_FN_H */
Index: src/include/commands/tablecmds.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/commands/tablecmds.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/include/commands/tablecmds.h	19 May 2009 06:59:38 -0000	1.1.1.2
--- src/include/commands/tablecmds.h	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 18,23 ****
--- 18,38 ----
  #include "utils/relcache.h"
  
  
+ typedef struct partitionInfo
+ {
+     char    partitionName[20];
+     Value   minValue;
+     Value   maxValue;
+ }partitionInfo;
+ 
+ enum SpecialPartitionRanges
+ {
+     MINVALRANGE,
+     MAXVALRANGE,
+     OTHER
+ };
+ 
+ 
  extern Oid	DefineRelation(CreateStmt *stmt, char relkind);
  
  extern void RemoveRelations(DropStmt *drop);
***************
*** 69,73 ****
--- 84,93 ----
  extern void AtEOSubXact_on_commit_actions(bool isCommit,
  							  SubTransactionId mySubid,
  							  SubTransactionId parentSubid);
+ 
+ extern void	DefinePartitions(CreateStmt *stmt, Oid parentRelId);
+ extern int GetPartitionsCount(Oid parentOid);
+ extern int GetPartitionsCountAtt(Oid parentOid, Oid attNum);
+ extern int ValidateRanges(PartitionAttrs *partAttr, Oid parentRelOid, Oid *partitionRelOids);
  
  #endif   /* TABLECMDS_H */
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/nodes/execnodes.h,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/include/nodes/execnodes.h	19 May 2009 06:59:38 -0000	1.1.1.3
--- src/include/nodes/execnodes.h	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 355,360 ****
--- 355,364 ----
  	TupleTable	es_tupleTable;	/* Array of TupleTableSlots */
  
  	uint32		es_processed;	/* # of tuples processed */
+ 
+ 	/* # of tuples that could not find valid partition and have been inserted into overflow partition. */
+ 	uint32		es_partition_overflow_tuples;	
+ 
  	Oid			es_lastoid;		/* last oid processed (by INSERT) */
  	List	   *es_rowMarks;	/* not good place, but there is no other */
  
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/nodes/nodes.h,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/include/nodes/nodes.h	19 May 2009 06:59:38 -0000	1.1.1.3
--- src/include/nodes/nodes.h	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 376,382 ****
  	T_XmlSerialize,
  	T_WithClause,
  	T_CommonTableExpr,
! 
  	/*
  	 * TAGS FOR RANDOM OTHER STUFF
  	 *
--- 376,388 ----
  	T_XmlSerialize,
  	T_WithClause,
  	T_CommonTableExpr,
! 	T_PartitionAttrs,
! 	T_Partition,
! 	T_UpdatePartitionStmt,
! 	T_SplitPartitionStmt,
! 	T_MergePartitionStmt,
! 	T_ExchangePartitionStmt,
! 	T_RenamePartitionStmt,
  	/*
  	 * TAGS FOR RANDOM OTHER STUFF
  	 *
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/nodes/parsenodes.h,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/include/nodes/parsenodes.h	19 May 2009 06:59:38 -0000	1.1.1.3
--- src/include/nodes/parsenodes.h	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 1131,1137 ****
  	AT_EnableReplicaRule,		/* ENABLE REPLICA RULE name */
  	AT_DisableRule,				/* DISABLE RULE name */
  	AT_AddInherit,				/* INHERIT parent */
! 	AT_DropInherit				/* NO INHERIT parent */
  } AlterTableType;
  
  typedef struct AlterTableCmd	/* one subcommand of an ALTER TABLE */
--- 1131,1146 ----
  	AT_EnableReplicaRule,		/* ENABLE REPLICA RULE name */
  	AT_DisableRule,				/* DISABLE RULE name */
  	AT_AddInherit,				/* INHERIT parent */
! 	AT_DropInherit,				/* NO INHERIT parent */
! 	AT_AddPartition,			/* add partition */
! 	AT_DropPartitionByName,		/* drop partition by name. */
! 	AT_DropPartitionByRange,	/* drop partition by range. */
! 	AT_UpdatePartition,			/* Update the range partition. */
! 	AT_SplitPartition,			/* Split range partition. */
! 	AT_MergePartition,			/* Merge range partitions. */
! 	AT_UpdateHashPartition,  	/* Update the hash partition. */
! 	AT_ExchangePartition,		/* Exchange partition with a table. */
! 	AT_RenamePartition			/* Rename a partition. */
  } AlterTableType;
  
  typedef struct AlterTableCmd	/* one subcommand of an ALTER TABLE */
***************
*** 1334,1339 ****
--- 1343,1349 ----
  	List	   *options;		/* options from WITH clause */
  	OnCommitAction oncommit;	/* what do we do at COMMIT? */
  	char	   *tablespacename; /* table space to use, or NULL */
+ 	Node	   *partAttr;		/* partitioning related information */
  } CreateStmt;
  
  /* ----------
***************
*** 1372,1389 ****
  	CONSTR_ATTR_IMMEDIATE
  } ConstrType;
  
  typedef struct Constraint
  {
! 	NodeTag		type;
! 	ConstrType	contype;
! 	char	   *name;			/* name, or NULL if unnamed */
! 	Node	   *raw_expr;		/* expr, as untransformed parse tree */
! 	char	   *cooked_expr;	/* expr, as nodeToString representation */
! 	List	   *keys;			/* String nodes naming referenced column(s) */
! 	List	   *options;		/* options from WITH clause */
! 	char	   *indexspace;		/* index tablespace for PKEY/UNIQUE
! 								 * constraints; NULL for default */
  } Constraint;
  
  /* ----------
   * Definitions for FOREIGN KEY constraints in CreateStmt
--- 1382,1479 ----
  	CONSTR_ATTR_IMMEDIATE
  } ConstrType;
  
+ 
+ /*
+  * Enumeration which defines the various possibilites for the partitioning
+  * function.
+  */
+ typedef enum PartitionFunction {
+         PART_UNDEFINED,
+         PART_LIST,
+         PART_RANGE,
+         PART_HASH
+ } PartitionFunction;
+ 
+ 
  typedef struct Constraint
  {
! 	NodeTag				type;
! 	List 				*min_value;
! 	List				*max_value;
! 	List				*partition_list_values;
! //	ConstrType			contype;
! 	PartitionFunction	contype;
! 	char	   			*name;			/* name, or NULL if unnamed */
! 	Node	   			*raw_expr;		/* expr, as untransformed parse tree */
! 	char	   			*cooked_expr;	/* expr, as nodeToString representation */
! 	List	   			*keys;			/* String nodes naming referenced column(s) */
! 	List	   			*options;		/* options from WITH clause */
! 	char	   			*indexspace;	/* index tablespace for PKEY/UNIQUE
! 								 			* constraints; NULL for default */
  } Constraint;
+ 
+ //typedef struct PartitionConstraint
+ //{
+ //	Node			*min_value;
+ //  	Node			*max_value;
+ //	List 			*list_partition_values;
+ //	PartitionFunction 	contype;
+ //	char	   		*name;			/* name, or NULL if unnamed */
+ //	Node	   		*raw_expr;		/* expr, as untransformed parse tree */
+ //	char	   		*cooked_expr;		/* expr, as nodeToString representation */
+ //	List	   		*keys;			/* String nodes naming referenced column(s) */
+ //	List	   		*options;		/* options from WITH clause */
+ //	char	   		*indexspace;		/* index tablespace for PKEY/UNIQUE
+ //								 * constraints; NULL for default */
+ // } PartitionConstraint;
+ 
+ typedef struct Partition {
+ 	NodeTag		type;
+ 	RangeVar	*partName;          /* Name of the partition */
+ 	Constraint	*partitionCheck;    /* per partition constraint */
+ 	char 		*tablespacename;	/* tablespace name*/ 
+ } Partition;
+ 
+ typedef struct UpdatePartitionStmt
+ {
+ 	NodeTag		type;
+ 	Partition 	*prev;
+ 	Partition 	*after;
+ }UpdatePartitionStmt;
+ 
+ typedef struct SplitPartitionStmt
+ {
+ 	NodeTag 	type;
+ 	List		*partNames;
+ 	List		*splitValues;
+ }SplitPartitionStmt;
+ 
+ typedef struct MergePartitionStmt
+ {
+ 	NodeTag 	type;
+ 	List		*partNames;
+ }MergePartitionStmt;
+ 
+ typedef struct ExchangePartitionStmt
+ {
+ 	NodeTag 	type;
+ 	List		*partNames;
+ }ExchangePartitionStmt;
+ 
+ typedef struct RenamePartitionStmt
+ {
+ 	NodeTag 	type;
+ 	List		*partNames;
+ }RenamePartitionStmt;
+ 
+ typedef struct PartitionAttrs {
+ 	NodeTag				type;
+ 	int     			numberOfPartitions; /* Number of partitions */
+ 	List    			*partitions;  		/* The list of partitions */
+ 	PartitionFunction 	partFunc; 			/* type of partition */
+ 	List 				*colName;           /* partition column name */
+ 	bool				hasOverflowPartition;
+ } PartitionAttrs;
  
  /* ----------
   * Definitions for FOREIGN KEY constraints in CreateStmt
Index: src/include/parser/kwlist.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/parser/kwlist.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -c -r1.1.1.1 -r1.1.1.1.2.1
*** src/include/parser/kwlist.h	19 May 2009 06:59:38 -0000	1.1.1.1
--- src/include/parser/kwlist.h	26 May 2009 08:04:45 -0000	1.1.1.1.2.1
***************
*** 142,147 ****
--- 142,148 ----
  PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
  PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
  PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
+ PG_KEYWORD("exchange", EXCHANGE, UNRESERVED_KEYWORD)
  PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
  PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD)
  PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
***************
*** 227,232 ****
--- 228,234 ----
  PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
  PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
  PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
+ PG_KEYWORD("merge", MERGE, UNRESERVED_KEYWORD)
  PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
  PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
  PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
***************
*** 278,284 ****
  PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
  PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
  PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
! PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
  PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
  PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
  PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
--- 280,287 ----
  PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
  PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
  PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
! PG_KEYWORD("partition", PARTITION, RESERVED_KEYWORD)
! PG_KEYWORD("partitions", PARTITIONS, UNRESERVED_KEYWORD)
  PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
  PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
  PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
***************
*** 294,300 ****
  PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD)
  PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD)
  PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD)
! PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD)
  PG_KEYWORD("read", READ, UNRESERVED_KEYWORD)
  PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
  PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
--- 297,303 ----
  PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD)
  PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD)
  PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD)
! PG_KEYWORD("range", RANGE, RESERVED_KEYWORD)
  PG_KEYWORD("read", READ, UNRESERVED_KEYWORD)
  PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
  PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
***************
*** 340,345 ****
--- 343,349 ----
  PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD)
  PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD)
  PG_KEYWORD("some", SOME, RESERVED_KEYWORD)
+ PG_KEYWORD("split", SPLIT, UNRESERVED_KEYWORD)
  PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD)
  PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD)
  PG_KEYWORD("start", START, UNRESERVED_KEYWORD)
Index: src/include/tcop/dest.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/tcop/dest.h,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/include/tcop/dest.h	19 May 2009 06:59:38 -0000	1.1.1.3
--- src/include/tcop/dest.h	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 71,77 ****
  
  
  /* buffer size to use for command completion tags */
! #define COMPLETION_TAG_BUFSIZE	64
  
  
  /* ----------------
--- 71,77 ----
  
  
  /* buffer size to use for command completion tags */
! #define COMPLETION_TAG_BUFSIZE 128 
  
  
  /* ----------------
Index: src/include/utils/builtins.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/include/utils/builtins.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -c -r1.1.1.2 -r1.1.1.2.2.1
*** src/include/utils/builtins.h	19 May 2009 06:59:38 -0000	1.1.1.2
--- src/include/utils/builtins.h	26 May 2009 08:04:45 -0000	1.1.1.2.2.1
***************
*** 16,21 ****
--- 16,23 ----
  
  #include "fmgr.h"
  #include "nodes/parsenodes.h"
+ #include "nodes/primnodes.h"
+ #include "lib/stringinfo.h"
  
  /*
   *		Defined in adt/
***************
*** 595,600 ****
--- 597,604 ----
  extern const char *quote_identifier(const char *ident);
  extern char *quote_qualified_identifier(const char *namespace,
  						   const char *ident);
+ extern char *pg_get_expr_text(RangeVar *relation, 
+ 						Node *raw_expr, StringInfo buf);
  
  /* tid.c */
  extern Datum tidin(PG_FUNCTION_ARGS);
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -c -r1.1.1.3 -r1.1.1.3.2.1
*** src/interfaces/libpq/libpq-int.h	19 May 2009 06:59:40 -0000	1.1.1.3
--- src/interfaces/libpq/libpq-int.h	26 May 2009 08:04:45 -0000	1.1.1.3.2.1
***************
*** 81,87 ****
  /*
   * POSTGRES backend dependent Constants.
   */
! #define CMDSTATUS_LEN 64		/* should match COMPLETION_TAG_BUFSIZE */
  
  /*
   * PGresult and the subsidiary types PGresAttDesc, PGresAttValue
--- 81,87 ----
  /*
   * POSTGRES backend dependent Constants.
   */
! #define CMDSTATUS_LEN 128 /* should match COMPLETION_TAG_BUFSIZE */
  
  /*
   * PGresult and the subsidiary types PGresAttDesc, PGresAttValue
Index: src/test/regress/regress.c
===================================================================
RCS file: /mart/pgsql_home/pgrepo/pgsql_init/src/test/regress/regress.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.2
diff -c -r1.1.1.2 -r1.1.1.2.2.2
*** src/test/regress/regress.c	19 May 2009 06:59:42 -0000	1.1.1.2
--- src/test/regress/regress.c	8 Jun 2009 08:28:52 -0000	1.1.1.2.2.2
***************
*** 18,44 ****
  #include "utils/geo_decls.h"
  
  
  #define P_MAXDIG 12
  #define LDELIM			'('
  #define RDELIM			')'
  #define DELIM			','
  
! extern Datum regress_dist_ptpath(PG_FUNCTION_ARGS);
! extern Datum regress_path_dist(PG_FUNCTION_ARGS);
! extern PATH *poly2path(POLYGON *poly);
! extern Datum interpt_pp(PG_FUNCTION_ARGS);
! extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
! extern Datum overpaid(PG_FUNCTION_ARGS);
! extern Datum boxarea(PG_FUNCTION_ARGS);
! extern char *reverse_name(char *string);
! extern int	oldstyle_length(int n, text *t);
! extern Datum int44in(PG_FUNCTION_ARGS);
! extern Datum int44out(PG_FUNCTION_ARGS);
  
  #ifdef PG_MODULE_MAGIC
  PG_MODULE_MAGIC;
  #endif
  
  
  /*
   * Distance from a point to a path
--- 18,797 ----
  #include "utils/geo_decls.h"
  
  
+ #include "postgres.h"
+ #include "executor/spi.h"
+ #include "commands/trigger.h"
+ 
+ #include "optimizer/plancat.h" 
+ #include "utils/fmgroids.h"
+ #include "catalog/pg_partition.h"
+ #include "catalog/indexing.h"
+ #include "utils/tqual.h"
+ #include "utils/lsyscache.h"
+ #include "access/hash.h"
+ #include "nodes/parsenodes.h"
+ #include "utils/snapmgr.h"
+ 
+ 
+ extern Datum trigf(PG_FUNCTION_ARGS);
+ 
+ PG_FUNCTION_INFO_V1(trigf);
+ 
+ #define     ItemPointerGetDatum(X)   PointerGetDatum(X)
+ 
  #define P_MAXDIG 12
  #define LDELIM			'('
  #define RDELIM			')'
  #define DELIM			','
  
! extern 	Datum regress_dist_ptpath(PG_FUNCTION_ARGS);
! extern 	Datum regress_path_dist(PG_FUNCTION_ARGS);
! extern 	PATH *poly2path(POLYGON *poly);
! extern 	Datum interpt_pp(PG_FUNCTION_ARGS);
! extern 	void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
! extern 	Datum overpaid(PG_FUNCTION_ARGS);
! extern 	Datum boxarea(PG_FUNCTION_ARGS);
! extern 	char *reverse_name(char *string);
! extern 	int	oldstyle_length(int n, text *t);
! extern 	Datum int44in(PG_FUNCTION_ARGS);
! extern 	Datum int44out(PG_FUNCTION_ARGS);
! extern 	List* find_inheritance_parents(Oid inhrelid);
! extern 	Oid get_relevant_hash_partition(HeapTuple tuple, Relation rel);
! extern 	Oid get_relevant_partition(HeapTuple tuple, Relation rel);
! extern 	int GetPartitionType(Oid);
! extern 	char* DisplayDatum(Datum datum, Oid type);
! extern 	Datum GetDatum(Relation rel, Oid type, HeapTuple tuple, int column);
! Datum  	partition_update_trigger(PG_FUNCTION_ARGS); 
! Datum  	partition_constraints_hash(PG_FUNCTION_ARGS);
! Datum  	partition_insert_trigger_hash(PG_FUNCTION_ARGS);
! Datum  	partition_insert_trigger(PG_FUNCTION_ARGS);
! text   	*parttype(int type);
! text   	*maxval(Oid oid);
! text   	*minval(Oid oid);
! text 	*dumppartitionedtableschema(Oid oid);
! text	*getparentfromoverflow(Oid oid);
! extern 	List* GetPartitionNames(Oid parentOid);
! extern  List* GetMinValues(Oid parentOid);
! extern  List* GetMaxValues(Oid parentOid);
! extern  int   GetPartitionsCount(Oid parentOid);
! extern	bool  IsPartition(Oid oid);
! extern  bool  IsOverflowPartition(Oid oid);
! extern  List* GetPartitionAttributes(Oid parentOid);
! extern  List* GetPartitionAttributeTypes(Oid parentOid);
! extern  int   GetPartitionedTableType(Oid parentOid);
! extern  char* format_type_be(Oid type_oid);
! extern  char *GetPartitionedTableFromOverflow(Oid oid);
! int		isvalidpartition(Oid oid);
! int		isvalidpartitionedtable(Oid oid);
! int		isvalidoverflowpartition(Oid oid);
! int		isoverflowindex(Oid oid);
! extern 	void InsertTuple(HeapTuple newtuple, Oid targetId);
! extern 	Oid GetOverflowPartition(Relation rel);
! extern  Oid GetOverflowIndexId(Oid relId);
  
  #ifdef PG_MODULE_MAGIC
  PG_MODULE_MAGIC;
  #endif
  
+ 
+ text 
+ *getparentfromoverflow(Oid oid)
+ {
+ 	text        *typeText = NULL;
+ 	char		*str = NULL;
+ 	
+ 	str = GetPartitionedTableFromOverflow(oid);
+ 
+ 	if(str)
+ 	{
+ 	    typeText = palloc(VARHDRSZ + strlen(str));
+     	memcpy(VARDATA(typeText), str, strlen(str));
+ 	    SET_VARSIZE(typeText, (VARHDRSZ + strlen(str)));
+ 	}
+ 	else
+ 	{
+ 	    typeText = palloc(VARHDRSZ);
+ 	    SET_VARSIZE(typeText, VARHDRSZ);
+ 	}
+ 
+     return typeText;
+ 	
+ }
+ 
+ int 
+ isoverflowindex(Oid indexId)
+ {
+ 	Relation 	rel;
+ 	Oid			oid = 0;
+ 	
+ 	rel = index_open(indexId, AccessShareLock);
+ 
+ 	/* overflow indices are named as 'of_index_OVERFLOWTABLEID'*/
+ 	if(strncmp(RelationGetRelationName(rel), "of_index_", strlen("of_index_")) == 0)
+ 	{
+ 		sscanf(RelationGetRelationName(rel)+strlen("of_index_"), "%u", &oid);
+ 		if(IsOverflowPartition(oid))
+ 		{
+ 			index_close(rel, AccessShareLock);
+ 			return 1;
+ 		}
+ 	}
+ 	index_close(rel, AccessShareLock);
+ 	return 0;
+ }
+ 
+ int
+ isvalidoverflowpartition(Oid oid)
+ {
+ 	if(IsOverflowPartition(oid))
+ 		return 1;
+ 	else
+ 		return 0;
+ }
+ 
+ int 
+ isvalidpartitionedtable(Oid oid)
+ {
+ 	return GetPartitionsCount(oid);
+ }
+ 
+ int
+ isvalidpartition(Oid oid)
+ {
+ 	if(IsPartition(oid))
+ 		return 1;
+ 	else
+ 		return 0;
+ }
+ 
+ text *
+ dumppartitionedtableschema(Oid oid)
+ {
+ 	List		*partitionNames 	= NULL; 
+ 	List    	*partitionAttrs		= NULL;
+ 	List		*minValues 			= NULL;
+ 	List		*maxValues			= NULL;
+ 	List		*partitionAttrTypes = NULL;
+ 	ListCell 	*cell;
+ 	ListCell	*minValue;
+ 	ListCell 	*maxValue;
+ 	ListCell	*type;
+ 	int			partitionedTableType;
+ 	int			partitionCount;
+ 	bool		flag;
+ 	StringInfo	str = makeStringInfo();
+ 	StringInfo	part= makeStringInfo();
+ 	text    	*typeText;	
+ 	
+ 	partitionCount 			= GetPartitionsCount(oid);
+ 	partitionAttrs 			= GetPartitionAttributes(oid);
+ 	partitionNames 			= GetPartitionNames(oid);
+ 	minValues				= GetMinValues(oid);
+ 	maxValues				= GetMaxValues(oid);
+ 	partitionAttrTypes 		= GetPartitionAttributeTypes(oid);
+ 	partitionedTableType	= GetPartitionedTableType(oid);
+ 
+ 
+ 	flag = false;
+ 	switch(partitionedTableType)
+ 	{
+ 		case PART_RANGE:
+ 			appendStringInfo(str, "PARTITION BY RANGE (");
+ 			break;
+ 		case PART_LIST:
+ 			appendStringInfo(str, "PARTITION BY LIST (");
+ 			break;
+ 		case PART_HASH:
+ 			appendStringInfo(str, "PARTITION BY HASH (");
+ 			break;
+ 	}
+ 
+ 	foreach(cell, partitionAttrs)
+ 	{
+ 		if(flag == false)
+ 		{
+ 			appendStringInfo(str, "%s", (char *)lfirst(cell));
+ 			flag = true;
+ 		}
+ 		else
+ 		{
+ 			appendStringInfo(str, ", %s", (char *)lfirst(cell));
+ 		}
+ 	}
+ 	
+ 	if(partitionedTableType == PART_RANGE)
+ 	{
+ 		Relation    rel;
+ 
+ 		appendStringInfo(str, ")\n(\n");
+ 
+ 		minValue = list_head(minValues);
+ 		maxValue = list_head(maxValues);
+ 		flag = false;
+ 
+ 		foreach(cell, partitionNames)
+ 		{		
+ 			bool 		flag1 = false;
+ 			StringInfo	min = makeStringInfo();
+ 			StringInfo	max = makeStringInfo();
+ 
+ 			foreach(type, partitionAttrTypes)
+ 			{
+ 				if(flag1 == false)				
+ 				{
+ 					if(strcasecmp(lfirst(minValue), "minvalue"))
+ 					{
+ 						appendStringInfo(min, "'%s'::%s", (char *)lfirst(minValue), format_type_be((int)lfirst_int(type)));
+ 					}
+ 					else
+ 					{
+ 						appendStringInfo(min, "%s", (char *)lfirst(minValue));
+ 					}
+ 
+ 					if(strcasecmp(lfirst(maxValue), "maxvalue"))
+ 					{
+ 						appendStringInfo(max, "'%s'::%s", (char *)lfirst(maxValue), format_type_be((int)lfirst_int(type)));
+ 					}
+ 					else
+ 					{
+ 						appendStringInfo(max, "%s", (char *)lfirst(maxValue));
+ 					}
+ 					flag1 = true;
+ 				}
+ 				else
+ 				{
+ 					if(strcasecmp(lfirst(minValue), "minvalue"))
+ 					{
+ 						appendStringInfo(min, ", '%s'::%s", (char *)lfirst(minValue), format_type_be((int)lfirst_int(type)));
+ 					}
+ 					else
+ 					{
+ 						appendStringInfo(min, ", %s", (char *)lfirst(minValue));
+ 					}
+ 
+ 					if(strcasecmp(lfirst(maxValue), "maxvalue"))
+ 					{
+ 						appendStringInfo(max, ", '%s'::%s", (char *)lfirst(maxValue), format_type_be((int)lfirst_int(type)));
+ 					}
+ 					else
+ 					{
+ 						appendStringInfo(max, ", %s", (char *)lfirst(maxValue));
+ 					}
+ 				}
+ 				minValue = minValue->next;
+ 				maxValue = maxValue->next;
+ 			}
+ 
+ 			if(flag == false)
+ 			{
+ 				appendStringInfo(part, " %s( START %s END %s )", (char *)lfirst(cell), min->data, max->data);
+ 				flag = true;
+ 			}
+ 			else
+ 			{
+ 				appendStringInfo(part, ",\n %s( START %s END %s )", (char *)lfirst(cell), min->data, max->data);
+ 			}
+ 
+ 			appendStringInfo(str, "%s", part->data);
+ 			resetStringInfo(part);
+ 			resetStringInfo(min);
+ 			resetStringInfo(max);
+ 		}
+ 
+ 		rel = RelationIdGetRelation(oid);
+ 		if(GetOverflowPartition(rel))
+ 			appendStringInfo(str, ",\n DEFAULT");
+ 		RelationClose(rel);
+ 
+ 		/* End the command */
+ 		appendStringInfo(str, "\n)");
+ 	}
+ 	else if(partitionedTableType == PART_HASH)
+ 	{
+ 		appendStringInfo(str, ") PARTITIONS %d", partitionCount);
+ 	}
+ 
+ 	typeText = palloc(VARHDRSZ + strlen(str->data));
+ 	memcpy(VARDATA(typeText), str->data , strlen(str->data));
+ 	SET_VARSIZE(typeText, (VARHDRSZ + strlen(str->data)));
+ 
+ 	return typeText;
+ 
+ }
+ 
+ text *
+ parttype(int type)
+ {
+ 	text	*typeText = palloc(VARHDRSZ+6);
+ 	SET_VARSIZE(typeText, VARHDRSZ+6);			
+ 	switch(type)
+ 	{
+ 		case PART_RANGE:
+ 			memcpy(VARDATA(typeText), "range", strlen("range"));
+ 			SET_VARSIZE(typeText, VARHDRSZ+5);			
+ 			break;
+ 		case PART_LIST:
+ 			memcpy(VARDATA(typeText), "list", strlen("list"));
+ 			SET_VARSIZE(typeText, VARHDRSZ+4);			
+ 			break;
+ 		case PART_HASH:
+ 			memcpy(VARDATA(typeText), "hash", strlen("hash"));
+ 			SET_VARSIZE(typeText, VARHDRSZ+4);			
+ 			break;
+ 	}
+ 	return typeText;
+ }
+ 
+ text *
+ maxval(Oid oid)
+ {
+ 	Relation		pg_partrel;
+ 	HeapScanDesc	scanDesc;
+ 	HeapTuple		tuple;
+ 	Snapshot		snap;
+ 	Oid				tmpOid;
+ 	char			*string;
+ 	text			*maxValueText;
+ 	int				size;
+ 	Datum 			values[Natts_pg_partition];
+ 	char  			nulls [Natts_pg_partition];
+ 
+     snap = GetActiveSnapshot();
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     scanDesc = heap_beginscan(pg_partrel, snap, 0, NULL);
+ 
+ 	while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, ForwardScanDirection)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(tuple);
+ 
+ 		/* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
+ 		heap_deformtuple(tuple, pg_partrel->rd_att, values, nulls);
+ 	
+ 		tmpOid = HeapTupleGetOid(tuple);
+ 
+ 		if(tmpOid == oid)
+ 		{
+ 			if(nulls[Anum_pg_partition_maxval-1] == 'n')
+ 			{
+ 				if(pg_part->parttype == PART_RANGE)
+ 				{
+ 					size = VARHDRSZ + strlen("MAXVALUE");
+ 					maxValueText = palloc(size);
+ 					SET_VARSIZE(maxValueText, size);					
+ 					memcpy(VARDATA(maxValueText), "MAXVALUE", strlen("MAXVALUE"));
+ 				}
+ 				else
+ 				{
+ 					size = VARHDRSZ;
+ 					maxValueText = palloc(size);
+ 					SET_VARSIZE(maxValueText, size);					
+ 					heap_endscan(scanDesc);
+ 					heap_close(pg_partrel, AccessShareLock);
+ 					return maxValueText;
+ 				}
+ 			}
+ 			else
+ 			{
+ 				string = DisplayDatum(GetDatum(pg_partrel, pg_part->keytype, tuple, Anum_pg_partition_maxval), pg_part->keytype);
+ 
+ 				size = VARHDRSZ + strlen(string);
+ 				maxValueText = palloc(size);
+ 				SET_VARSIZE(maxValueText, size);			
+ 		
+ 				memcpy(VARDATA(maxValueText), string, strlen(string));
+ 			}
+ 
+ 			heap_endscan(scanDesc);
+ 			heap_close(pg_partrel, AccessShareLock);
+ 
+ 			return maxValueText;	
+ 		}
+ 	}	
+ 
+ 	heap_endscan(scanDesc);
+ 	heap_close(pg_partrel, AccessShareLock);
+ 			
+ 	return NULL;	
+ }
+ 
+ text *
+ minval(Oid oid)
+ {
+ 	Relation		pg_partrel;
+ 	HeapScanDesc	scanDesc;
+ 	HeapTuple		tuple;
+ 	Snapshot		snap;
+ 	Oid				tmpOid;
+ 	char			*string;
+ 	text			*minValueText;
+ 	int				size;
+     Datum           values[Natts_pg_partition];
+     char            nulls [Natts_pg_partition];
+ 
+     snap = GetActiveSnapshot();
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     scanDesc = heap_beginscan(pg_partrel, snap, 0, NULL);
+ 
+ 	while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, ForwardScanDirection)))
+ 	{
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(tuple);
+ 
+         /* Deform the tuple to find out if there are any MINVALUE/MAXVALUE present. */
+         heap_deformtuple(tuple, pg_partrel->rd_att, values, nulls);
+ 	
+ 		tmpOid = HeapTupleGetOid(tuple);
+ 
+ 		if(tmpOid == oid)
+ 		{
+             if(nulls[Anum_pg_partition_minval-1] == 'n')
+             {
+ 				if(pg_part->parttype == PART_RANGE)
+ 				{
+ 	                size = VARHDRSZ + strlen("MINVALUE");
+     	            minValueText = palloc(size);
+         	        SET_VARSIZE(minValueText, size);
+             	    memcpy(VARDATA(minValueText), "MINVALUE", strlen("MINVALUE"));
+ 				}
+ 				else
+ 				{
+ 	                size = VARHDRSZ;
+     	            minValueText = palloc(size);
+         	        SET_VARSIZE(minValueText, size);
+ 					heap_endscan(scanDesc);
+ 					heap_close(pg_partrel, AccessShareLock);
+ 					return minValueText;
+ 				}
+             }
+             else
+             {
+                 string = DisplayDatum(GetDatum(pg_partrel, pg_part->keytype, tuple, Anum_pg_partition_minval), pg_part->keytype);
+                 size = VARHDRSZ + strlen(string);
+                 minValueText = palloc(size);
+                 SET_VARSIZE(minValueText, size);
+                 memcpy(VARDATA(minValueText), string, strlen(string));
+             }
+ 
+ 			heap_endscan(scanDesc);
+ 			heap_close(pg_partrel, AccessShareLock);
+ 
+ 			return minValueText;	
+ 		}
+ 	}	
+ 
+ 	heap_endscan(scanDesc);
+ 	heap_close(pg_partrel, AccessShareLock);
+ 			
+ 	return NULL;	
+ }
+ 
+ PG_FUNCTION_INFO_V1(partition_update_trigger);
+ 
+ /*
+  * Update trigger for all partitions.
+  * Update is implemented as delete + insert operation.
+  * Delete the OLD row from child table and insert the NEW
+  * row on parent table.
+  */
+ Datum
+ partition_update_trigger(PG_FUNCTION_ARGS)
+ {
+     TriggerData *trigdata = (TriggerData *) fcinfo->context;
+     HeapTuple   trigtuple = trigdata->tg_trigtuple;
+     HeapTuple   newtuple  = trigdata->tg_newtuple;
+ 	List		*parents  = find_inheritance_parents(RelationGetRelid(trigdata->tg_relation));
+ 	HeapTuple 	dummyTuple = NULL;
+ 	Oid			targetId = 0;
+     Relation    parent_relation = RelationIdGetRelation(linitial_oid(parents));
+ 	Relation	tmpRel;
+ 	StringInfo	tmpRelName = makeStringInfo();
+ 	bool		isOverflowPartitionSelected;
+ 
+ 	isOverflowPartitionSelected = false;	
+ 
+ 	switch(GetPartitionType(trigtuple->t_tableOid))
+ 	{
+ 		case PART_RANGE:
+ 			targetId = get_relevant_partition(newtuple, parent_relation);
+ 			break;
+ 		case PART_HASH:
+ 			targetId = get_relevant_hash_partition(newtuple, parent_relation);
+ 			break;
+ 		default:
+ 			elog(ERROR, "Invalid partition type.");
+ 	}
+ 
+ 	if(targetId == InvalidOid)
+ 		elog(ERROR, "Could not find valid partition");
+ 
+ 	/* Delete the tuple from table and insert into target table obtained by
+ 	   evaluating constraints. */
+ 	simple_heap_delete(trigdata->tg_relation, &trigtuple->t_self);
+ 	CommandCounterIncrement();
+ 
+ 	InsertTuple(newtuple, targetId);
+ 
+ 	appendStringInfo(tmpRelName, "of_%s_%u", RelationGetRelationName(parent_relation), RelationGetRelid(parent_relation));
+ 
+ 	/* Check if we inserted in any overflow partition. */
+ 	tmpRel = RelationIdGetRelation(targetId);
+ 
+ 	if(strcmp(RelationGetRelationName(tmpRel), tmpRelName->data) == 0)
+ 	{
+ 		isOverflowPartitionSelected = true;	
+ 	}
+ 	
+ 	/* Close relation. */
+     RelationClose(tmpRel);
+ 
+ 	/* Close parent relation. */
+     RelationClose(parent_relation);
+ 
+ 	/* Form a dummy-tuple to count no. of rows modified. */
+ 	dummyTuple = palloc(newtuple->t_len);
+ 
+ 	if(isOverflowPartitionSelected == true)
+ 		dummyTuple->t_len = -2;		/* overflow partition tuple. */
+ 	else
+ 		dummyTuple->t_len = -1;		
+ 		
+ 
+     return PointerGetDatum(dummyTuple);
+ }
+ /*
+  * Constaints for hash partitions are implemented by monitoring inserts to child tables
+  * using following trigger which computes the hash value of partition key attributes 
+  * and allows insert iff it matches with its designated hash value as specified  
+  * in pg_partition catalog table.
+  */
+ PG_FUNCTION_INFO_V1(partition_constraints_hash);
+ Datum
+ partition_constraints_hash(PG_FUNCTION_ARGS)
+ {
+     TriggerData *trigdata = (TriggerData *) fcinfo->context;
+     HeapTuple   trigtuple = trigdata->tg_trigtuple;
+     Relation    relation = trigdata->tg_relation;
+     Relation 	pg_partrel;
+     Oid 		relation_id;
+ 	ScanKeyData skey;
+ 	SysScanDesc pg_partscan;
+ 	HeapTuple   pg_parttup;
+ 	int         hash_partition_entries = 0;
+ 	List        *distinct_part_key_list=NULL;
+ 	StringInfo	str_to_hash = makeStringInfo();
+ 	unsigned int hashValueFromCatalog;
+ 	Oid			parentOid;
+ 	Datum       attr;
+ 	unsigned int hashValue;
+ 
+     /* make sure it's called as a trigger at all */
+     if (!CALLED_AS_TRIGGER(fcinfo))
+         elog(ERROR, "partition_insert_trigger: not called by trigger manager");
+ 
+     /* Sanity checks */
+     if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) || !TRIGGER_FIRED_BEFORE(trigdata->tg_event))
+         elog(ERROR, "partition_insert_trigger: not called on insert before");
+ 
+     relation_id = RelationGetRelid(relation);
+ 
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_partrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(RelationGetRelid(relation)));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+         bool            isnull, typbyval;
+         int16           len;
+         bool            isVariableLength;
+         Oid             typoutput;
+ 
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+ 		if(pg_part->partrelid == RelationGetRelid(relation))
+ 		{
+         	if(pg_part->parttype == PART_HASH)
+ 	        {
+     	        if (!list_member_int(distinct_part_key_list, pg_part->partkey))
+         	    {
+             	    distinct_part_key_list = lappend_int(distinct_part_key_list, pg_part->partkey);
+ 
+                 	/* Get attribute from tuple */
+ 	                attr      = heap_getattr(trigtuple, pg_part->partkey, relation->rd_att, &isnull);
+ 
+         	        /* Get len and typbyval from pg_type */
+             	    get_typlenbyval(pg_part->keytype, &len, &typbyval);
+ 
+         	        /* Read the list value */
+             	    getTypeOutputInfo(pg_part->keytype, &typoutput, &isVariableLength);
+                 	appendStringInfo(str_to_hash, DatumGetCString(OidFunctionCall1(typoutput, attr)));
+ 	
+ 					parentOid = pg_part->parentrelid;
+ 					hashValueFromCatalog = heap_getattr (pg_parttup, Anum_pg_partition_hashval, pg_partrel->rd_att, &isnull);
+         	    }
+         	}
+ 		}
+     }
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, AccessShareLock);
+ 
+     /*Scan key to scan pg_partition table on parentrelid*/
+     ScanKeyInit(&skey,
+                 Anum_pg_partition_parentrelid,
+                 BTEqualStrategyNumber, F_OIDEQ,
+                 ObjectIdGetDatum(parentOid));
+ 
+     pg_partrel = heap_open(PartitionRelationId, AccessShareLock);
+     pg_partscan = systable_beginscan(pg_partrel, PartitionParentIndexId, true,
+                                 SnapshotNow, 1, &skey);
+ 
+ 	hash_partition_entries = 0;
+ 
+     while (HeapTupleIsValid(pg_parttup= systable_getnext(pg_partscan)))
+     {
+         /* Instead of pg_part Use heap_getattr for accessing bytea coluns */
+         Form_pg_partition pg_part = (Form_pg_partition) GETSTRUCT(pg_parttup);
+ 
+         if(pg_part->parttype == PART_HASH)
+         {
+             /* Increase the no. of hash partition entries count. */
+ 			hash_partition_entries++;
+ 		}
+ 	}
+ 
+     systable_endscan(pg_partscan);
+     heap_close(pg_partrel, AccessShareLock);
+ 
+     hashValue = DatumGetUInt32(hash_any((unsigned char *)str_to_hash->data, strlen(str_to_hash->data))) %
+                 (int)(hash_partition_entries / distinct_part_key_list->length);
+ 
+ //	elog(NOTICE, "String to be hashed : %s", str_to_hash->data);
+ 
+ 	if(hashValueFromCatalog != hashValue)
+ 		elog(ERROR, "This row can not be inserted. Invalid hash value '%d'; expected '%d'", hashValue, hashValueFromCatalog);
+ 	
+     return PointerGetDatum(trigtuple);
+ }
+ 
+ PG_FUNCTION_INFO_V1(partition_insert_trigger_hash);
+ Datum
+ partition_insert_trigger_hash(PG_FUNCTION_ARGS)
+ {
+     TriggerData *trigdata = (TriggerData *) fcinfo->context;
+     HeapTuple   trigtuple= trigdata->tg_trigtuple;
+     Relation    parent_relation = trigdata->tg_relation;
+ 
+     char        *child_table_name;
+     Relation 	child_table_relation;
+     Oid 		relation_id,parent_reloid;
+     ResultRelInfo *resultRelInfo;
+     TupleTableSlot *slot;
+     EState *estate= CreateExecutorState();
+ 
+ 
+     /* make sure it's called as a trigger at all */
+     if (!CALLED_AS_TRIGGER(fcinfo))
+         elog(ERROR, "partition_insert_trigger: not called by trigger manager");
+ 
+     /* Sanity checks */
+     if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) || !TRIGGER_FIRED_BEFORE(trigdata->tg_event))
+         elog(ERROR, "partition_insert_trigger: not called on insert before");
+ 
+     parent_reloid = RelationGetRelid(parent_relation);
+ 
+     relation_id = get_relevant_hash_partition(trigtuple, parent_relation);
+     if (relation_id == InvalidOid)
+         elog(ERROR, "partition_insert_trigger: Invalid child table %s", child_table_name);
+ 
+     child_table_relation = RelationIdGetRelation(relation_id);
+     if (child_table_relation == NULL)
+     elog(ERROR, "partition_insert_trigger: Failed to locate relation for child table %s", child_table_name);
+ 
+     resultRelInfo = makeNode(ResultRelInfo);
+     resultRelInfo->ri_RangeTableIndex = 1;
+     resultRelInfo->ri_RelationDesc = child_table_relation;
+ 
+     estate->es_result_relations = resultRelInfo;
+     estate->es_num_result_relations = 1;
+     estate->es_result_relation_info = resultRelInfo;
+ 
+ 	/* Set up a tuple slot too */
+     slot = MakeSingleTupleTableSlot(trigdata->tg_relation->rd_att);
+     ExecStoreTuple(trigtuple, slot, InvalidBuffer, false);
+ 
+ 	/* If there are any constraints then execute. */
+ 	if(resultRelInfo->ri_RelationDesc->rd_att->constr != NULL)
+ 		ExecConstraints(resultRelInfo, slot, estate);
+ 
+     heap_insert(child_table_relation, trigtuple, GetCurrentCommandId(true), 0, NULL);
+     RelationClose(child_table_relation);
+     ExecDropSingleTupleTableSlot(slot);
+     FreeExecutorState (estate);
+ 	
+ 	/* Form a dummy-tuple to count no. of rows modified. */
+ 	trigtuple->t_len = -1;
+ 
+     return PointerGetDatum(trigtuple);
+ }
+ 
+ PG_FUNCTION_INFO_V1(partition_insert_trigger);
+ Datum
+ partition_insert_trigger(PG_FUNCTION_ARGS)
+ {
+     TriggerData *trigdata = (TriggerData *) fcinfo->context;
+     HeapTuple   trigtuple= trigdata->tg_trigtuple;
+     Relation    parent_relation = trigdata->tg_relation;
+     Oid relation_id,parent_reloid;
+ 	Relation	tmpRel;
+ 	StringInfo	tmpRelName = makeStringInfo();
+ 	bool		isOverflowPartitionSelected;
+ 
+ 	isOverflowPartitionSelected = false;
+ 
+     /* make sure it's called as a trigger at all */
+     if (!CALLED_AS_TRIGGER(fcinfo))
+         elog(ERROR, "partition_insert_trigger: not called by trigger manager");
+ 
+     /* Sanity checks */
+     if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event) || !TRIGGER_FIRED_BEFORE(trigdata->tg_event))
+         elog(ERROR, "partition_insert_trigger: not called on insert before");
+ 
+ 	parent_reloid = RelationGetRelid(parent_relation);
+ 
+ 	relation_id = get_relevant_partition(trigtuple, parent_relation);
+     if (relation_id == InvalidOid)
+         elog(ERROR, "Could not find valid partition ... ");
+ 
+ 	InsertTuple(trigtuple, relation_id);
+ 
+ 	appendStringInfo(tmpRelName, "of_%s_%u", RelationGetRelationName(parent_relation), RelationGetRelid(parent_relation));
+ 
+ 	/* Check if we inserted in any overflow partition. */
+ 	tmpRel = RelationIdGetRelation(relation_id);
+ 
+ 	if(strcmp(RelationGetRelationName(tmpRel), tmpRelName->data) == 0)
+ 	{
+ 		isOverflowPartitionSelected = true;	
+ 	}
+ 	
+ 	/* Close relation. */
+     RelationClose(tmpRel);
+ 
+ 	/* Form a dummy-tuple to count no. of rows modified. */
+ 	if(isOverflowPartitionSelected == true)
+ 		trigtuple->t_len = -2;		/* overflow partition tuple. */
+ 	else
+ 		trigtuple->t_len = -1;		
+ 
+     return PointerGetDatum(trigtuple);
+ }
  
  /*
   * Distance from a point to a path